If you have an MGE Ellipse UPS, or you see timeouts in HID
transactions, say Y; otherwise say N.
+EHCI (USB 2.0) support
+CONFIG_USB_EHCI_HCD
+ The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
+ "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
+ If your USB host controller supports USB 2.0, you will likely want to
+ configure this Host Controller Driver. At this writing, the primary
+ implementation of EHCI is a chip from NEC, widely available in add-on
+ PCI cards, but implementations are in the works from other vendors
+ including Intel and Philips. Motherboard support is appearing.
+
+ EHCI controllers are packaged with "companion" host controllers (OHCI
+ or UHCI) to handle USB 1.1 devices connected to root hub ports. Ports
+ will connect to EHCI if it the device is high speed, otherwise they
+ connect to a companion controller. If you configure EHCI, you should
+ probably configure the OHCI (for NEC and some other vendors) USB Host
+ Controller Driver too.
+
+ You may want to read <file:Documentation/usb/ehci.txt>.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called ehci-hcd.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
UHCI (Intel PIIX4, VIA, ...) support
CONFIG_USB_UHCI
The Universal Host Controller Interface is a standard by Intel for
The module will be called visor.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+USB Compaq iPAQ Driver
+CONFIG_USB_SERIAL_IPAQ
+ Say Y here if you want to connect to your Compaq iPAQ running
+ Windows CE 3.0 using a USB autosync cable. For information on using
+ the driver, read <file:Documentation/usb/usb-serial.txt>.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called ipaq.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
USB IR Dongle Serial Driver
CONFIG_USB_SERIAL_IR
Say Y here if you want to enable simple serial support for USB IrDA
The module will be called io_edgeport.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>.
+USB PalmConnect (and other KL5KUSB105-based) Single Port Serial Driver
+CONFIG_USB_SERIAL_KLSI
+ Say Y here if you want to use a KL5KUSB105 - based single port
+ serial adapter. The most widely known -- and currently the only
+ tested -- device in this category is the PalmConnect USB Serial
+ adapter sold by Palm Inc. for use with their Palm III and Palm V
+ series PDAs.
+
+ Please read <file:Documentation/usb/usb-serial.txt> for more
+ information.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called kl5kusb105.o. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>.
+
USB Serial Converter verbose debug
CONFIG_USB_SERIAL_DEBUG
Say Y here if you want verbose debug messages from the USB Serial
The module will be called pwc.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+USB SE401 Camera support
+CONFIG_USB_SE401
+ Say Y here if you want to connect this type of camera to your
+ computer's USB port. See <file:Documentation/usb/se401.txt> for more
+ information and for a list of supported cameras.
+
+ This driver uses the Video For Linux API. You must say Y or M to
+ "Video For Linux" (under Multimedia Devices) to use this driver.
+ Information on this API and pointers to "v4l" programs may be found
+ on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called se401.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+USB STV680 (Pencam) Camera support
+CONFIG_USB_STV680
+ Say Y here if you want to connect this type of camera to your
+ computer's USB port. This includes the Pencam line of cameras.
+ See <file:Documentation/usb/stv680.txt> for more information and for
+ a list of supported cameras.
+
+ This driver uses the Video For Linux API. You must say Y or M to
+ "Video For Linux" (under Multimedia Devices) to use this driver.
+ Information on this API and pointers to "v4l" programs may be found
+ on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called stv680.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+Vicam
+CONFIG_USB_VICAM
+ Say Y here if you have 3com homeconnect camera (vicam).
+
+ This driver uses the Video For Linux API. You must say Y or M to
+ "Video For Linux" (under Multimedia Devices) to use this driver.
+ Information on this API and pointers to "v4l" programs may be found
+ on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called vicam.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+
Pegasus/Pegasus II based USB-Ethernet device support
CONFIG_USB_PEGASUS
Say Y here if you know you have Pegasus or Pegasus II based adapter.
will issue the hlt instruction if nothing is to be done, thereby
sending the processor to sleep and saving power.
-USB SE401 Camera support
-CONFIG_USB_SE401
- Say Y here if you want to connect this type of camera to your
- computer's USB port. See <file:Documentation/usb/se401.txt> for more
- information and for a list of supported cameras.
-
- This driver uses the Video For Linux API. You must say Y or M to
- "Video For Linux" (under Multimedia Devices) to use this driver.
- Information on this API and pointers to "v4l" programs may be found
- on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
- This code is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called se401.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
ACPI support
CONFIG_ACPI
ACPI/OSPM support for Linux is currently under development. As such,
--- /dev/null
+18-Dec-2001
+
+The EHCI driver is used to talk to high speed USB 2.0 devices using
+USB 2.0-capable host controller hardware. The USB 2.0 standard is
+compatible with the USB 1.1 standard. It defines three transfer speeds:
+
+ - "High Speed" 480 Mbit/sec (60 MByte/sec)
+ - "Full Speed" 12 Mbit/sec (1.5 MByte/sec)
+ - "Low Speed" 1.5 Mbit/sec
+
+USB 1.1 only addressed full speed and low speed. High speed devices
+can be used on USB 1.1 systems, but they slow down to USB 1.1 speeds.
+
+USB 1.1 devices may also be used on USB 2.0 systems. When plugged
+into an EHCI controller, they are given to a USB 1.1 "companion"
+controller, which is a OHCI or UHCI controller as normally used with
+such devices. When USB 1.1 devices plug into USB 2.0 hubs, they
+interact with the EHCI controller through a "Transaction Translator"
+(TT) in the hub, which turns low or full speed transactions into
+high speed "split transactions" that don't waste transfer bandwidth.
+
+At this writing, high speed devices are finally beginning to appear.
+While usb-storage devices have been available for some time (working
+quite speedily on the 2.4 version of this driver), hubs have only
+very recently become available.
+
+Note that USB 2.0 support involves more than just EHCI. It requires
+other changes to the Linux-USB core APIs, including the hub driver,
+but those changes haven't needed to really change the basic "usbcore"
+APIs exposed to USB device drivers.
+
+- David Brownell
+ <dbrownell@users.sourceforge.net>
+
+
+FUNCTIONALITY
+
+This driver is regularly tested on x86 hardware, and has also been
+used on PPC hardware so big/little endianneess issues should be gone.
+It's believed to do all the right PCI magic so that I/O works even on
+systems with interesting DMA mapping issues.
+
+At this writing the driver should comfortably handle all control and bulk
+transfers, including requests to USB 1.1 devices through transaction
+translators (TTs) in USB 2.0 hubs. However, there some situations where
+the hub driver needs to clear TT error state, which it doesn't yet do.
+
+Interrupt transfer support is newly functional and not yet as robust as
+control and bulk traffic. As yet there is no support for split transaction
+scheduling for interrupt transfers, which means among other things that
+connecting USB 1.1 hubs, keyboards, and mice to USB 2.0 hubs won't work.
+Connect them to USB 1.1 hubs, or to a root hub.
+
+Isochronous (ISO) transfer support is not yet working. No production
+high speed devices are available which would need it (though high quality
+webcams are in the works!). Note that split transaction support for ISO
+transfers can't share much code with the code for high speed ISO transfers,
+since EHCI represents these with a different data structure.
+
+The EHCI root hub code should hand off USB 1.1 devices to its companion
+controller. This driver doesn't need to know anything about those
+drivers; a OHCI or UHCI driver that works already doesn't need to change
+just because the EHCI driver is also present.
+
+There are some issues with power management; suspend/resume doesn't
+behave quite right at the moment.
+
+
+USE BY
+
+Assuming you have an EHCI controller (on a PCI card or motherboard)
+and have compiled this driver as a module, load this like:
+
+ # modprobe ehci-hcd
+
+and remove it by:
+
+ # rmmod ehci-hcd
+
+You should also have a driver for a "companion controller", such as
+"ohci-hcd", "usb-ohci", "usb-uhci", or "uhci". In case of any trouble
+with the EHCI driver, remove its module and then the driver for that
+companion controller will take over (at lower speed) all the devices
+that were previously handled by the EHCI driver.
+
+Module parameters (pass to "modprobe") include:
+
+ log2_irq_thresh (default 0):
+ Log2 of default interrupt delay, in microframes. The default
+ value is 0, indicating 1 microframe (125 usec). Maximum value
+ is 6, indicating 2^6 = 64 microframes. This controls how often
+ the EHCI controller can issue interrupts.
+
+The EHCI interrupt handler just acknowledges interrupts and schedules
+a tasklet to handle whatever needs handling. That keeps latencies low,
+no matter how often interrupts are issued.
+
+Device drivers shouldn't care whether they're running over EHCI or not,
+but they may want to check for "usb_device->speed == USB_SPEED_HIGH".
+High speed devices can do things that full speed (or low speed) ones
+can't, such as "high bandwidth" periodic (interrupt or ISO) transfers.
+
+
+PERFORMANCE
+
+USB 2.0 throughput is gated by two main factors: how fast the host
+controller can process requests, and how fast devices can respond to
+them. The 480 Mbit/sec "raw transfer rate" is obeyed by all devices,
+but aggregate throughput is also affected by issues like delays between
+individual high speed packets, driver intelligence, and of course the
+overall system load. Latency is also a performance concern.
+
+Bulk transfers are most often used where throughput is an issue. It's
+good to keep in mind that bulk transfers are always in 512 byte packets,
+and at most 13 of those fit into one USB 2.0 microframe. Eight USB 2.0
+microframes fit in a USB 1.1 frame; a microframe is 1 msec/8 = 125 usec.
+
+Hardware Performance
+
+At this writing, individual USB 2.0 devices tend to max out at around
+20 MByte/sec transfer rates. This is of course subject to change;
+and some devices now go faster, while others go slower.
+
+The NEC implementation of EHCI seems to have a hardware bottleneck
+at around 28 MByte/sec aggregate transfer rate. While this is clearly
+enough for a single device at 20 MByte/sec, putting three such devices
+onto one bus does not get you 60 MByte/sec. The issue appears to be
+that the controller hardware won't do concurrent USB and PCI access,
+so that it's only trying six (or maybe seven) USB transactions each
+microframe rather than thirteen. (Seems like a reasonable trade off
+for a product that beat all the others to market by over a year!)
+It's expected that newer implementations will better this, throwing
+more silicon real estate at the problem so that new motherboard chip
+sets will get closer to that 60 MByte/sec target.
+
+There's a minimum latency of one microframe (125 usec) for the host
+to receive interrupts from the EHCI controller indicating completion
+of requests. That latency is tunable; there's a module option. By
+default ehci-hcd driver uses the minimum latency, which means that if
+you issue a control or bulk request you can often expect to learn that
+it completed in less than 250 usec (depending on transfer size).
+
+Software Performance
+
+To get even 20 MByte/sec transfer rates, Linux-USB device drivers will
+need to keep the EHCI queue full. That means issuing large requests,
+or using bulk queuing if a series of small requests needs to be issued.
+When drivers don't do that, their performance results will show it.
+
+In typical situations, a usb_bulk_msg() loop writing out 4 KB chunks is
+going to waste more than half the USB 2.0 bandwidth. Delays between the
+I/O completion and the driver issuing the next request will take longer
+than the I/O. If that same loop used 16 KB chunks, it'd be better; a
+sequence of 128 KB chunks would waste a lot less.
+
+But rather than depending on such large I/O buffers to make synchronous
+I/O be efficient, it's better to just queue all several (bulk) requests
+to the HC, and wait for them all to complete (or be canceled on error).
+Such URB queuing should work with all the USB 1.1 HC drivers too.
+
+TBD: Interrupt and ISO transfer performance issues. Those periodic
+transfers are fully scheduled, so the main issue is likely to be how
+to trigger "high bandwidth" modes.
+
--- /dev/null
+Linux driver for STV0680 based USB cameras
+
+Copyright, 2001, Kevin Sisson
+
+
+INTRODUCTION:
+
+STMicroelectronics produces the STV0680B chip, which comes in two
+types, -001 and -003. The -003 version allows the recording and downloading
+of sound clips from the camera, and allows a flash attachment. Otherwise,
+it uses the same commands as the -001 version. Both versions support a
+variety of SDRAM sizes and sensors, allowing for a maximum of 26 VGA or 20
+CIF pictures. The STV0680 supports either a serial or a usb interface, and
+video is possible through the usb interface.
+
+The following cameras are known to work with this driver, although any
+camera with Vendor/Product codes of 0553/0202 should work:
+
+Aiptek Pencam (various models)
+Nisis QuickPix 2
+Radio Shack 'Kid's digital camera' (#60-1207)
+At least one Trust Spycam model
+Several other European brand models
+
+WHAT YOU NEED:
+
+- USB support
+- VIDEO4LINUX support
+
+More information about USB support for linux can be found at:
+http://www.linux-usb.org
+
+
+MODULE OPTIONS:
+
+When the driver is compiled as a module, you can set a "swapRGB=1"
+option, if necessary, for those applications that require it
+(such as xawtv). However, the driver should detect and set this
+automatically, so this option should not normally be used.
+
+
+KNOWN PROBLEMS:
+
+The driver seems to work better with the usb-ohci than the usb-uhci host
+controller driver.
+
+HELP:
+
+The latest info on this driver can be found at:
+http://personal.clt.bellsouth.net/~kjsisson or at
+http://stv0680-usb.sourceforge.net
+
+Any questions to me can be send to: kjsisson@bellsouth.net
+
+
Kroah-Hartman at greg@kroah.com
+Compaq iPAQ driver
+
+ This driver can be used to connect to Compaq iPAQ PDAs running
+ Windows CE 3.0 using a USB autosync cable. It has been tested only on
+ the Compaq H3135. It should work with the H3600 and later models too.
+ It may work with other CE based handhelds as well.
+
+ The driver presents a serial interface (usually on /dev/ttyUSB0) over
+ which one may run ppp and establish a TCP/IP link to the iPAQ. Once this
+ is done, you can transfer files, backup, download email etc. The most
+ significant advantage of using USB is speed - you can get 73 to 113
+ kbytes/sec for download/upload to the iPAQ.
+
+ The driver works intermittently with the usb-uhci driver but quite
+ reliably with the uhci driver. Make sure you have the right driver
+ loaded - usb-uhci is often the default.
+
+ You must setup hotplug to invoke pppd as soon as the iPAQ is connected.
+ A ppp script like the one below may be used:
+
+ #!/bin/bash
+
+ MYIP=linux.box.ip
+ REMOTEIP=ipaq.ip
+ MYDNS=my.dns.server
+ killall -9 pppd
+ /usr/sbin/pppd /dev/ttyUSB0 \
+ connect "/usr/sbin/chat -v TIMEOUT 60 CLIENT 'CLIENTSERVER\c'" \
+ nocrtscts local debug passive $MYIP:$REMOTEIP ms-dns $MYDNS noauth \
+ proxyarp
+
+ You must also download and install asyncd from http://synce.sourceforge.net
+ This is required to emulate keep-alive packets which are exchanged by
+ ActiveSync and the iPAQ.
+
+ On connecting the cable, you should see the usual "Device Connected",
+ "User Authenticated" messages flash by on your iPAQ. Once connected,
+ you can use Win CE programs like ftpView, Pocket Outlook from the iPAQ
+ and other synce utilities from the Linux side. Remember to enable IP
+ forwarding.
+
+ To use Pocket IE, follow the instructions given at
+ http://www.tekguru.co.uk/EM500/usbtonet.htm to achieve the same thing
+ on Win98. Omit the proxy server part; Linux is quite capable of forwarding
+ packets unlike Win98. Another modification is required at least for the
+ iPAQ - disable autosync by going to the Start/Settings/Connections menu
+ and unchecking the "Automatically synchronize ..." box. Go to
+ Start/Programs/Connections, connect the cable and select "usbdial" (or
+ whatever you named your new USB connection). You should finally wind
+ up with a "Connected to usbdial" window with status shown as connected.
+ Now start up PIE and browse away.
+
+ If it doesn't work for some reason, load both the usbserial and ipaq module
+ with the module parameter "debug" set to 1 and examine the system log.
+ You can also try soft-resetting your iPAQ before attempting a connection.
+
+ For any questions or problems with the driver, please contact Ganesh
+ Varadarajan <ganesh@veritas.com>
+
+
Keyspan PDA Serial Adapter
Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly
Kroah-Hartman at greg@kroah.com
+KL5KUSB105 chipset / PalmConnect USB single-port adapter
+
+Current status:
+ The driver was put together by looking at the usb bus transactions
+ done by Palm's driver under Windows, so a lot of functionality is
+ still missing. Notably, serial ioctls are sometimes faked or not yet
+ implemented. Support for finding out about DSR and CTS line status is
+ however implemented (though not nicely), so your favorite autopilot(1)
+ and pilot-manager -daemon calls will work. Baud rates up to 115200
+ are supported, but handshaking (software or hardware) is not, which is
+ why it is wise to cut down on the rate used is wise for large
+ transfers until this is settled.
+
+Options supported:
+ If this driver is compiled as a module you can pass the following
+ options to it:
+ debug - extra verbose debugging info
+ (default: 0; nonzero enables)
+ use_lowlatency - use low_latency flag to speed up tty layer
+ when reading from from the device.
+ (default: 0; nonzero enables)
+
+ See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
+ information on this driver.
+
+
Generic Serial driver
If your device is not one of the above listed devices, compatible with
VERSION = 2
PATCHLEVEL = 5
SUBLEVEL = 2
-EXTRAVERSION =-pre6
+EXTRAVERSION =-pre7
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
u32 data[4];
size_t rv;
u32 reg = *ppos;
- int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+ int cpu = minor(file->f_dentry->d_inode->i_rdev);
if ( count % 16 )
return -EINVAL; /* Invalid chunk size */
static int cpuid_open(struct inode *inode, struct file *file)
{
- int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+ int cpu = minor(file->f_dentry->d_inode->i_rdev);
struct cpuinfo_x86 *c = &(cpu_data)[cpu];
if ( !(cpu_online_map & (1UL << cpu)) )
u32 data[2];
size_t rv;
u32 reg = *ppos;
- int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+ int cpu = minor(file->f_dentry->d_inode->i_rdev);
int err;
if ( count % 8 )
u32 data[2];
size_t rv;
u32 reg = *ppos;
- int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+ int cpu = minor(file->f_dentry->d_inode->i_rdev);
int err;
if ( count % 8 )
static int msr_open(struct inode *inode, struct file *file)
{
- int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+ int cpu = minor(file->f_dentry->d_inode->i_rdev);
struct cpuinfo_x86 *c = &(cpu_data)[cpu];
if ( !(cpu_online_map & (1UL << cpu)) )
*/
#define DAC960_ControllerNumber(Device) \
- (MAJOR(Device) - DAC960_MAJOR)
+ (major(Device) - DAC960_MAJOR)
#define DAC960_LogicalDriveNumber(Device) \
- (MINOR(Device) >> DAC960_MaxPartitionsBits)
+ (minor(Device) >> DAC960_MaxPartitionsBits)
#define DAC960_PartitionNumber(Device) \
- (MINOR(Device) & (DAC960_MaxPartitions - 1))
+ (minor(Device) & (DAC960_MaxPartitions - 1))
#define DAC960_MajorNumber(ControllerNumber) \
(DAC960_MAJOR + (ControllerNumber))
*/
static int cciss_open(struct inode *inode, struct file *filep)
{
- int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
- int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
+ int ctlr = major(inode->i_rdev) - MAJOR_NR;
+ int dsk = minor(inode->i_rdev) >> NWD_SHIFT;
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk);
if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
return -ENXIO;
- if (!suser() && hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0)
+ if (!suser() && hba[ctlr]->sizes[minor(inode->i_rdev)] == 0)
return -ENXIO;
/*
* for "raw controller".
*/
if (suser()
- && (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0)
- && (MINOR(inode->i_rdev)!= 0))
+ && (hba[ctlr]->sizes[minor(inode->i_rdev)] == 0)
+ && (minor(inode->i_rdev)!= 0))
return -ENXIO;
hba[ctlr]->drv[dsk].usage_count++;
*/
static int cciss_release(struct inode *inode, struct file *filep)
{
- int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
- int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
+ int ctlr = major(inode->i_rdev) - MAJOR_NR;
+ int dsk = minor(inode->i_rdev) >> NWD_SHIFT;
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk);
static int cciss_ioctl(struct inode *inode, struct file *filep,
unsigned int cmd, unsigned long arg)
{
- int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
- int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
+ int ctlr = major(inode->i_rdev) - MAJOR_NR;
+ int dsk = minor(inode->i_rdev) >> NWD_SHIFT;
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg);
unsigned long flags;
int res;
- target = MINOR(dev) >> NWD_SHIFT;
- ctlr = MAJOR(dev) - MAJOR_NR;
+ target = minor(dev) >> NWD_SHIFT;
+ ctlr = major(dev) - MAJOR_NR;
gdev = &(hba[ctlr]->gendisk);
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
int ctlr, i;
unsigned long flags;
- ctlr = MAJOR(dev) - MAJOR_NR;
- if (MINOR(dev) != 0)
+ ctlr = major(dev) - MAJOR_NR;
+ if (minor(dev) != 0)
return -ENXIO;
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_ON);
cciss_geninit(ctlr);
- for(i=0; i<NWD; i++)
+ for(i=0; i<NWD; i++) {
+ kdev_t kdev = mk_kdev(major(dev), i << NWD_SHIFT);
if (hba[ctlr]->sizes[ i<<NWD_SHIFT ])
- revalidate_logvol(dev+(i<<NWD_SHIFT), 2);
+ revalidate_logvol(kdev, 2);
+ }
hba[ctlr]->usage_count--;
return 0;
ctlr_info_t *h= q->queuedata;
CommandList_struct *c;
int log_unit, start_blk, seg;
- struct list_head *queue_head = &q->queue_head;
struct request *creq;
u64bit temp64;
struct scatterlist tmp_sg[MAXSGENTRIES];
goto startio;
queue:
- if (list_empty(queue_head))
+ if (blk_queue_empty(q))
goto startio;
creq = elv_next_request(q);
if (creq->nr_phys_segments > MAXSGENTRIES)
BUG();
- if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR )
+ if (h->ctlr != major(creq->rq_dev)-MAJOR_NR )
{
printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
- h->ctlr, creq->rq_dev, creq);
+ h->ctlr, major(creq->rq_dev), creq);
blkdev_dequeue_request(creq);
complete_buffers(creq->bio, 0);
end_that_request_last(creq);
c->rq = creq;
/* fill in the request */
- log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT;
+ log_unit = minor(creq->rq_dev) >> NWD_SHIFT;
c->Header.ReplyQueue = 0; // unused in simple mode
c->Header.Tag.lower = c->busaddr; // use the physical address the cmd block for tag
c->Header.LUN.LogDev.VolId= hba[h->ctlr]->drv[log_unit].LunID;
cciss_geninit(i);
for(j=0; j<NWD; j++)
register_disk(&(hba[i]->gendisk),
- MKDEV(MAJOR_NR+i, j <<4),
+ mk_kdev(MAJOR_NR+i, j <<4),
MAX_PART, &cciss_fops,
hba[i]->drv[j].nr_blocks);
//general boundary defintions
#define SENSEINFOBYTES 32//note that this value may vary between host implementations
-#define MAXSGENTRIES 32
+#define MAXSGENTRIES 31
#define MAXREPLYQS 256
//Command Status value
ida_geninit(i);
for(j=0; j<NWD; j++)
register_disk(&ida_gendisk[i],
- MKDEV(MAJOR_NR+i,j<<4),
+ mk_kdev(MAJOR_NR+i,j<<4),
16, &ida_fops, hba[i]->drv[j].nr_blks);
}
*/
static int ida_open(struct inode *inode, struct file *filep)
{
- int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
- int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
+ int ctlr = major(inode->i_rdev) - MAJOR_NR;
+ int dsk = minor(inode->i_rdev) >> NWD_SHIFT;
DBGINFO(printk("ida_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
return -ENXIO;
if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) +
- MINOR(inode->i_rdev)] == 0)
+ minor(inode->i_rdev)] == 0)
return -ENXIO;
/*
* for "raw controller".
*/
if (suser()
- && ida_sizes[(ctlr << CTLR_SHIFT) + MINOR(inode->i_rdev)] == 0
- && MINOR(inode->i_rdev) != 0)
+ && ida_sizes[(ctlr << CTLR_SHIFT) + minor(inode->i_rdev)] == 0
+ && minor(inode->i_rdev) != 0)
return -ENXIO;
hba[ctlr]->drv[dsk].usage_count++;
*/
static int ida_release(struct inode *inode, struct file *filep)
{
- int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
- int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
+ int ctlr = major(inode->i_rdev) - MAJOR_NR;
+ int dsk = minor(inode->i_rdev) >> NWD_SHIFT;
DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
{
ctlr_info_t *h = q->queuedata;
cmdlist_t *c;
- struct list_head * queue_head = &q->queue_head;
struct request *creq;
struct scatterlist tmp_sg[SG_MAX];
int i, dir, seg;
goto startio;
queue_next:
- if (list_empty(queue_head))
+ if (blk_queue_empty(q))
goto startio;
creq = elv_next_request(q);
if (creq->nr_phys_segments > SG_MAX)
BUG();
- if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR || h->ctlr > nr_ctlr)
+ if (h->ctlr != major(creq->rq_dev)-MAJOR_NR || h->ctlr > nr_ctlr)
{
printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
- h->ctlr, creq->rq_dev, creq);
+ h->ctlr, minor(creq->rq_dev), creq);
blkdev_dequeue_request(creq);
complete_buffers(creq->bio, 0);
end_that_request_last(creq);
spin_unlock_irq(q->queue_lock);
c->ctlr = h->ctlr;
- c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT;
+ c->hdr.unit = minor(creq->rq_dev) >> NWD_SHIFT;
c->hdr.size = sizeof(rblk_t) >> 2;
c->size += sizeof(rblk_t);
*/
static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
{
- int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
- int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
+ int ctlr = major(inode->i_rdev) - MAJOR_NR;
+ int dsk = minor(inode->i_rdev) >> NWD_SHIFT;
int error;
int diskinfo[4];
struct hd_geometry *geo = (struct hd_geometry *)arg;
int ctlr, i;
unsigned long flags;
- ctlr = MAJOR(dev) - MAJOR_NR;
- if (MINOR(dev) != 0)
+ ctlr = major(dev) - MAJOR_NR;
+ if (minor(dev) != 0)
return -ENXIO;
spin_lock_irqsave(IDA_LOCK(ctlr), flags);
hba[ctlr]->access.set_intr_mask(hba[ctlr], FIFO_NOT_EMPTY);
ida_geninit(ctlr);
- for(i=0; i<NWD; i++)
+ for(i=0; i<NWD; i++) {
+ kdev_t kdev = mk_kdev(major(dev), i << NWD_SHIFT);
if (ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)])
- revalidate_logvol(dev+(i<<NWD_SHIFT), 2);
+ revalidate_logvol(kdev, 2);
+ }
hba[ctlr]->usage_count--;
return 0;
int res;
target = DEVICE_NR(dev);
- ctlr = MAJOR(dev) - MAJOR_NR;
+ ctlr = major(dev) - MAJOR_NR;
gdev = &ida_gendisk[ctlr];
spin_lock_irqsave(IDA_LOCK(ctlr), flags);
inline int elv_try_merge(struct request *__rq, struct bio *bio)
{
- unsigned int count = bio_sectors(bio);
int ret = ELEVATOR_NO_MERGE;
/*
* we can merge and sequence is ok, check if it's possible
*/
if (elv_rq_merge_ok(__rq, bio)) {
- if (__rq->sector + __rq->nr_sectors == bio->bi_sector) {
+ if (__rq->sector + __rq->nr_sectors == bio->bi_sector)
ret = ELEVATOR_BACK_MERGE;
- } else if (__rq->sector - count == bio->bi_sector) {
- __rq->elevator_sequence -= count;
+ else if (__rq->sector - bio_sectors(bio) == bio->bi_sector)
ret = ELEVATOR_FRONT_MERGE;
- }
}
return ret;
}
-int elevator_linus_merge(request_queue_t *q, struct request **req,
- struct bio *bio)
+inline int elv_try_last_merge(request_queue_t *q, struct request **req,
+ struct bio *bio)
{
- struct list_head *entry;
- struct request *__rq;
- int ret;
+ int ret = ELEVATOR_NO_MERGE;
/*
* give a one-shot try to merging with the last touched
* request
*/
if (q->last_merge) {
- __rq = list_entry_rq(q->last_merge);
+ struct request *__rq = list_entry_rq(q->last_merge);
BUG_ON(__rq->flags & REQ_STARTED);
- if ((ret = elv_try_merge(__rq, bio))) {
+ if ((ret = elv_try_merge(__rq, bio)))
*req = __rq;
- return ret;
- }
}
+ return ret;
+}
+
+/*
+ * elevator_linux starts here
+ */
+int elevator_linus_merge(request_queue_t *q, struct request **req,
+ struct bio *bio)
+{
+ struct list_head *entry;
+ struct request *__rq;
+ int ret;
+
+ if ((ret = elv_try_last_merge(q, req, bio)))
+ return ret;
+
entry = &q->queue_head;
ret = ELEVATOR_NO_MERGE;
while ((entry = entry->prev) != &q->queue_head) {
/*
* simply "aging" of requests in queue
*/
- if (__rq->elevator_sequence-- <= 0)
+ if (elv_linus_sequence(__rq)-- <= 0)
break;
if (!(__rq->flags & REQ_CMD))
continue;
- if (__rq->elevator_sequence < bio_sectors(bio))
+ if (elv_linus_sequence(__rq) < bio_sectors(bio))
break;
if (!*req && bio_rq_in_between(bio, __rq, &q->queue_head))
*req = __rq;
if ((ret = elv_try_merge(__rq, bio))) {
+ if (ret == ELEVATOR_FRONT_MERGE)
+ elv_linus_sequence(__rq) -= bio_sectors(bio);
*req = __rq;
q->last_merge = &__rq->queuelist;
break;
while ((entry = entry->next) != &q->queue_head) {
struct request *tmp;
tmp = list_entry_rq(entry);
- tmp->elevator_sequence -= count;
+ elv_linus_sequence(tmp) -= count;
}
}
void elevator_linus_merge_req(struct request *req, struct request *next)
{
- if (next->elevator_sequence < req->elevator_sequence)
- req->elevator_sequence = next->elevator_sequence;
+ if (elv_linus_sequence(next) < elv_linus_sequence(req))
+ elv_linus_sequence(req) = elv_linus_sequence(next);
}
-void elv_add_request_fn(request_queue_t *q, struct request *rq,
- struct list_head *insert_here)
+void elevator_linus_add_request(request_queue_t *q, struct request *rq,
+ struct list_head *insert_here)
{
+ elevator_t *e = &q->elevator;
+ int lat = 0, *latency = e->elevator_data;
+
+ if (!(rq->flags & REQ_BARRIER))
+ lat = latency[rq_data_dir(rq)];
+
+ elv_linus_sequence(rq) = lat;
+
list_add(&rq->queuelist, insert_here);
/*
q->last_merge = &rq->queuelist;
}
-struct request *elv_next_request_fn(request_queue_t *q)
+int elevator_linus_init(request_queue_t *q, elevator_t *e)
{
- if (!blk_queue_empty(q))
- return list_entry_rq(q->queue_head.next);
+ int *latency;
- return NULL;
-}
+ latency = kmalloc(2 * sizeof(int), GFP_KERNEL);
+ if (!latency)
+ return -ENOMEM;
-int elv_linus_init(request_queue_t *q, elevator_t *e)
-{
+ latency[READ] = 8192;
+ latency[WRITE] = 16384;
+
+ e->elevator_data = latency;
return 0;
}
-void elv_linus_exit(request_queue_t *q, elevator_t *e)
+void elevator_linus_exit(request_queue_t *q, elevator_t *e)
{
+ kfree(e->elevator_data);
}
/*
+ * elevator noop
+ *
* See if we can find a request that this buffer can be coalesced with.
*/
int elevator_noop_merge(request_queue_t *q, struct request **req,
struct request *__rq;
int ret;
- if (q->last_merge) {
- __rq = list_entry_rq(q->last_merge);
- BUG_ON(__rq->flags & REQ_STARTED);
-
- if ((ret = elv_try_merge(__rq, bio))) {
- *req = __rq;
- return ret;
- }
- }
+ if ((ret = elv_try_last_merge(q, req, bio)))
+ return ret;
while ((entry = entry->prev) != &q->queue_head) {
__rq = list_entry_rq(entry);
return ELEVATOR_NO_MERGE;
}
-void elevator_noop_merge_cleanup(request_queue_t *q, struct request *req, int count) {}
+void elevator_noop_add_request(request_queue_t *q, struct request *rq,
+ struct list_head *insert_here)
+{
+ list_add_tail(&rq->queuelist, &q->queue_head);
+
+ /*
+ * new merges must not precede this barrier
+ */
+ if (rq->flags & REQ_BARRIER)
+ q->last_merge = NULL;
+ else if (!q->last_merge)
+ q->last_merge = &rq->queuelist;
+}
+
+struct request *elevator_noop_next_request(request_queue_t *q)
+{
+ if (!blk_queue_empty(q))
+ return list_entry_rq(q->queue_head.next);
-void elevator_noop_merge_req(struct request *req, struct request *next) {}
+ return NULL;
+}
+/*
+ * general block -> elevator interface starts here
+ */
int elevator_init(request_queue_t *q, elevator_t *e, elevator_t type)
{
*e = type;
return 0;
}
+void elv_merge_cleanup(request_queue_t *q, struct request *rq,
+ int nr_sectors)
+{
+ elevator_t *e = &q->elevator;
+
+ if (e->elevator_merge_cleanup_fn)
+ e->elevator_merge_cleanup_fn(q, rq, nr_sectors);
+}
+
+int elv_merge(request_queue_t *q, struct request **rq, struct bio *bio)
+{
+ elevator_t *e = &q->elevator;
+
+ if (e->elevator_merge_fn)
+ return e->elevator_merge_fn(q, rq, bio);
+
+ return ELEVATOR_NO_MERGE;
+}
+
+void elv_merge_requests(request_queue_t *q, struct request *rq,
+ struct request *next)
+{
+ elevator_t *e = &q->elevator;
+
+ if (e->elevator_merge_req_fn)
+ e->elevator_merge_req_fn(rq, next);
+}
+
+/*
+ * add_request and next_request are required to be supported, naturally
+ */
+void __elv_add_request(request_queue_t *q, struct request *rq,
+ struct list_head *insert_here)
+{
+ q->elevator.elevator_add_req_fn(q, rq, insert_here);
+}
+
+struct request *__elv_next_request(request_queue_t *q)
+{
+ return q->elevator.elevator_next_req_fn(q);
+}
+
+void elv_remove_request(request_queue_t *q, struct request *rq)
+{
+ elevator_t *e = &q->elevator;
+
+ if (e->elevator_remove_req_fn)
+ e->elevator_remove_req_fn(q, rq);
+}
+
+elevator_t elevator_linus = {
+ elevator_merge_fn: elevator_linus_merge,
+ elevator_merge_cleanup_fn: elevator_linus_merge_cleanup,
+ elevator_merge_req_fn: elevator_linus_merge_req,
+ elevator_next_req_fn: elevator_noop_next_request,
+ elevator_add_req_fn: elevator_linus_add_request,
+ elevator_init_fn: elevator_linus_init,
+ elevator_exit_fn: elevator_linus_exit,
+};
+
+elevator_t elevator_noop = {
+ elevator_merge_fn: elevator_noop_merge,
+ elevator_next_req_fn: elevator_noop_next_request,
+ elevator_add_req_fn: elevator_noop_add_request,
+};
+
module_init(elevator_global_init);
+
+EXPORT_SYMBOL(elevator_linus);
+EXPORT_SYMBOL(elevator_noop);
+
+EXPORT_SYMBOL(__elv_add_request);
+EXPORT_SYMBOL(__elv_next_request);
+EXPORT_SYMBOL(elv_remove_request);
struct bio *bio)
{
int nr_hw_segs = bio_hw_segments(q, bio);
+ int nr_phys_segs = bio_phys_segments(q, bio);
- if (req->nr_hw_segments + nr_hw_segs > q->max_hw_segments) {
+ if (req->nr_hw_segments + nr_hw_segs > q->max_hw_segments
+ || req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) {
req->flags |= REQ_NOMERGE;
q->last_merge = NULL;
return 0;
* counters.
*/
req->nr_hw_segments += nr_hw_segs;
- req->nr_phys_segments += bio_phys_segments(q, bio);
+ req->nr_phys_segments += nr_phys_segs;
return 1;
}
if (blk_init_free_list(q))
return -ENOMEM;
- if ((ret = elevator_init(q, &q->elevator, ELEVATOR_LINUS))) {
+ if ((ret = elevator_init(q, &q->elevator, elevator_linus))) {
blk_cleanup_queue(q);
return ret;
}
blk_queue_make_request(q, __make_request);
blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
+
+ blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
+ blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
return 0;
}
* elevator indicated where it wants this request to be
* inserted at elevator_merge time
*/
- q->elevator.elevator_add_req_fn(q, req, insert_here);
+ __elv_add_request(q, req, insert_here);
}
/*
* counts here.
*/
if (q->merge_requests_fn(q, req, next)) {
- q->elevator.elevator_merge_req_fn(req, next);
+ elv_merge_requests(q, req, next);
blkdev_dequeue_request(next);
static int __make_request(request_queue_t *q, struct bio *bio)
{
struct request *req, *freereq = NULL;
- int el_ret, latency = 0, rw, nr_sectors, cur_nr_sectors, barrier;
+ int el_ret, rw, nr_sectors, cur_nr_sectors, barrier;
struct list_head *insert_here;
- elevator_t *elevator = &q->elevator;
sector_t sector;
sector = bio->bi_sector;
spin_lock_prefetch(q->queue_lock);
- latency = elevator_request_latency(elevator, rw);
barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw);
spin_lock_irq(q->queue_lock);
goto get_rq;
}
- el_ret = elevator->elevator_merge_fn(q, &req, bio);
+ el_ret = elv_merge(q, &req, bio);
switch (el_ret) {
case ELEVATOR_BACK_MERGE:
BUG_ON(!rq_mergeable(req));
if (!q->back_merge_fn(q, req, bio))
break;
- elevator->elevator_merge_cleanup_fn(q, req, nr_sectors);
+ elv_merge_cleanup(q, req, nr_sectors);
req->biotail->bi_next = bio;
req->biotail = bio;
if (!q->front_merge_fn(q, req, bio))
break;
- elevator->elevator_merge_cleanup_fn(q, req, nr_sectors);
+ elv_merge_cleanup(q, req, nr_sectors);
bio->bi_next = req->bio;
req->bio = bio;
goto again;
}
- /*
- * fill up the request-info, and add it to the queue
- */
- req->elevator_sequence = latency;
-
/*
* first three bits are identical in rq->flags and bio->bi_rw,
* see bio.h and blkdev.h
{
if (S_ISREG(lo_dentry->d_inode->i_mode))
return (lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS;
- if (blk_size[MAJOR(lodev)])
- return blk_size[MAJOR(lodev)][MINOR(lodev)] -
+ if (blk_size[major(lodev)])
+ return blk_size[major(lodev)][minor(lodev)] -
(lo->lo_offset >> BLOCK_SIZE_BITS);
return MAX_DISK_SIZE;
}
*/
static int loop_end_io_transfer(struct bio *bio, int nr_sectors)
{
- struct loop_device *lo = &loop_dev[MINOR(bio->bi_dev)];
+ struct bio *rbh = bio->bi_private;
+ struct loop_device *lo = &loop_dev[minor(rbh->bi_dev)];
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
if (!uptodate || bio_rw(bio) == WRITE) {
- struct bio *rbh = bio->bi_private;
-
bio_endio(rbh, uptodate, nr_sectors);
if (atomic_dec_and_test(&lo->lo_pending))
up(&lo->lo_bh_mutex);
unsigned long IV;
int rw = bio_rw(rbh);
- if (MINOR(rbh->bi_dev) >= max_loop)
+ if (minor(rbh->bi_dev) >= max_loop)
goto out;
- lo = &loop_dev[MINOR(rbh->bi_dev)];
+ lo = &loop_dev[minor(rbh->bi_dev)];
spin_lock_irq(&lo->lo_lock);
if (lo->lo_state != Lo_bound)
goto inactive;
if (S_ISBLK(inode->i_mode)) {
lo_device = inode->i_rdev;
- if (lo_device == dev) {
+ if (kdev_same(lo_device, dev)) {
error = -EBUSY;
goto out;
}
loop_release_xfer(lo);
lo->transfer = NULL;
lo->ioctl = NULL;
- lo->lo_device = 0;
+ lo->lo_device = NODEV;
lo->lo_encrypt_type = 0;
lo->lo_offset = 0;
lo->lo_encrypt_key_size = 0;
if (!inode)
return -EINVAL;
- if (MAJOR(inode->i_rdev) != MAJOR_NR) {
+ if (major(inode->i_rdev) != MAJOR_NR) {
printk(KERN_WARNING "lo_ioctl: pseudo-major != %d\n",
MAJOR_NR);
return -ENODEV;
}
- dev = MINOR(inode->i_rdev);
+ dev = minor(inode->i_rdev);
if (dev >= max_loop)
return -ENODEV;
lo = &loop_dev[dev];
if (!inode)
return -EINVAL;
- if (MAJOR(inode->i_rdev) != MAJOR_NR) {
+ if (major(inode->i_rdev) != MAJOR_NR) {
printk(KERN_WARNING "lo_open: pseudo-major != %d\n", MAJOR_NR);
return -ENODEV;
}
- dev = MINOR(inode->i_rdev);
+ dev = minor(inode->i_rdev);
if (dev >= max_loop)
return -ENODEV;
if (!inode)
return 0;
- if (MAJOR(inode->i_rdev) != MAJOR_NR) {
+ if (major(inode->i_rdev) != MAJOR_NR) {
printk(KERN_WARNING "lo_release: pseudo-major != %d\n",
MAJOR_NR);
return 0;
}
- dev = MINOR(inode->i_rdev);
+ dev = minor(inode->i_rdev);
if (dev >= max_loop)
return 0;
blk_size[MAJOR_NR] = loop_sizes;
blksize_size[MAJOR_NR] = loop_blksizes;
for (i = 0; i < max_loop; i++)
- register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &lo_fops, 0);
+ register_disk(NULL, mk_kdev(MAJOR_NR, i), 1, &lo_fops, 0);
printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
return 0;
unsigned long offset, len;
int rw = sbh->bi_rw;
- minor = MINOR(sbh->bi_dev);
+ minor = minor(sbh->bi_dev);
if (minor >= NUM_RAMDISKS)
goto fail;
int error = -EINVAL;
unsigned int minor;
- if (!inode || !inode->i_rdev)
+ if (!inode || kdev_none(inode->i_rdev))
goto out;
- minor = MINOR(inode->i_rdev);
+ minor = minor(inode->i_rdev);
switch (cmd) {
case BLKFLSBUF:
rd_bdev[i] = NULL;
if (bdev)
blkdev_put(bdev, BDEV_FILE);
- destroy_buffers(MKDEV(MAJOR_NR, i));
+ destroy_buffers(mk_kdev(MAJOR_NR, i));
}
devfs_unregister (devfs_handle);
&rd_bd_op, NULL);
for (i = 0; i < NUM_RAMDISKS; i++)
- register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &rd_bd_op, rd_size<<1);
+ register_disk(NULL, mk_kdev(MAJOR_NR,i), 1, &rd_bd_op, rd_size<<1);
#ifdef CONFIG_BLK_DEV_INITRD
/* We ought to separate initrd operations here */
static unsigned short read_status_reg;
static unsigned short data_reg;
+static spinlock_t sonycd535_lock = SPIN_LOCK_UNLOCKED; /* queue lock */
+
static int initialized; /* Has the drive been initialized? */
static int sony_disc_changed = 1; /* Has the disk been changed
since the last check? */
end_request(0);
continue;
}
- switch (CURRENT->cmd) {
- case READ:
- /*
- * If the block address is invalid or the request goes beyond the end of
- * the media, return an error.
- */
-
- if (sony_toc->lead_out_start_lba <= (block / 4)) {
- end_request(0);
- return;
- }
- if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) {
- end_request(0);
- return;
- }
- while (0 < nsect) {
+ if(CURRENT->flags & REQ_CMD) {
+ switch (rq_data_dir(CURRENT)) {
+ case READ:
/*
- * If the requested sector is not currently in the read-ahead buffer,
- * it must be read in.
+ * If the block address is invalid or the request goes beyond the end of
+ * the media, return an error.
*/
- if ((block < sony_first_block) || (sony_last_block < block)) {
- sony_first_block = (block / 4) * 4;
- log_to_msf(block / 4, params);
-
- /*
- * If the full read-ahead would go beyond the end of the media, trim
- * it back to read just till the end of the media.
- */
- if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) {
- sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1;
- read_size = sony_toc->lead_out_start_lba - (block / 4);
- } else {
- sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1;
- read_size = sony_buffer_sectors;
- }
- size_to_buf(read_size, ¶ms[3]);
-
+
+ if (sony_toc->lead_out_start_lba <= (block / 4)) {
+ end_request(0);
+ return;
+ }
+ if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) {
+ end_request(0);
+ return;
+ }
+ while (0 < nsect) {
/*
- * Read the data. If the drive was not spinning,
- * spin it up and try some more.
+ * If the requested sector is not currently in the read-ahead buffer,
+ * it must be read in.
*/
- for (spin_up_retry=0 ;; ++spin_up_retry) {
- /* This loop has been modified to support the Sony
- * CDU-510/515 series, thanks to Claudio Porfiri
- * <C.Porfiri@nisms.tei.ericsson.se>.
- */
+ if ((block < sony_first_block) || (sony_last_block < block)) {
+ sony_first_block = (block / 4) * 4;
+ log_to_msf(block / 4, params);
+
/*
- * This part is to deal with very slow hardware. We
- * try at most MAX_SPINUP_RETRY times to read the same
- * block. A check for seek_and_read_N_blocks' result is
- * performed; if the result is wrong, the CDROM's engine
- * is restarted and the operation is tried again.
+ * If the full read-ahead would go beyond the end of the media, trim
+ * it back to read just till the end of the media.
*/
+ if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) {
+ sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1;
+ read_size = sony_toc->lead_out_start_lba - (block / 4);
+ } else {
+ sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1;
+ read_size = sony_buffer_sectors;
+ }
+ size_to_buf(read_size, ¶ms[3]);
+
/*
- * 1995-06-01: The system got problems when downloading
- * from Slackware CDROM, the problem seems to be:
- * seek_and_read_N_blocks returns BAD_STATUS and we
- * should wait for a while before retrying, so a new
- * part was added to discriminate the return value from
- * seek_and_read_N_blocks for the various cases.
+ * Read the data. If the drive was not spinning,
+ * spin it up and try some more.
*/
- int readStatus = seek_and_read_N_blocks(params, read_size,
- status, sony_buffer, (read_size * CDU535_BLOCK_SIZE));
- if (0 <= readStatus) /* Good data; common case, placed first */
- break;
- if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) {
- /* give up */
- if (readStatus == NO_ROOM)
- printk(CDU535_MESSAGE_NAME " No room to read from CD\n");
- else
- printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n",
- status[0]);
- sony_first_block = -1;
- sony_last_block = -1;
- end_request(0);
- return;
- }
- if (readStatus == BAD_STATUS) {
- /* Sleep for a while, then retry */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10);
- }
+ for (spin_up_retry=0 ;; ++spin_up_retry) {
+ /* This loop has been modified to support the Sony
+ * CDU-510/515 series, thanks to Claudio Porfiri
+ * <C.Porfiri@nisms.tei.ericsson.se>.
+ */
+ /*
+ * This part is to deal with very slow hardware. We
+ * try at most MAX_SPINUP_RETRY times to read the same
+ * block. A check for seek_and_read_N_blocks' result is
+ * performed; if the result is wrong, the CDROM's engine
+ * is restarted and the operation is tried again.
+ */
+ /*
+ * 1995-06-01: The system got problems when downloading
+ * from Slackware CDROM, the problem seems to be:
+ * seek_and_read_N_blocks returns BAD_STATUS and we
+ * should wait for a while before retrying, so a new
+ * part was added to discriminate the return value from
+ * seek_and_read_N_blocks for the various cases.
+ */
+ int readStatus = seek_and_read_N_blocks(params, read_size,
+ status, sony_buffer, (read_size * CDU535_BLOCK_SIZE));
+ if (0 <= readStatus) /* Good data; common case, placed first */
+ break;
+ if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) {
+ /* give up */
+ if (readStatus == NO_ROOM)
+ printk(CDU535_MESSAGE_NAME " No room to read from CD\n");
+ else
+ printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n",
+ status[0]);
+ sony_first_block = -1;
+ sony_last_block = -1;
+ end_request(0);
+ return;
+ }
+ if (readStatus == BAD_STATUS) {
+ /* Sleep for a while, then retry */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10);
+ }
#if DEBUG > 0
- printk(CDU535_MESSAGE_NAME
- " debug: calling spin up when reading data!\n");
+ printk(CDU535_MESSAGE_NAME
+ " debug: calling spin up when reading data!\n");
#endif
- cmd[0] = SONY535_SPIN_UP;
- do_sony_cmd(cmd, 1, status, NULL, 0, 0);
+ cmd[0] = SONY535_SPIN_UP;
+ do_sony_cmd(cmd, 1, status, NULL, 0, 0);
+ }
}
+ /*
+ * The data is in memory now, copy it to the buffer and advance to the
+ * next block to read.
+ */
+ copyoff = block - sony_first_block;
+ memcpy(CURRENT->buffer,
+ sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512);
+
+ block += 1;
+ nsect -= 1;
+ CURRENT->buffer += 512;
}
- /*
- * The data is in memory now, copy it to the buffer and advance to the
- * next block to read.
- */
- copyoff = block - sony_first_block;
- memcpy(CURRENT->buffer,
- sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512);
- block += 1;
- nsect -= 1;
- CURRENT->buffer += 512;
+ end_request(1);
+ break;
+
+ case WRITE:
+ end_request(0);
+ break;
+
+ default:
+ panic("Unknown SONY CD cmd");
}
-
- end_request(1);
- break;
-
- case WRITE:
- end_request(0);
- break;
-
- default:
- panic("Unknown SONY CD cmd");
}
}
}
-
/*
* Read the table of contents from the drive and set sony_toc_read if
* successful.
MAJOR_NR, CDU535_MESSAGE_NAME);
return -EIO;
}
- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &sonycd535_lock);
blksize_size[MAJOR_NR] = &sonycd535_block_size;
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */
static int acq_open(struct inode *inode, struct file *file)
{
- switch(MINOR(inode->i_rdev))
+ switch(minor(inode->i_rdev))
{
case WATCHDOG_MINOR:
spin_lock(&acq_lock);
static int acq_close(struct inode *inode, struct file *file)
{
- if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
+ if(minor(inode->i_rdev)==WATCHDOG_MINOR)
{
spin_lock(&acq_lock);
#ifndef CONFIG_WATCHDOG_NOWAYOUT
static int
advwdt_open(struct inode *inode, struct file *file)
{
- switch (MINOR(inode->i_rdev)) {
+ switch (minor(inode->i_rdev)) {
case WATCHDOG_MINOR:
spin_lock(&advwdt_lock);
if (advwdt_is_open) {
static int
advwdt_close(struct inode *inode, struct file *file)
{
- if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+ if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
spin_lock(&advwdt_lock);
#ifndef CONFIG_WATCHDOG_NOWAYOUT
inb_p(WDT_STOP);
#define NR_MICE 15
#define FIRST_MOUSE 0
-#define DEV_TO_MOUSE(dev) MINOR_TO_MOUSE(MINOR(dev))
+#define DEV_TO_MOUSE(dev) MINOR_TO_MOUSE(minor(dev))
#define MINOR_TO_MOUSE(minor) ((minor) - FIRST_MOUSE)
/*
static int eurwdt_open(struct inode *inode, struct file *file)
{
- switch (MINOR(inode->i_rdev)) {
+ switch (minor(inode->i_rdev)) {
case WATCHDOG_MINOR:
spin_lock(&eurwdt_lock);
if (eurwdt_is_open) {
static int eurwdt_release(struct inode *inode, struct file *file)
{
- if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+ if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
#ifndef CONFIG_WATCHDOG_NOWAYOUT
eurwdt_disable_timer();
#endif
static int
ibwdt_open(struct inode *inode, struct file *file)
{
- switch (MINOR(inode->i_rdev)) {
+ switch (minor(inode->i_rdev)) {
case WATCHDOG_MINOR:
spin_lock(&ibwdt_lock);
if (ibwdt_is_open) {
ibwdt_close(struct inode *inode, struct file *file)
{
lock_kernel();
- if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+ if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
spin_lock(&ibwdt_lock);
#ifndef CONFIG_WATCHDOG_NOWAYOUT
outb_p(WD_TIMO, WDT_STOP);
char name[32];
#ifdef CONFIG_DEVFS_FS
- sprintf(name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
+ sprintf(name, tty->driver.name, minor(tty->device) - tty->driver.minor_start);
#else
- sprintf(name, "%s%d", tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
+ sprintf(name, "%s%d", tty->driver.name, minor(tty->device) - tty->driver.minor_start);
#endif
serio_register_port(&serport->serio);
static ssize_t lp_write(struct file * file, const char * buf,
size_t count, loff_t *ppos)
{
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
struct parport *port = lp_table[minor].dev->port;
char *kbuf = lp_table[minor].lp_buffer;
ssize_t retv = 0;
static ssize_t lp_read(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
- unsigned int minor=MINOR(file->f_dentry->d_inode->i_rdev);
+ unsigned int minor=minor(file->f_dentry->d_inode->i_rdev);
struct parport *port = lp_table[minor].dev->port;
ssize_t retval = 0;
char *kbuf = lp_table[minor].lp_buffer;
static int lp_open(struct inode * inode, struct file * file)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
if (minor >= LP_NO)
return -ENXIO;
static int lp_release(struct inode * inode, struct file * file)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
lp_claim_parport_or_block (&lp_table[minor]);
parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT);
static int lp_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
int status;
int retval = 0;
static int zf_open(struct inode *inode, struct file *file)
{
- switch(MINOR(inode->i_rdev)){
+ switch(minor(inode->i_rdev)){
case WATCHDOG_MINOR:
spin_lock(&zf_lock);
if(zf_is_open){
static int zf_close(struct inode *inode, struct file *file)
{
- if(MINOR(inode->i_rdev) == WATCHDOG_MINOR){
+ if(minor(inode->i_rdev) == WATCHDOG_MINOR){
if(zf_expect_close){
zf_timer_off();
static int pcwd_open(struct inode *ino, struct file *filep)
{
- switch (MINOR(ino->i_rdev))
+ switch (minor(ino->i_rdev))
{
case WATCHDOG_MINOR:
if ( !atomic_dec_and_test(&open_allowed) )
/* Can't seek (pread) on this device */
if (ppos != &file->f_pos)
return -ESPIPE;
- switch(MINOR(file->f_dentry->d_inode->i_rdev))
+ switch(minor(file->f_dentry->d_inode->i_rdev))
{
case TEMP_MINOR:
/*
static int pcwd_close(struct inode *ino, struct file *filep)
{
- if (MINOR(ino->i_rdev)==WATCHDOG_MINOR)
+ if (minor(ino->i_rdev)==WATCHDOG_MINOR)
{
#ifndef CONFIG_WATCHDOG_NOWAYOUT
/* Disable the board */
static ssize_t pp_read (struct file * file, char * buf, size_t count,
loff_t * ppos)
{
- unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
+ unsigned int minor = minor (file->f_dentry->d_inode->i_rdev);
struct pp_struct *pp = file->private_data;
char * kbuffer;
ssize_t bytes_read = 0;
static ssize_t pp_write (struct file * file, const char * buf, size_t count,
loff_t * ppos)
{
- unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
+ unsigned int minor = minor (file->f_dentry->d_inode->i_rdev);
struct pp_struct *pp = file->private_data;
char * kbuffer;
ssize_t bytes_written = 0;
static int pp_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct pp_struct *pp = file->private_data;
struct parport * port;
static int pp_open (struct inode * inode, struct file * file)
{
- unsigned int minor = MINOR (inode->i_rdev);
+ unsigned int minor = minor (inode->i_rdev);
struct pp_struct *pp;
if (minor >= PARPORT_MAX)
static int pp_release (struct inode * inode, struct file * file)
{
- unsigned int minor = MINOR (inode->i_rdev);
+ unsigned int minor = minor (inode->i_rdev);
struct pp_struct *pp = file->private_data;
int compat_negot;
/* Guesses if the device is a local hard drive */
static int is_local_disk(kdev_t dev) {
unsigned int major;
- major = MAJOR(dev);
+ major = major(dev);
switch (major) {
case IDE0_MAJOR:
for (sb = sb_entry(super_blocks.next);
sb != sb_entry(&super_blocks);
sb = sb_entry(sb->s_list.next))
- if (!is_local_disk(sb->s_dev) && MAJOR(sb->s_dev))
+ if (!is_local_disk(sb->s_dev) && major(sb->s_dev))
go_sync(sb, remount_flag);
unlock_kernel();
int idx = minor - driver->minor_start;
char buf[32];
- switch (device) {
- case TTY_DEV:
- case PTMX_DEV:
+ if (IS_TTY_DEV(device) || IS_PTMX_DEV(device))
+ mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ else {
+ if (driver->major == PTY_MASTER_MAJOR)
mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
- break;
- default:
- if (driver->major == PTY_MASTER_MAJOR)
- mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
- break;
}
if ( (minor < driver->minor_start) ||
(minor >= driver->minor_start + driver->num) ) {
if (ptr != &file->f_pos)
return -ESPIPE;
- switch(MINOR(file->f_dentry->d_inode->i_rdev))
+ switch(minor(file->f_dentry->d_inode->i_rdev))
{
case TEMP_MINOR:
c*=11;
static int wdt_open(struct inode *inode, struct file *file)
{
- switch(MINOR(inode->i_rdev))
+ switch(minor(inode->i_rdev))
{
case WATCHDOG_MINOR:
if(test_and_set_bit(0, &wdt_is_open))
static int wdt_release(struct inode *inode, struct file *file)
{
- if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
+ if(minor(inode->i_rdev)==WATCHDOG_MINOR)
{
#ifndef CONFIG_WATCHDOG_NOWAYOUT
inb_p(WDT_DC); /* Disable counters */
if (ptr != &file->f_pos)
return -ESPIPE;
- switch(MINOR(file->f_dentry->d_inode->i_rdev))
+ switch(minor(file->f_dentry->d_inode->i_rdev))
{
case TEMP_MINOR:
c*=11;
static int wdtpci_open(struct inode *inode, struct file *file)
{
- switch(MINOR(inode->i_rdev))
+ switch(minor(inode->i_rdev))
{
case WATCHDOG_MINOR:
if( test_and_set_bit(0,&wdt_is_open) )
static int wdtpci_release(struct inode *inode, struct file *file)
{
- if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
+ if(minor(inode->i_rdev)==WATCHDOG_MINOR)
{
#ifndef CONFIG_WATCHDOG_NOWAYOUT
inb_p(WDT_DC); /* Disable counters */
int i2cdev_open (struct inode *inode, struct file *file)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct i2c_client *client;
if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) {
static int i2cdev_release (struct inode *inode, struct file *file)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
kfree(file->private_data);
file->private_data=NULL;
#ifdef DEBUG
* Version 1.11 Highmem I/O support, Jens Axboe <axboe@suse.de>
*/
-#define IDEDISK_VERSION "1.10"
+#define IDEDISK_VERSION "1.11"
#undef REALLY_SLOW_IO /* most systems can safely undef this */
}
}
-static inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
ide_input_data(drive, buffer, wcount);
if (drive->bswap)
{
request_queue_t *q = &drive->queue;
int max_sectors;
+#ifdef CONFIG_BLK_DEV_PDC4030
+ int is_pdc4030_chipset = (HWIF(drive)->chipset == ide_pdc4030);
+#else
+ const int is_pdc4030_chipset = 0;
+#endif
q->queuedata = HWGROUP(drive);
blk_init_queue(q, do_ide_request, &ide_lock);
blk_queue_segment_boundary(q, 0xffff);
/* IDE can do up to 128K per request, pdc4030 needs smaller limit */
-#ifdef CONFIG_BLK_DEV_PDC4030
- max_sectors = 127;
-#else
- max_sectors = 255;
-#endif
+ max_sectors = (is_pdc4030_chipset ? 127 : 255);
blk_queue_max_sectors(q, max_sectors);
/* IDE DMA can do PRD_ENTRIES number of segments. */
printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev));
goto kill_rq;
}
-#ifdef DEBUG
- if (rq->bh && !buffer_locked(rq->bh)) {
- printk("%s: block not locked\n", drive->name);
- goto kill_rq;
- }
-#endif
block = rq->sector;
/* Strange disk manager remap */
* some technical information which has shed a glimmer of light on some of the
* problems I was having, especially with writes.
*
- * There are still problems with the robustness and efficiency of this driver
- * because I still don't understand what the card is doing with interrupts.
+ * There are still potential problems with the robustness and efficiency of
+ * this driver because I still don't understand what the card is doing with
+ * interrupts, however, it has been stable for a while with no reports of ill
+ * effects.
*/
#define DEBUG_READ
byte stat;
int total_remaining;
unsigned int sectors_left, sectors_avail, nsect;
+ unsigned long flags;
struct request *rq;
+ char *to;
if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
return ide_error(drive, "promise_read_intr", stat);
if (nsect > sectors_avail)
nsect = sectors_avail;
sectors_avail -= nsect;
- ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
+ to = ide_map_buffer(rq, &flags);
+ idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
#ifdef DEBUG_READ
printk(KERN_DEBUG "%s: promise_read: sectors(%ld-%ld), "
"buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
- rq->sector+nsect-1, (unsigned long) rq->buffer,
- rq->nr_sectors-nsect);
+ rq->sector+nsect-1, (unsigned long) to, rq->nr_sectors-nsect);
#endif
+ ide_unmap_buffer(to, &flags);
rq->sector += nsect;
- rq->buffer += nsect<<9;
rq->errors = 0;
rq->nr_sectors -= nsect;
total_remaining = rq->nr_sectors;
#ifdef DEBUG_WRITE
printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
#endif
- for (i = rq->nr_sectors; i > 0; ) {
- i -= rq->current_nr_sectors;
- ide_end_request(1, hwgroup);
- }
+ __ide_end_request(hwgroup, 1, rq->nr_sectors);
return ide_stopped;
}
unsigned long timeout;
byte stat;
- if (rq->cmd == READ) {
+/* Check that it's a regular command. If not, bomb out early. */
+ if (!(rq->flags & REQ_CMD)) {
+ blk_dump_rq_flags(rq, "pdc4030 bad flags");
+ ide_end_request(0, HWGROUP(drive));
+ return ide_stopped;
+ }
+
+ switch (rq_data_dir(rq)) {
+ case READ:
OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
/*
* The card's behaviour is odd at this point. If the data is
printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n",
drive->name);
return ide_stopped;
- } else if (rq->cmd == WRITE) {
+ break;
+
+ case WRITE:
ide_startstop_t startstop;
OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
+/*
+ * Strategy on write is:
+ * look for the DRQ that should have been immediately asserted
+ * copy the request into the hwgroup's scratchpad
+ * call the promise_write function to deal with writing the data out
+ * NOTE: No interrupts are generated on writes. Write completion must be polled
+ */
if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
printk(KERN_ERR "%s: no DRQ after issuing "
"PROMISE_WRITE\n", drive->name);
__cli(); /* local CPU only */
HWGROUP(drive)->wrq = *rq; /* scratchpad */
return promise_write(drive);
+ break;
- } else {
- printk("KERN_WARNING %s: bad command: %d\n",
- drive->name, rq->cmd);
+ default:
+ printk(KERN_ERR "pdc4030: command not READ or WRITE! Huh?\n");
ide_end_request(0, HWGROUP(drive));
- return ide_stopped;
+ break;
}
}
static int evdev_open(struct inode * inode, struct file * file)
{
struct evdev_list *list;
- int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE;
+ int i = minor(inode->i_rdev) - EVDEV_MINOR_BASE;
if (i >= EVDEV_MINORS || !evdev_table[i])
return -ENODEV;
static int input_open_file(struct inode *inode, struct file *file)
{
- struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5];
+ struct input_handler *handler = input_table[minor(inode->i_rdev) >> 5];
struct file_operations *old_fops, *new_fops = NULL;
int err;
static int joydev_open(struct inode *inode, struct file *file)
{
struct joydev_list *list;
- int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE;
+ int i = minor(inode->i_rdev) - JOYDEV_MINOR_BASE;
if (i >= JOYDEV_MINORS || !joydev_table[i])
return -ENODEV;
static int mousedev_open(struct inode * inode, struct file * file)
{
struct mousedev_list *list;
- int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
+ int i = minor(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
return -ENODEV;
fi
bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
bool ' HiSax Support for US NI1' CONFIG_HISAX_NI1
+ int ' Maximum number of cards supported by HiSax' CONFIG_HISAX_MAX_CARDS 8
comment ' HiSax supported cards'
bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0
bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA
dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA
dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL
- dep_tristate 'Fritz!PCIv2 support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL
+ dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL
fi
endmenu
-/* $Id: avmcard.h,v 1.8.6.4 2001/09/23 22:24:33 kai Exp $
+/* $Id: avmcard.h,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
*
* Copyright 1999 by Carsten Paeth <calle@calle.de>
*
avm_c2
};
+typedef struct avmcard_dmabuf {
+ long size;
+ __u8 *dmabuf;
+ dma_addr_t dmaaddr;
+} avmcard_dmabuf;
+
typedef struct avmcard_dmainfo {
- __u32 recvlen;
- __u8 recvbuf[128+2048];
- struct sk_buff_head send_queue;
- __u8 sendbuf[128+2048];
-} avmcard_dmainfo;
+ __u32 recvlen;
+ avmcard_dmabuf recvbuf;
+
+ avmcard_dmabuf sendbuf;
+ struct sk_buff_head send_queue;
+ struct pci_dev *pcidev;
+} avmcard_dmainfo;
typedef struct avmcard {
char name[32];
int b1ctl_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl);
+avmcard_dmainfo *avmcard_dma_alloc(char *name, struct pci_dev *,
+ long rsize, long ssize);
+void avmcard_dma_free(avmcard_dmainfo *);
+
+
/* b1dma.c */
int b1pciv4_detect(avmcard *card);
int t1pci_detect(avmcard *card);
-/* $Id: b1.c,v 1.20.6.7 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
*
* Common module for AVM B1 cards.
*
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/pci.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include "capicmd.h"
#include "capiutil.h"
-static char *revision = "$Revision: 1.20.6.7 $";
+static char *revision = "$Revision: 1.1.4.1.2.1 $";
/* ------------------------------------------------------------- */
/* ------------------------------------------------------------- */
+#ifdef CONFIG_PCI
+
+avmcard_dmainfo *
+avmcard_dma_alloc(char *name, struct pci_dev *pdev, long rsize, long ssize)
+{
+ avmcard_dmainfo *p;
+ void *buf;
+
+ p = kmalloc(sizeof(avmcard_dmainfo), GFP_KERNEL);
+ if (!p) {
+ printk(KERN_WARNING "%s: no memory.\n", name);
+ goto err;
+ }
+ memset(p, 0, sizeof(avmcard_dmainfo));
+
+ p->recvbuf.size = rsize;
+ buf = pci_alloc_consistent(pdev, rsize, &p->recvbuf.dmaaddr);
+ if (!buf) {
+ printk(KERN_WARNING "%s: allocation of receive dma buffer failed.\n", name);
+ goto err_kfree;
+ }
+ p->recvbuf.dmabuf = buf;
+
+ p->sendbuf.size = ssize;
+ buf = pci_alloc_consistent(pdev, ssize, &p->sendbuf.dmaaddr);
+ if (!buf) {
+ printk(KERN_WARNING "%s: allocation of send dma buffer failed.\n", name);
+ goto err_free_consistent;
+ }
+
+ p->sendbuf.dmabuf = buf;
+ skb_queue_head_init(&p->send_queue);
+
+ return p;
+
+ err_free_consistent:
+ pci_free_consistent(p->pcidev, p->recvbuf.size,
+ p->recvbuf.dmabuf, p->recvbuf.dmaaddr);
+ err_kfree:
+ kfree(p);
+ err:
+ return 0;
+}
+
+void avmcard_dma_free(avmcard_dmainfo *p)
+{
+ pci_free_consistent(p->pcidev, p->recvbuf.size,
+ p->recvbuf.dmabuf, p->recvbuf.dmaaddr);
+ pci_free_consistent(p->pcidev, p->sendbuf.size,
+ p->sendbuf.dmabuf, p->sendbuf.dmaaddr);
+ skb_queue_purge(&p->send_queue);
+ kfree(p);
+}
+
+EXPORT_SYMBOL(avmcard_dma_alloc);
+EXPORT_SYMBOL(avmcard_dma_free);
+
+#endif
+
EXPORT_SYMBOL(b1_irq_table);
EXPORT_SYMBOL(b1_detect);
-/* $Id: b1dma.c,v 1.11.6.8 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1dma.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
*
* Common module for AVM B1 cards that support dma with AMCC
*
#error FIXME: driver requires 32-bit platform
#endif
-static char *revision = "$Revision: 1.11.6.8 $";
+static char *revision = "$Revision: 1.1.4.1.2.1 $";
/* ------------------------------------------------------------- */
cmd = CAPIMSG_COMMAND(skb->data);
subcmd = CAPIMSG_SUBCOMMAND(skb->data);
- p = dma->sendbuf;
+ p = dma->sendbuf.dmabuf;
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
__u16 dlen = CAPIMSG_DATALEN(skb->data);
_put_byte(&p, SEND_MESSAGE);
_put_slice(&p, skb->data, len);
}
- txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
+ txlen = (__u8 *)p - (__u8 *)dma->sendbuf.dmabuf;
#ifdef CONFIG_B1DMA_DEBUG
printk(KERN_DEBUG "tx(%d): put msg len=%d\n",
inint, txlen);
printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n",
inint, skb->data[2], txlen);
#endif
- memcpy(dma->sendbuf, skb->data+2, skb->len-2);
+ memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2);
}
txlen = (txlen + 3) & ~3;
- b1dmaoutmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf));
+ b1dmaoutmeml(card->mbase+AMCC_TXPTR, dma->sendbuf.dmaaddr);
b1dmaoutmeml(card->mbase+AMCC_TXLEN, txlen);
card->csr |= EN_TX_TC_INT;
avmcard_dmainfo *dma = card->dma;
struct capi_ctr *ctrl = cinfo->capi_ctrl;
struct sk_buff *skb;
- void *p = dma->recvbuf+4;
+ void *p = dma->recvbuf.dmabuf+4;
__u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
__u8 b1cmd = _get_byte(&p);
b1dmaoutmeml(card->mbase+AMCC_INTCSR, newcsr);
if ((status & RX_TC_INT) != 0) {
- __u8 *recvbuf = card->dma->recvbuf;
+ struct avmcard_dmainfo *dma = card->dma;
__u32 rxlen;
if (card->dma->recvlen == 0) {
- card->dma->recvlen = *((__u32 *)recvbuf);
- rxlen = (card->dma->recvlen + 3) & ~3;
+ dma->recvlen = *((__u32 *)dma->recvbuf.dmabuf);
+ rxlen = (dma->recvlen + 3) & ~3;
b1dmaoutmeml(card->mbase+AMCC_RXPTR,
- virt_to_phys(recvbuf+4));
+ dma->recvbuf.dmaaddr+4);
b1dmaoutmeml(card->mbase+AMCC_RXLEN, rxlen);
} else {
b1dma_handle_rx(card);
- card->dma->recvlen = 0;
- b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf));
+ dma->recvlen = 0;
+ b1dmaoutmeml(card->mbase+AMCC_RXPTR,
+ dma->recvbuf.dmaaddr);
b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4);
}
}
t1outp(card->port, 0x10, 0xF0);
card->dma->recvlen = 0;
- b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf));
+ b1dmaoutmeml(card->mbase+AMCC_RXPTR, card->dma->recvbuf.dmaaddr);
b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4);
card->csr |= EN_RX_TC_INT;
b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
__u8 flag;
int len = 0;
char *s;
- __u32 txaddr, txlen, rxaddr, rxlen, csr;
+ __u32 txoff, txlen, rxoff, rxlen, csr;
len += sprintf(page+len, "%-16s %s\n", "name", card->name);
len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
save_flags(flags);
cli();
- txaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x2c));
- txaddr -= (__u32)card->dma->sendbuf;
- txlen = b1dmainmeml(card->mbase+0x30);
+ txoff = (dma_addr_t)b1dmainmeml(card->mbase+0x2c)-card->dma->sendbuf.dmaaddr;
+ txlen = b1dmainmeml(card->mbase+0x30);
- rxaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x24));
- rxaddr -= (__u32)card->dma->recvbuf;
- rxlen = b1dmainmeml(card->mbase+0x28);
+ rxoff = (dma_addr_t)b1dmainmeml(card->mbase+0x24)-card->dma->recvbuf.dmaaddr;
+ rxlen = b1dmainmeml(card->mbase+0x28);
csr = b1dmainmeml(card->mbase+AMCC_INTCSR);
len += sprintf(page+len, "%-16s 0x%lx\n",
"csr", (unsigned long)csr);
len += sprintf(page+len, "%-16s %lu\n",
- "txoff", (unsigned long)txaddr);
+ "txoff", (unsigned long)txoff);
len += sprintf(page+len, "%-16s %lu\n",
"txlen", (unsigned long)txlen);
len += sprintf(page+len, "%-16s %lu\n",
- "rxoff", (unsigned long)rxaddr);
+ "rxoff", (unsigned long)rxoff);
len += sprintf(page+len, "%-16s %lu\n",
"rxlen", (unsigned long)rxlen);
-/* $Id: b1pci.c,v 1.29.6.5 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1pci.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
*
* Module for AVM B1 PCI-card.
*
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.29.6.5 $";
+static char *revision = "$Revision: 1.1.4.1.2.1 $";
/* ------------------------------------------------------------- */
/* ------------------------------------------------------------- */
-static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
+static int b1pci_add_card(struct capi_driver *driver,
+ struct capicardparams *p,
+ struct pci_dev *dev)
{
avmcard *card;
avmctrl_info *cinfo;
release_region(card->port, AVMB1_PORTLEN);
ctrl->driverdata = 0;
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
/* ------------------------------------------------------------- */
-static int b1pciv4_add_card(struct capi_driver *driver, struct capicardparams *p)
+static int b1pciv4_add_card(struct capi_driver *driver,
+ struct capicardparams *p,
+ struct pci_dev *dev)
{
avmcard *card;
avmctrl_info *cinfo;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
- card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+ card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
if (!card->dma) {
- printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ printk(KERN_WARNING "%s: dma alloc.\n", driver->name);
kfree(card);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
- memset(card->dma, 0, sizeof(avmcard_dmainfo));
cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -ENOMEM;
"%s: ports 0x%03x-0x%03x in use.\n",
driver->name, card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
driver->name, card->membase);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EIO;
driver->name, card->port, retval);
iounmap(card->mbase);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EIO;
iounmap(card->mbase);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
card->cardnr = cinfo->capi_ctrl->cnr;
- skb_queue_head_init(&card->dma->send_queue);
-
printk(KERN_INFO
"%s: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n",
driver->name, card->port, card->irq,
"%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
driver->name, param.port, param.irq, param.membase);
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
- retval = b1pciv4_add_card(driver, ¶m);
+ retval = b1pciv4_add_card(driver, ¶m, dev);
#else
- retval = b1pci_add_card(driver, ¶m);
+ retval = b1pci_add_card(driver, ¶m, dev);
#endif
if (retval != 0) {
printk(KERN_ERR
printk(KERN_INFO
"%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
driver->name, param.port, param.irq);
- retval = b1pci_add_card(driver, ¶m);
+ retval = b1pci_add_card(driver, ¶m, dev);
if (retval != 0) {
printk(KERN_ERR
"%s: no AVM-B1 at i/o %#x, irq %d detected\n",
-/* $Id: c4.c,v 1.20.6.11 2001/09/23 22:24:33 kai Exp $
+/* $Id: c4.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
*
* Module for AVM C4 & C2 card.
*
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.20.6.11 $";
+static char *revision = "$Revision: 1.1.4.1.2.1 $";
#undef CONFIG_C4_DEBUG
#undef CONFIG_C4_POLLDEBUG
cmd = CAPIMSG_COMMAND(skb->data);
subcmd = CAPIMSG_SUBCOMMAND(skb->data);
- p = dma->sendbuf;
+ p = dma->sendbuf.dmabuf;
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
__u16 dlen = CAPIMSG_DATALEN(skb->data);
_put_byte(&p, SEND_MESSAGE);
_put_slice(&p, skb->data, len);
}
- txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
+ txlen = (__u8 *)p - (__u8 *)dma->sendbuf.dmabuf;
#ifdef CONFIG_C4_DEBUG
printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen);
#endif
printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n",
card->name, skb->data[2], txlen);
#endif
- memcpy(dma->sendbuf, skb->data+2, skb->len-2);
+ memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2);
}
txlen = (txlen + 3) & ~3;
- c4outmeml(card->mbase+MBOX_DOWN_ADDR, virt_to_phys(dma->sendbuf));
+ c4outmeml(card->mbase+MBOX_DOWN_ADDR, dma->sendbuf.dmaaddr);
c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen);
card->csr |= DBELL_DOWN_ARM;
struct capi_ctr *ctrl;
avmctrl_info *cinfo;
struct sk_buff *skb;
- void *p = dma->recvbuf;
+ void *p = dma->recvbuf.dmabuf;
__u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
__u8 b1cmd = _get_byte(&p);
__u32 cidx;
c4outmeml(card->mbase+MBOX_UP_LEN, 0);
c4_handle_rx(card);
card->dma->recvlen = 0;
- c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf));
+ c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size);
c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
}
c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x08);
card->dma->recvlen = 0;
- c4outmeml(card->mbase+MBOX_UP_ADDR, virt_to_phys(card->dma->recvbuf));
- c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf));
+ c4outmeml(card->mbase+MBOX_UP_ADDR, card->dma->recvbuf.dmaaddr);
+ c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size);
c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
restore_flags(flags);
release_region(card->port, AVMB1_PORTLEN);
ctrl->driverdata = 0;
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
static int c4_add_card(struct capi_driver *driver,
struct capicardparams *p,
+ struct pci_dev *dev,
int nr)
{
avmctrl_info *cinfo;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
- card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+ card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
if (!card->dma) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
- memset(card->dma, 0, sizeof(avmcard_dmainfo));
cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -ENOMEM;
"%s: ports 0x%03x-0x%03x in use.\n",
driver->name, card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
driver->name, card->membase);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EIO;
driver->name, card->port, retval);
iounmap(card->mbase);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EIO;
iounmap(card->mbase);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
iounmap(card->mbase);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
card->cardnr = cinfo->capi_ctrl->cnr;
}
- skb_queue_head_init(&card->dma->send_queue);
-
printk(KERN_INFO
"%s: AVM C%d at i/o %#x, irq %d, mem %#lx\n",
driver->name, nr, card->port, card->irq, card->membase);
printk(KERN_INFO
"%s: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n",
driver->name, nr, param.port, param.irq, param.membase);
- retval = c4_add_card(driver, ¶m, nr);
+ retval = c4_add_card(driver, ¶m, dev, nr);
if (retval != 0) {
printk(KERN_ERR
"%s: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n",
};
struct capidev {
- struct capidev *next;
- struct file *file;
+ struct list_head list;
u16 applid;
u16 errcode;
- unsigned int minor;
unsigned userflags;
struct sk_buff_head recvqueue;
/* -------- global variables ---------------------------------------- */
-static struct capi_interface *capifuncs = 0;
-static struct capidev *capidev_openlist = 0;
+static struct capi_interface *capifuncs;
+static rwlock_t capidev_list_lock;
+static LIST_HEAD(capidev_list);
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-static struct capiminor *minors = 0;
+static struct capiminor *minors;
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-static kmem_cache_t *capidev_cachep = 0;
-static kmem_cache_t *capincci_cachep = 0;
+static kmem_cache_t *capidev_cachep;
+static kmem_cache_t *capincci_cachep;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-static kmem_cache_t *capiminor_cachep = 0;
-static kmem_cache_t *capidh_cachep = 0;
+static kmem_cache_t *capiminor_cachep;
+static kmem_cache_t *capidh_cachep;
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
printk(KERN_DEBUG "set mp->nccip\n");
#endif
#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
- kdev = MKDEV(capi_rawmajor, mp->minor);
+ kdev = mk_kdev(capi_rawmajor, mp->minor);
capifs_new_ncci('r', mp->minor, kdev);
- kdev = MKDEV(capi_ttymajor, mp->minor);
+ kdev = mk_kdev(capi_ttymajor, mp->minor);
capifs_new_ncci(0, mp->minor, kdev);
#endif
}
static struct capidev *capidev_alloc(struct file *file)
{
struct capidev *cdev;
- struct capidev **pp;
+ unsigned long flags;
cdev = (struct capidev *)kmem_cache_alloc(capidev_cachep, GFP_KERNEL);
if (!cdev)
return 0;
memset(cdev, 0, sizeof(struct capidev));
- cdev->file = file;
- cdev->minor = MINOR(file->f_dentry->d_inode->i_rdev);
skb_queue_head_init(&cdev->recvqueue);
init_waitqueue_head(&cdev->recvwait);
- pp=&capidev_openlist;
- while (*pp) pp = &(*pp)->next;
- *pp = cdev;
+ write_lock_irqsave(&capidev_list_lock, flags);
+ list_add_tail(&cdev->list, &capidev_list);
+ write_unlock_irqrestore(&capidev_list_lock, flags);
return cdev;
}
static void capidev_free(struct capidev *cdev)
{
- struct capidev **pp;
+ unsigned long flags;
if (cdev->applid)
(*capifuncs->capi_release) (cdev->applid);
cdev->applid = 0;
-
skb_queue_purge(&cdev->recvqueue);
-
- pp=&capidev_openlist;
- while (*pp && *pp != cdev) pp = &(*pp)->next;
- if (*pp)
- *pp = cdev->next;
-
+ write_lock_irqsave(&capidev_list_lock, flags);
+ list_del(&cdev->list);
+ write_unlock_irqrestore(&capidev_list_lock, flags);
kmem_cache_free(capidev_cachep, cdev);
}
static struct capidev *capidev_find(u16 applid)
{
- struct capidev *p;
- for (p=capidev_openlist; p; p = p->next) {
+ // FIXME this doesn't guarantee that the device won't go away shortly
+ struct list_head *l;
+ struct capidev *p = NULL;
+
+ read_lock(&capidev_list_lock);
+ list_for_each(l, &capidev_list) {
+ p = list_entry(l, struct capidev, list);
if (p->applid == applid)
break;
}
+ read_unlock(&capidev_list_lock);
+
+ if (l == &capidev_list)
+ return NULL;
+
return p;
}
if (file->private_data)
return -EEXIST;
- if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0)
+ if ((mp = capiminor_find(minor(file->f_dentry->d_inode->i_rdev))) == 0)
return -ENXIO;
if (mp->nccip == 0)
return -ENXIO;
{
struct capiminor *mp;
- if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0)
+ if ((mp = capiminor_find(minor(file->f_dentry->d_inode->i_rdev))) == 0)
return -ENXIO;
if (mp->nccip == 0)
return -ENXIO;
int count, int *eof, void *data)
{
struct capidev *cdev;
+ struct list_head *l;
int len = 0;
- for (cdev=capidev_openlist; cdev; cdev = cdev->next) {
- len += sprintf(page+len, "%d %d %lu %lu %lu %lu\n",
- cdev->minor,
+ read_lock(&capidev_list_lock);
+ list_for_each(l, &capidev_list) {
+ cdev = list_entry(l, struct capidev, list);
+ len += sprintf(page+len, "0 %d %lu %lu %lu %lu\n",
cdev->applid,
cdev->nrecvctlpkt,
cdev->nrecvdatapkt,
goto endloop;
}
}
+
endloop:
+ read_unlock(&capidev_list_lock);
if (len < count)
*eof = 1;
- if (len>count) len = count;
- if (len<0) len = 0;
+ if (len > count) len = count;
+ if (len < 0) len = 0;
return len;
}
{
struct capidev *cdev;
struct capincci *np;
+ struct list_head *l;
int len = 0;
- for (cdev=capidev_openlist; cdev; cdev = cdev->next) {
+ read_lock(&capidev_list_lock);
+ list_for_each(l, &capidev_list) {
+ cdev = list_entry(l, struct capidev, list);
for (np=cdev->nccis; np; np = np->next) {
len += sprintf(page+len, "%d 0x%x%s\n",
cdev->applid,
}
}
endloop:
+ read_unlock(&capidev_list_lock);
*start = page+off;
if (len < count)
*eof = 1;
inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
inode->i_nlink = 1;
inode->i_ino = ino + 2;
- init_special_inode(inode, sbi->mode|S_IFCHR, np->kdev);
+ init_special_inode(inode, sbi->mode|S_IFCHR, kdev_t_to_nr(np->kdev));
}
}
}
-/* $Id: t1pci.c,v 1.13.6.6 2001/09/23 22:24:34 kai Exp $
+/* $Id: t1pci.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
*
* Module for AVM T1 PCI-card.
*
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.13.6.6 $";
+static char *revision = "$Revision: 1.1.4.1.2.1 $";
#undef CONFIG_T1PCI_DEBUG
#undef CONFIG_T1PCI_POLLDEBUG
release_region(card->port, AVMB1_PORTLEN);
ctrl->driverdata = 0;
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
/* ------------------------------------------------------------- */
-static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
+static int t1pci_add_card(struct capi_driver *driver,
+ struct capicardparams *p,
+ struct pci_dev *dev)
{
avmcard *card;
avmctrl_info *cinfo;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
- card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+ card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
if (!card->dma) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
- memset(card->dma, 0, sizeof(avmcard_dmainfo));
cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -ENOMEM;
"%s: ports 0x%03x-0x%03x in use.\n",
driver->name, card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
driver->name, card->membase);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EIO;
driver->name, card->port, retval);
iounmap(card->mbase);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EIO;
iounmap(card->mbase);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
- kfree(card->dma);
+ avmcard_dma_free(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
card->cardnr = cinfo->capi_ctrl->cnr;
- skb_queue_head_init(&card->dma->send_queue);
-
printk(KERN_INFO
"%s: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n",
driver->name, card->port, card->irq, card->membase);
printk(KERN_INFO
"%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
driver->name, param.port, param.irq, param.membase);
- retval = t1pci_add_card(driver, ¶m);
+ retval = t1pci_add_card(driver, ¶m, dev);
if (retval != 0) {
printk(KERN_ERR
"%s: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n",
O_TARGET := vmlinux-obj.o
+# Define maximum number of cards
+
+EXTRA_CFLAGS += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS)
+
# Objects that export symbols.
export-objs := config.o fsm.o hisax_isac.o
-/* $Id: config.c,v 2.57.6.20 2001/09/23 22:24:47 kai Exp $
+/* $Id: config.c,v 1.1.4.2.2.1 2001/12/09 20:18:40 kai Exp $
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
NULL, \
}
-#define EMPTY_CARD {0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL}
-
-struct IsdnCard cards[] = {
+struct IsdnCard cards[HISAX_MAX_CARDS] = {
FIRST_CARD,
- EMPTY_CARD,
- EMPTY_CARD,
- EMPTY_CARD,
- EMPTY_CARD,
- EMPTY_CARD,
- EMPTY_CARD,
- EMPTY_CARD,
};
-static char HiSaxID[64] __devinitdata = { 0, };
+#define HISAX_IDSIZE (HISAX_MAX_CARDS*8)
+static char HiSaxID[HISAX_IDSIZE] __devinitdata = { 0, };
char *HiSax_id __devinitdata = HiSaxID;
#ifdef MODULE
/* Variables for insmod */
-static int type[8] __devinitdata = { 0, };
-static int protocol[8] __devinitdata = { 0, };
-static int io[8] __devinitdata = { 0, };
+static int type[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int protocol[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int io[HISAX_MAX_CARDS] __devinitdata = { 0, };
#undef IO0_IO1
#ifdef CONFIG_HISAX_16_3
#define IO0_IO1
#define IO0_IO1
#endif
#ifdef IO0_IO1
-static int io0[8] __devinitdata = { 0, };
-static int io1[8] __devinitdata = { 0, };
+static int io0[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int io1[HISAX_MAX_CARDS] __devinitdata = { 0, };
#endif
-static int irq[8] __devinitdata = { 0, };
-static int mem[8] __devinitdata = { 0, };
+static int irq[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int mem[HISAX_MAX_CARDS] __devinitdata = { 0, };
static char *id __devinitdata = HiSaxID;
+#define PARM_PARA "1-" __MODULE_STRING(HISAX_MAX_CARDS) "i"
+
MODULE_DESCRIPTION("ISDN4Linux: Driver for passive ISDN cards");
MODULE_AUTHOR("Karsten Keil");
MODULE_LICENSE("GPL");
-MODULE_PARM(type, "1-8i");
-MODULE_PARM(protocol, "1-8i");
-MODULE_PARM(io, "1-8i");
-MODULE_PARM(irq, "1-8i");
-MODULE_PARM(mem, "1-8i");
+MODULE_PARM(type, PARM_PARA);
+MODULE_PARM(protocol, PARM_PARA);
+MODULE_PARM(io, PARM_PARA);
+MODULE_PARM(irq, PARM_PARA);
+MODULE_PARM(mem, PARM_PARA);
MODULE_PARM(id, "s");
#ifdef IO0_IO1
-MODULE_PARM(io0, "1-8i");
-MODULE_PARM(io1, "1-8i");
+MODULE_PARM(io0, PARM_PARA);
+MODULE_PARM(io1, PARM_PARA);
#endif
#endif /* MODULE */
i = 0;
j = 1;
while (argc && (i < HISAX_MAX_CARDS)) {
+ cards[i].protocol = DEFAULT_PROTO;
if (argc) {
cards[i].typ = ints[j];
j++;
}
i++;
}
- if (str && *str) {
- strcpy(HiSaxID, str);
- HiSax_id = HiSaxID;
- } else {
+ if (str && *str) {
+ if (strlen(str) < HISAX_IDSIZE)
+ strcpy(HiSaxID, str);
+ else
+ printk(KERN_WARNING "HiSax: ID too long!");
+ } else
strcpy(HiSaxID, "HiSax");
- HiSax_id = HiSaxID;
- }
+
+ HiSax_id = HiSaxID;
return 1;
}
if (protocol[i]) {
cards[j].protocol = protocol[i];
nzproto++;
+ } else {
+ cards[j].protocol = DEFAULT_PROTO;
}
switch (type[i]) {
case ISDN_CTYPE_16_0:
} else {
/* QUADRO is a 4 BRI card */
cards[j++].para[0] = 1;
- cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
- cards[j].protocol = protocol[i];
- cards[j++].para[0] = 2;
- cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
- cards[j].protocol = protocol[i];
- cards[j++].para[0] = 3;
- cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
- cards[j].protocol = protocol[i];
- cards[j].para[0] = 4;
+ /* we need to check if further cards can be added */
+ if (j < HISAX_MAX_CARDS) {
+ cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+ cards[j].protocol = protocol[i];
+ cards[j++].para[0] = 2;
+ }
+ if (j < HISAX_MAX_CARDS) {
+ cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+ cards[j].protocol = protocol[i];
+ cards[j++].para[0] = 3;
+ }
+ if (j < HISAX_MAX_CARDS) {
+ cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+ cards[j].protocol = protocol[i];
+ cards[j].para[0] = 4;
+ }
}
break;
}
cards[i].typ = type[i];
if (protocol[i]) {
cards[i].protocol = protocol[i];
+ } else {
+ cards[i].protocol = DEFAULT_PROTO;
}
}
cards[0].para[0] = pcm_irq;
cards[i].typ = type[i];
if (protocol[i]) {
cards[i].protocol = protocol[i];
+ } else {
+ cards[i].protocol = DEFAULT_PROTO;
}
}
cards[0].para[0] = pcm_irq;
cards[i].typ = type[i];
if (protocol[i]) {
cards[i].protocol = protocol[i];
+ } else {
+ cards[i].protocol = DEFAULT_PROTO;
}
}
cards[0].para[0] = pcm_irq;
cards[i].typ = type[i];
if (protocol[i]) {
cards[i].protocol = protocol[i];
+ } else {
+ cards[i].protocol = DEFAULT_PROTO;
}
}
cards[0].para[0] = pcm_irq;
-/* $Id: hisax.h,v 2.52.6.9 2001/09/23 22:24:48 kai Exp $
+/* $Id: hisax.h,v 1.1.4.1.2.1 2001/12/09 20:18:40 kai Exp $
*
* Basic declarations, defines and prototypes
*
#define MON0_TX 4
#define MON1_TX 8
-#define HISAX_MAX_CARDS 8
-
#define ISDN_CTYPE_16_0 1
#define ISDN_CTYPE_8_0 2
#define ISDN_CTYPE_16_3 3
static ssize_t
isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
{
- uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ uint minor = minor(file->f_dentry->d_inode->i_rdev);
int len = 0;
ulong flags;
int drvidx;
static ssize_t
isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
{
- uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ uint minor = minor(file->f_dentry->d_inode->i_rdev);
int drvidx;
int chidx;
int retval;
isdn_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
lock_kernel();
static int
isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
{
- uint minor = MINOR(inode->i_rdev);
+ uint minor = minor(inode->i_rdev);
isdn_ctrl c;
int drvidx;
int chidx;
static int
isdn_open(struct inode *ino, struct file *filep)
{
- uint minor = MINOR(ino->i_rdev);
+ uint minor = minor(ino->i_rdev);
int drvidx;
int chidx;
int retval = -ENODEV;
static int
isdn_close(struct inode *ino, struct file *filep)
{
- uint minor = MINOR(ino->i_rdev);
+ uint minor = minor(ino->i_rdev);
lock_kernel();
if (minor == ISDN_MINOR_STATUS) {
if (is->debug & 0x2)
printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
- MINOR(file->f_dentry->d_inode->i_rdev));
+ minor(file->f_dentry->d_inode->i_rdev));
/* just registers wait_queue hook. This doesn't really wait. */
poll_wait(file, &is->wq, wait);
#ifdef MODEM_PARANOIA_CHECK
if (!info) {
printk(KERN_WARNING "isdn_tty: null info_struct for (%d, %d) in %s\n",
- MAJOR(device), MINOR(device), routine);
+ major(device), minor(device), routine);
return 1;
}
if (info->magic != ISDN_ASYNC_MAGIC) {
printk(KERN_WARNING "isdn_tty: bad magic for modem struct (%d, %d) in %s\n",
- MAJOR(device), MINOR(device), routine);
+ major(device), minor(device), routine);
return 1;
}
#endif
int retval,
line;
- line = MINOR(tty->device) - tty->driver.minor_start;
+ line = minor(tty->device) - tty->driver.minor_start;
if (line < 0 || line > ISDN_MAX_CHANNELS)
return -ENODEV;
info = &dev->mdm.info[line];
goto_high_power(cam);
do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
if (goto_low_power(cam))
- return -NODEV;
+ return -ENODEV;
}
/* procedure described in developer's guide p3-28 */
static ssize_t video_read(struct file *file,
char *buf, size_t count, loff_t *ppos)
{
- struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+ struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
if(vfl->read)
return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
else
static ssize_t video_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
- struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+ struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
if(vfl->write)
return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
else
static unsigned int video_poll(struct file *file, poll_table * wait)
{
- struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+ struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
if(vfl->poll)
return vfl->poll(vfl, file, wait);
else
static int video_open(struct inode *inode, struct file *file)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
int err, retval = 0;
struct video_device *vfl;
{
struct video_device *vfl;
lock_kernel();
- vfl=video_device[MINOR(inode->i_rdev)];
+ vfl=video_device[minor(inode->i_rdev)];
if(vfl->close)
vfl->close(vfl);
vfl->busy=0;
static int video_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct video_device *vfl=video_device[MINOR(inode->i_rdev)];
+ struct video_device *vfl=video_device[minor(inode->i_rdev)];
int err=vfl->ioctl(vfl, cmd, (void *)arg);
if(err!=-ENOIOCTLCMD)
int video_mmap(struct file *file, struct vm_area_struct *vma)
{
int ret = -EINVAL;
- struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+ struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
if(vfl->mmap) {
lock_kernel();
ret = vfl->mmap(vfl, (char *)vma->vm_start,
*/
#define DRV_NAME "de2104x"
-#define DRV_VERSION "0.5.1"
-#define DRV_RELDATE "Nov 20, 2001"
+#define DRV_VERSION "0.5.4"
+#define DRV_RELDATE "Jan 1, 2002"
#include <linux/config.h>
#include <linux/module.h>
#include <linux/rtnetlink.h>
#include <asm/io.h>
#include <asm/uaccess.h>
+#include <asm/unaligned.h>
/* These identify the driver base version and may not be removed. */
static char version[] __initdata =
#define DE_DUMMY_SKB ((struct sk_buff *) 2)
#define DE_SETUP_FRAME_WORDS 96
#define DE_EEPROM_WORDS 256
+#define DE_EEPROM_SIZE (DE_EEPROM_WORDS * sizeof(u16))
#define DE_MAX_MEDIA 5
#define DE_MEDIA_TP_AUTO 0
#define DE_MEDIA_INVALID DE_MAX_MEDIA
#define DE_MEDIA_FIRST 0
#define DE_MEDIA_LAST (DE_MAX_MEDIA - 1)
+#define DE_AUI_BNC (SUPPORTED_AUI | SUPPORTED_BNC)
+
#define DE_TIMER_LINK (60 * HZ)
#define DE_TIMER_NO_LINK (5 * HZ)
#define DE_REGS_VER 1
/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (6*HZ)
+#define TX_TIMEOUT (6*HZ)
+
+#define DE_UNALIGNED_16(a) (u16)(get_unaligned((u16 *)(a)))
/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
to support a pre-NWay full-duplex signaling mechanism using short frames.
u16 default_media;
u8 n_blocks;
u8 unused;
- struct de_srom_media_block media[0];
} __attribute__((packed));
struct de_desc {
struct media_info media[DE_MAX_MEDIA];
struct timer_list media_timer;
+ u8 *ee_data;
unsigned board_idx;
unsigned de21040 : 1;
unsigned media_lock : 1;
static void de_media_interrupt (struct de_private *de, u32 status);
static void de21040_media_timer (unsigned long data);
static void de21041_media_timer (unsigned long data);
+static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media);
static struct pci_device_id de_pci_tbl[] __initdata = {
dw32(MacStatus, dr32(MacStatus));
- synchronize_irq();
udelay(10);
de->rx_tail = 0;
else
de->macmode &= ~FullDuplex;
- if (netif_msg_link(de))
- printk(KERN_INFO "%s: set link %s, mode %x, sia %x,%x,%x,%x\n"
- KERN_INFO " set mode %x, set sia %x,%x,%x\n",
+ if (netif_msg_link(de)) {
+ printk(KERN_INFO "%s: set link %s\n"
+ KERN_INFO "%s: mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n"
+ KERN_INFO "%s: set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
de->dev->name, media_name[media],
- dr32(MacMode), dr32(SIAStatus), dr32(CSR13),
- dr32(CSR14), dr32(CSR15), de->macmode,
- de->media[media].csr13,
- de->media[media].csr14,
- de->media[media].csr15);
+ de->dev->name, dr32(MacMode), dr32(SIAStatus),
+ dr32(CSR13), dr32(CSR14), dr32(CSR15),
+ de->dev->name, de->macmode, de->media[media].csr13,
+ de->media[media].csr14, de->media[media].csr15);
+ }
+}
+
+static void de_next_media (struct de_private *de, u32 *media,
+ unsigned int n_media)
+{
+ unsigned int i;
+
+ for (i = 0; i < n_media; i++) {
+ if (de_ok_to_advertise(de, media[i])) {
+ de->media_type = media[i];
+ return;
+ }
+ }
}
static void de21040_media_timer (unsigned long data)
struct net_device *dev = de->dev;
u32 status = dr32(SIAStatus);
unsigned int carrier;
+ unsigned long flags;
carrier = (status & NetCxnErr) ? 0 : 1;
if (de->media_lock)
return;
- if (de->media_type == DE_MEDIA_AUI)
- de->media_type = DE_MEDIA_TP;
- else
- de->media_type = DE_MEDIA_AUI;
+ if (de->media_type == DE_MEDIA_AUI) {
+ u32 next_state = DE_MEDIA_TP;
+ de_next_media(de, &next_state, 1);
+ } else {
+ u32 next_state = DE_MEDIA_AUI;
+ de_next_media(de, &next_state, 1);
+ }
+ spin_lock_irqsave(&de->lock, flags);
de_stop_rxtx(de);
+ spin_unlock_irqrestore(&de->lock, flags);
de_set_media(de);
de_start_rxtx(de);
{
struct de_private *de = (struct de_private *) data;
struct net_device *dev = de->dev;
- u32 status = dr32(SIAStatus), new_media;
+ u32 status = dr32(SIAStatus);
unsigned int carrier;
+ unsigned long flags;
carrier = (status & NetCxnErr) ? 0 : 1;
/* if activity detected, use that as hint for new media type */
if (status & NonselPortActive) {
- if (de->media_type == DE_MEDIA_AUI)
- de->media_type = DE_MEDIA_TP;
- else
+ unsigned int have_media = 1;
+
+ /* if AUI/BNC selected, then activity is on TP port */
+ if (de->media_type == DE_MEDIA_AUI ||
+ de->media_type == DE_MEDIA_BNC) {
+ if (de_ok_to_advertise(de, DE_MEDIA_TP_AUTO))
+ de->media_type = DE_MEDIA_TP_AUTO;
+ else
+ have_media = 0;
+ }
+
+ /* TP selected. If there is only TP and BNC, then it's BNC */
+ else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_BNC) &&
+ de_ok_to_advertise(de, DE_MEDIA_BNC))
+ de->media_type = DE_MEDIA_BNC;
+
+ /* TP selected. If there is only TP and AUI, then it's AUI */
+ else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_AUI) &&
+ de_ok_to_advertise(de, DE_MEDIA_AUI))
de->media_type = DE_MEDIA_AUI;
- goto set_media;
- }
- /* move to next advertised media */
- new_media = de->media_type;
- do {
- if (new_media == DE_MEDIA_LAST)
- new_media = DE_MEDIA_FIRST;
+ /* otherwise, ignore the hint */
else
- new_media++;
- } while ((!de_ok_to_advertise(de, new_media)) &&
- (new_media != de->media_type));
+ have_media = 0;
- de->media_type = new_media;
+ if (have_media)
+ goto set_media;
+ }
+
+ /*
+ * Absent or ambiguous activity hint, move to next advertised
+ * media state. If de->media_type is left unchanged, this
+ * simply resets the PHY and reloads the current media settings.
+ */
+ if (de->media_type == DE_MEDIA_AUI) {
+ u32 next_states[] = { DE_MEDIA_BNC, DE_MEDIA_TP_AUTO };
+ de_next_media(de, next_states, ARRAY_SIZE(next_states));
+ } else if (de->media_type == DE_MEDIA_BNC) {
+ u32 next_states[] = { DE_MEDIA_TP_AUTO, DE_MEDIA_AUI };
+ de_next_media(de, next_states, ARRAY_SIZE(next_states));
+ } else {
+ u32 next_states[] = { DE_MEDIA_AUI, DE_MEDIA_BNC, DE_MEDIA_TP_AUTO };
+ de_next_media(de, next_states, ARRAY_SIZE(next_states));
+ }
set_media:
+ spin_lock_irqsave(&de->lock, flags);
de_stop_rxtx(de);
+ spin_unlock_irqrestore(&de->lock, flags);
de_set_media(de);
de_start_rxtx(de);
static int de_reset_mac (struct de_private *de)
{
- unsigned tmp;
- u32 status;
+ u32 status, tmp;
/*
* Reset MAC. Copied from de4x5.c.
*/
- dr32 (BusMode);
+ tmp = dr32 (BusMode);
+ if (tmp == 0xffffffff)
+ return -ENODEV;
mdelay (1);
- dw32 (BusMode, de_bus_mode | CmdReset);
+ dw32 (BusMode, tmp | CmdReset);
mdelay (1);
- dw32 (BusMode, de_bus_mode);
+ dw32 (BusMode, tmp);
mdelay (1);
for (tmp = 0; tmp < 5; tmp++) {
}
for (i = 0; i < DE_TX_RING_SIZE; i++) {
- if (de->tx_skb[i].skb) {
- struct sk_buff *skb = de->tx_skb[i].skb;
- pci_unmap_single(de->pdev, de->tx_skb[i].mapping,
- skb->len, PCI_DMA_TODEVICE);
- dev_kfree_skb(skb);
- de->net_stats.tx_dropped++;
+ struct sk_buff *skb = de->tx_skb[i].skb;
+ if ((skb) && (skb != DE_DUMMY_SKB)) {
+ if (skb != DE_SETUP_SKB) {
+ dev_kfree_skb(skb);
+ de->net_stats.tx_dropped++;
+ pci_unmap_single(de->pdev,
+ de->tx_skb[i].mapping,
+ skb->len, PCI_DMA_TODEVICE);
+ } else {
+ pci_unmap_single(de->pdev,
+ de->tx_skb[i].mapping,
+ sizeof(de->setup_frame),
+ PCI_DMA_TODEVICE);
+ }
}
}
{
struct de_private *de = dev->priv;
int rc;
+ unsigned long flags;
if (netif_msg_ifup(de))
printk(KERN_DEBUG "%s: enabling interface\n", dev->name);
}
netif_start_queue(dev);
+ mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
return 0;
err_out_hw:
+ spin_lock_irqsave(&de->lock, flags);
de_stop_hw(de);
+ spin_unlock_irqrestore(&de->lock, flags);
+
err_out_free:
de_free_rings(de);
return rc;
static int de_close (struct net_device *dev)
{
struct de_private *de = dev->priv;
+ unsigned long flags;
if (netif_msg_ifdown(de))
printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
- netif_stop_queue(dev);
- netif_carrier_off(dev);
del_timer_sync(&de->media_timer);
+
+ spin_lock_irqsave(&de->lock, flags);
de_stop_hw(de);
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+ spin_unlock_irqrestore(&de->lock, flags);
+
free_irq(dev->irq, dev);
+
de_free_rings(de);
de_adapter_sleep(de);
pci_disable_device(de->pdev);
strcpy (info.driver, DRV_NAME);
strcpy (info.version, DRV_VERSION);
strcpy (info.bus_info, de->pdev->slot_name);
+ info.eedump_len = DE_EEPROM_SIZE;
info.regdump_len = DE_REGS_SIZE;
if (copy_to_user (useraddr, &info, sizeof (info)))
return -EFAULT;
return 0;
}
+ /* get SROM dump */
+ case ETHTOOL_GEEPROM: {
+ struct ethtool_eeprom eeprom;
+
+ if (!de->ee_data)
+ break;
+ if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
+ return -EFAULT;
+ if ((eeprom.offset != 0) || (eeprom.magic != 0) ||
+ (eeprom.len != DE_EEPROM_SIZE))
+ return -EINVAL;
+
+ useraddr += offsetof(struct ethtool_regs, data);
+ if (copy_to_user(useraddr, de->ee_data, DE_EEPROM_SIZE))
+ return -EFAULT;
+ }
+
default:
break;
}
}
}
-/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
+static void __init de21040_get_media_info(struct de_private *de)
+{
+ unsigned int i;
+
+ de->media_type = DE_MEDIA_TP;
+ de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full |
+ SUPPORTED_10baseT_Half | SUPPORTED_AUI;
+ de->media_advertise = de->media_supported;
+
+ for (i = 0; i < DE_MAX_MEDIA; i++) {
+ switch (i) {
+ case DE_MEDIA_AUI:
+ case DE_MEDIA_TP:
+ case DE_MEDIA_TP_FD:
+ de->media[i].type = i;
+ de->media[i].csr13 = t21040_csr13[i];
+ de->media[i].csr14 = t21040_csr14[i];
+ de->media[i].csr15 = t21040_csr15[i];
+ break;
+ default:
+ de->media[i].type = DE_MEDIA_INVALID;
+ break;
+ }
+ }
+}
/* Note: this routine returns extra data bits for size detection. */
static unsigned __init tulip_read_eeprom(void *regs, int location, int addr_len)
return retval;
}
-static void __init tulip_get_srom_info (struct de_private *de)
+static void __init de21041_get_srom_info (struct de_private *de)
{
unsigned i, sa_offset = 0, ofs;
- u8 ee_data[DE_EEPROM_WORDS * sizeof(u16)];
+ u8 ee_data[DE_EEPROM_SIZE + 6] = {};
unsigned ee_addr_size = tulip_read_eeprom(de->regs, 0xff, 8) & 0x40000 ? 8 : 6;
struct de_srom_info_leaf *il;
+ void *bufp;
/* download entire eeprom */
- for (i = 0; i < sizeof(ee_data)/2; i++)
+ for (i = 0; i < DE_EEPROM_WORDS; i++)
((u16 *)ee_data)[i] =
le16_to_cpu(tulip_read_eeprom(de->regs, i, ee_addr_size));
goto bad_srom;
/* get default media type */
- switch (il->default_media) {
+ switch (DE_UNALIGNED_16(&il->default_media)) {
case 0x0001: de->media_type = DE_MEDIA_BNC; break;
case 0x0002: de->media_type = DE_MEDIA_AUI; break;
case 0x0204: de->media_type = DE_MEDIA_TP_FD; break;
default: de->media_type = DE_MEDIA_TP_AUTO; break;
}
+ if (netif_msg_probe(de))
+ printk(KERN_INFO "de%d: SROM leaf offset %u, default media %s\n",
+ de->board_idx, ofs,
+ media_name[de->media_type]);
+
/* init SIA register values to defaults */
for (i = 0; i < DE_MAX_MEDIA; i++) {
de->media[i].type = DE_MEDIA_INVALID;
/* parse media blocks to see what medias are supported,
* and if any custom CSR values are provided
*/
+ bufp = ((void *)il) + sizeof(*il);
for (i = 0; i < il->n_blocks; i++) {
- struct de_srom_media_block *ib = &il[i].media[0];
+ struct de_srom_media_block *ib = bufp;
unsigned idx;
/* index based on media type in media block */
goto bad_srom;
}
- if (ib->opts & MediaCustomCSRs) {
- de->media[idx].csr13 = ib->csr13;
- de->media[idx].csr14 = ib->csr14;
- de->media[idx].csr15 = ib->csr15;
- }
-
de->media[idx].type = idx;
- de->media_advertise |= de->media_supported;
+
+ if (netif_msg_probe(de))
+ printk(KERN_INFO "de%d: media block #%u: %s",
+ de->board_idx, i,
+ media_name[de->media[idx].type]);
+
+ bufp += sizeof (ib->opts);
+
+ if (ib->opts & MediaCustomCSRs) {
+ de->media[idx].csr13 = DE_UNALIGNED_16(&ib->csr13);
+ de->media[idx].csr14 = DE_UNALIGNED_16(&ib->csr14);
+ de->media[idx].csr15 = DE_UNALIGNED_16(&ib->csr15);
+ bufp += sizeof(ib->csr13) + sizeof(ib->csr14) +
+ sizeof(ib->csr15);
+
+ if (netif_msg_probe(de))
+ printk(" (%x,%x,%x)\n",
+ de->media[idx].csr13,
+ de->media[idx].csr14,
+ de->media[idx].csr15);
+
+ } else if (netif_msg_probe(de))
+ printk("\n");
+
+ if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3]))
+ break;
}
+ de->media_advertise = de->media_supported;
+
fill_defaults:
/* fill in defaults, for cases where custom CSRs not used */
for (i = 0; i < DE_MAX_MEDIA; i++) {
de->media[i].csr15 = t21041_csr15[i];
}
- if (netif_msg_link(de))
- printk(KERN_INFO "de%d: SROM-listed ports: %s%s%s\n",
- de->board_idx,
- de->media_supported & SUPPORTED_TP ? "TP " : "",
- de->media_supported & SUPPORTED_BNC ? "BNC " : "",
- de->media_supported & SUPPORTED_AUI ? "AUI" : "");
+ de->ee_data = kmalloc(DE_EEPROM_SIZE, GFP_KERNEL);
+ if (de->ee_data)
+ memcpy(de->ee_data, &ee_data[0], DE_EEPROM_SIZE);
return;
de_adapter_wake(de);
/* make sure hardware is not running */
- de_stop_hw(de);
+ rc = de_reset_mac(de);
+ if (rc) {
+ printk(KERN_ERR PFX "Cannot reset MAC, pci dev %s\n",
+ pdev->slot_name);
+ goto err_out_iomap;
+ }
- /* get MAC address, and some register values related to media types */
+ /* get MAC address, initialize default media type and
+ * get list of supported media
+ */
if (de->de21040) {
- unsigned i;
-
de21040_get_mac_address(de);
-
- de->media_type = DE_MEDIA_TP;
- de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full |
- SUPPORTED_10baseT_Half | SUPPORTED_AUI;
- de->media_advertise = de->media_supported;
- for (i = 0; i < DE_MAX_MEDIA; i++) {
- switch (i) {
- case DE_MEDIA_AUI:
- case DE_MEDIA_TP:
- case DE_MEDIA_TP_FD:
- de->media[i].type = i;
- de->media[i].csr13 = t21040_csr13[i];
- de->media[i].csr14 = t21040_csr14[i];
- de->media[i].csr15 = t21040_csr15[i];
- break;
- default:
- de->media[i].type = DE_MEDIA_INVALID;
- break;
- }
- }
+ de21040_get_media_info(de);
} else {
- tulip_get_srom_info(de);
+ de21041_get_srom_info(de);
}
/* register new network interface with kernel */
return 0;
err_out_iomap:
+ if (de->ee_data)
+ kfree(de->ee_data);
iounmap(regs);
err_out_res:
pci_release_regions(pdev);
if (!dev)
BUG();
unregister_netdev(dev);
+ if (de->ee_data)
+ kfree(de->ee_data);
iounmap(de->regs);
pci_release_regions(pdev);
pci_disable_device(pdev);
static int __init dfx_eisa_init(void)
{
- int rc = -NODEV;
+ int rc = -ENODEV;
int i; /* used in for loops */
u16 port; /* temporary I/O (port) address */
u32 slot_id; /* EISA hardware (slot) ID read from adapter */
/* Give self a name */
sprintf(name, "%s%d", tty->driver.name,
- MINOR(tty->device) - tty->driver.minor_start +
+ minor(tty->device) - tty->driver.minor_start +
tty->driver.name_base);
hashbin_insert(irtty, (irda_queue_t *) self, (int) self, NULL);
/* Give self a hardware name */
sprintf(hwname, "%s%d", tty->driver.name,
- MINOR(tty->device) - tty->driver.minor_start +
+ minor(tty->device) - tty->driver.minor_start +
tty->driver.name_base);
/*
break;
if (slp->ctrl.leased) {
- if (slp->ctrl.line != line)
+ if (!kdev_same(slp->ctrl.line, line))
continue;
if (slp->ctrl.tty)
return NULL;
continue;
if (current->pid == slp->ctrl.pid) {
- if (slp->ctrl.line == line && score < 3) {
+ if (kdev_same(slp->ctrl.line, line) && score < 3) {
sel = i;
score = 3;
continue;
}
continue;
}
- if (slp->ctrl.line == line && score < 1) {
+ if (kdev_same(slp->ctrl.line, line) && score < 1) {
sel = i;
score = 1;
continue;
tty->disc_data = 0;
sl->tty = NULL;
if (!sl->leased)
- sl->line = 0;
+ sl->line = NODEV;
/* VSV = very important to remove timers */
#ifdef CONFIG_SLIP_SMART
unsigned long flags;
int n;
- if ((n=MINOR(file->f_dentry->d_inode->i_rdev)>>CARD_MINOR_BITS)
+ if ((n=minor(file->f_dentry->d_inode->i_rdev)>>CARD_MINOR_BITS)
>= nr_cards)
return -ENODEV;
cosa = cosa_cards+n;
- if ((n=MINOR(file->f_dentry->d_inode->i_rdev)
+ if ((n=minor(file->f_dentry->d_inode->i_rdev)
& ((1<<CARD_MINOR_BITS)-1)) >= cosa->nchannels)
return -ENODEV;
chan = cosa->chan + n;
if (!tty->driver_data){
int port;
- port = MINOR(tty->device) - tty->driver.minor_start;
+ port = minor(tty->device) - tty->driver.minor_start;
if ((port < 0) || (port >= NR_PORTS))
return -ENODEV;
void BusLogic_AcquireHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
ProcessorFlags_T *ProcessorFlags)
{
- spin_lock_irqsave(&io_request_lock, *ProcessorFlags);
+ spin_lock_irqsave(&HostAdapter->SCSI_Host->host_lock, *ProcessorFlags);
}
void BusLogic_ReleaseHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
ProcessorFlags_T *ProcessorFlags)
{
- spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags);
+ spin_unlock_irqrestore(&HostAdapter->SCSI_Host->host_lock, *ProcessorFlags);
}
#define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif /* CONFIG_PROC_FS */
-/*
- * XXX - Release and acquire the io_request_lock. These macros are needed
- * because the 2.4 kernel SCSI mid-level driver holds the 'io_request_lock'
- * on entry to SCSI low-level drivers.
- *
- * These definitions and all code that uses code should be removed when the
- * SCSI mid-level driver no longer holds the 'io_request_lock' on entry to
- * SCSI low-level driver detect, queuecommand, and reset entrypoints.
- *
- * The interrupt flags values doesn't matter in the macros because the
- * SCSI mid-level will save and restore the flags values before and after
- * calling advansys_detect, advansys_queuecommand, and advansys_reset where
- * these macros are used. We do want interrupts enabled after the lock is
- * released so an explicit sti() is done. The driver only needs interrupts
- * disabled when it acquires the per board lock.
- */
-#define ASC_UNLOCK_IO_REQUEST_LOCK \
- { \
- ulong flags; /* flags value not needed, cf. comment above. */ \
- save_flags(flags); \
- spin_unlock_irqrestore(&io_request_lock, flags); \
- sti(); /* enable interrupts */ \
- }
-
-#define ASC_LOCK_IO_REQUEST_LOCK \
- { \
- ulong flags; /* flags value not needed, cf. comment above. */ \
- spin_lock_irqsave(&io_request_lock, flags); \
- }
-
/* Asc Library return codes */
#define ASC_TRUE 1
#define ASC_FALSE 0
ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
} eep_config;
ulong last_reset; /* Saved last reset time */
- spinlock_t lock; /* Board spinlock */
#ifdef CONFIG_PROC_FS
/* /proc/scsi/advansys/[0...] */
char *prtbuf; /* /proc print buffer */
ASC_DBG(1, "advansys_detect: begin\n");
- /*
- * XXX - Remove this comment and the next line when SCSI mid-level
- * no longer acquires 'io_request_lock' before calling the SCSI
- * low-level detect entrypoint.
- */
- ASC_UNLOCK_IO_REQUEST_LOCK
-
#if ASC_LINUX_KERNEL24
tpnt->proc_name = "advansys";
#elif ASC_LINUX_KERNEL22
memset(boardp, 0, sizeof(asc_board_t));
boardp->id = asc_board_count - 1;
- /* Initialize spinlock. */
- boardp->lock = SPIN_LOCK_UNLOCKED;
-
/*
* Handle both narrow and wide boards.
*
}
}
- /*
- * XXX - Remove this comment and the next line when SCSI mid-level
- * no longer acquires 'io_request_lock' before calling the SCSI
- * low-level detect entrypoint.
- */
- ASC_LOCK_IO_REQUEST_LOCK
-
ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count);
return asc_board_count;
}
boardp = ASC_BOARDP(shp);
ASC_STATS(shp, queuecommand);
- /*
- * XXX - Remove this comment and the next line when SCSI mid-level
- * no longer acquires 'io_request_lock' before calling the SCSI
- * low-level queuecommand entrypoint.
- */
- ASC_UNLOCK_IO_REQUEST_LOCK
-
- spin_lock_irqsave(&boardp->lock, flags);
+ spin_lock_irqsave(&shp->host_lock, flags);
/*
* Block new commands while handling a reset or abort request.
* handling.
*/
asc_enqueue(&boardp->done, scp, ASC_BACK);
- spin_unlock_irqrestore(&boardp->lock, flags);
+ spin_unlock_irqrestore(&shp->host_lock, flags);
return 0;
}
break;
}
- spin_unlock_irqrestore(&boardp->lock, flags);
-
- /*
- * XXX - Remove this comment and the next line when SCSI mid-level
- * no longer acquires 'io_request_lock' before calling the SCSI
- * low-level queuecommand entrypoint.
- */
- ASC_LOCK_IO_REQUEST_LOCK
-
+ spin_unlock_irqrestore(&shp->host_lock, flags);
return 0;
}
/*
* Check for re-entrancy.
*/
- spin_lock_irqsave(&boardp->lock, flags);
+ spin_lock_irqsave(&shp->host_lock, flags);
if (boardp->flags & ASC_HOST_IN_RESET) {
- spin_unlock_irqrestore(&boardp->lock, flags);
+ spin_unlock_irqrestore(&shp->host_lock, flags);
return FAILED;
}
boardp->flags |= ASC_HOST_IN_RESET;
- spin_unlock_irqrestore(&boardp->lock, flags);
-
- /*
- * XXX - Remove this comment and the next line when SCSI mid-level
- * no longer acquires 'io_request_lock' before calling the SCSI
- * low-level reset entrypoint.
- */
- ASC_UNLOCK_IO_REQUEST_LOCK
+ spin_unlock_irqrestore(&shp->host_lock, flags);
if (ASC_NARROW_BOARD(boardp)) {
/*
/*
* Acquire the board lock.
*/
- spin_lock_irqsave(&boardp->lock, flags);
+ spin_lock_irqsave(&shp->host_lock, flags);
} else {
/*
* Acquire the board lock and ensure all requests completed by the
* microcode have been processed by calling AdvISR().
*/
- spin_lock_irqsave(&boardp->lock, flags);
+ spin_lock_irqsave(&shp->host_lock, flags);
(void) AdvISR(adv_dvc_varp);
}
boardp->flags &= ~ASC_HOST_IN_RESET;
/* Release the board. */
- spin_unlock_irqrestore(&boardp->lock, flags);
+ spin_unlock_irqrestore(&shp->host_lock, flags);
/*
* Complete all the 'done_scp' requests.
asc_scsi_done_list(done_scp);
}
- /*
- * XXX - Remove this comment and the next line when SCSI mid-level
- * no longer acquires 'io_request_lock' before calling the SCSI
- * low-level reset entrypoint.
- */
- ASC_LOCK_IO_REQUEST_LOCK
-
ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
return ret;
* AscISR() will call asc_isr_callback().
*/
for (i = 0; i < asc_board_count; i++) {
- boardp = ASC_BOARDP(asc_host[i]);
+ struct Scsi_Host *shp = asc_host[i];
+ boardp = ASC_BOARDP(shp);
ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
i, (ulong) boardp);
- spin_lock_irqsave(&boardp->lock, flags);
+ spin_lock_irqsave(&shp->host_lock, flags);
if (ASC_NARROW_BOARD(boardp)) {
/*
* Narrow Board
}
}
}
- spin_unlock_irqrestore(&boardp->lock, flags);
+ spin_unlock_irqrestore(&shp->host_lock, flags);
}
/*
printk(KERN_INFO "aha152x%d: trying software interrupt, ", HOSTNO);
SETPORT(DMACNTRL0, SWINT|INTEN);
- spin_unlock_irq(&io_request_lock);
+ spin_unlock_irq(&shpnt->host_lock);
mdelay(1000);
- spin_lock_irq(&io_request_lock);
+ spin_lock_irq(&shpnt->host_lock);
free_irq(shpnt->irq, shpnt);
if (!HOSTDATA(shpnt)->swint) {
/* A "high" level interrupt handler */
void aha1740_intr_handle(int irq, void *dev_id, struct pt_regs * regs)
{
+ struct Scsi_Host *host = aha_host[irq - 9];
void (*my_done)(Scsi_Cmnd *);
int errstatus, adapstat;
int number_serviced;
unsigned int base;
unsigned long flags;
- spin_lock_irqsave(&io_request_lock, flags);
-
- if (!aha_host[irq - 9])
+ if (!host)
panic("aha1740.c: Irq from unknown host!\n");
- base = aha_host[irq - 9]->io_port;
+ spin_lock_irqsave(&host->host_lock, flags);
+ base = host->io_port;
number_serviced = 0;
while(inb(G2STAT(base)) & G2STAT_INTPEND)
number_serviced++;
}
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_unlock_irqrestore(&host->host_lock, flags);
}
int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
msg[2] |= 0x80000000 | ((u32)wait_data->id);
timeout *= HZ;
if((status = adpt_i2o_post_this(pHba, msg, len)) == 0){
- if(!timeout){
- set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irq(&io_request_lock);
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irq(&pHba->host->host_lock);
+ if (!timeout)
schedule();
- spin_lock_irq(&io_request_lock);
- } else {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irq(&io_request_lock);
+ else
schedule_timeout(timeout*HZ);
- spin_lock_irq(&io_request_lock);
- }
+ spin_lock_irq(&pHba->host->host_lock);
}
wq_write_lock_irq(&adpt_wq_i2o_post.lock);
__remove_wait_queue(&adpt_wq_i2o_post, &wait);
//TODO check for root access
//
- minor = MINOR(inode->i_rdev);
+ minor = minor(inode->i_rdev);
if (minor >= hba_count) {
return -ENXIO;
}
int minor;
adpt_hba* pHba;
- minor = MINOR(inode->i_rdev);
+ minor = minor(inode->i_rdev);
if (minor >= hba_count) {
return -ENXIO;
}
}
do {
- spin_lock_irqsave(&io_request_lock, flags);
+ spin_lock_irqsave(&pHba->host->host_lock, flags);
// This state stops any new commands from enterring the
// controller while processing the ioctl
// pHba->state |= DPTI_STATE_IOCTL;
// the queue empties and stops. We need a way to restart the queue
rcode = adpt_i2o_post_wait(pHba, msg, size, FOREVER);
// pHba->state &= ~DPTI_STATE_IOCTL;
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_unlock_irqrestore(&pHba->host->host_lock, flags);
} while(rcode == -ETIMEDOUT);
if(rcode){
adpt_hba* pHba;
ulong flags;
- minor = MINOR(inode->i_rdev);
+ minor = minor(inode->i_rdev);
if (minor >= DPTI_MAX_HBA){
return -ENXIO;
}
break;
}
case I2ORESETCMD:
- spin_lock_irqsave(&io_request_lock, flags);
+ spin_lock_irqsave(&pHba->host->host_lock, flags);
adpt_hba_reset(pHba);
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_unlock_irqrestore(&pHba->host->host_lock, flags);
break;
case I2ORESCANCMD:
adpt_rescan(pHba);
static void adpt_isr(int irq, void *dev_id, struct pt_regs *regs)
{
Scsi_Cmnd* cmd;
- adpt_hba* pHba=NULL;
+ adpt_hba* pHba = dev_id;
u32 m;
ulong reply;
u32 status=0;
u32 context;
ulong flags = 0;
- pHba = dev_id;
if (pHba == NULL ){
printk(KERN_WARNING"adpt_isr: NULL dev_id\n");
return;
}
- spin_lock_irqsave(&io_request_lock, flags);
+ spin_lock_irqsave(&pHba->host->host_lock, flags);
while( readl(pHba->irq_mask) & I2O_INTERRUPT_PENDING_B) {
m = readl(pHba->reply_port);
if(m == EMPTY_QUEUE){
if(m == EMPTY_QUEUE){
// This really should not happen
printk(KERN_ERR"dpti: Could not get reply frame\n");
- spin_unlock_irqrestore(&io_request_lock,flags);
- return;
+ goto out;
}
}
reply = (ulong)bus_to_virt(m);
wmb();
rmb();
}
- spin_unlock_irqrestore(&io_request_lock, flags);
- return;
-
+out: spin_unlock_irqrestore(&pHba->host->host_lock, flags);
}
static s32 adpt_scsi_to_i2o(adpt_hba* pHba, Scsi_Cmnd* cmd, struct adpt_device* d)
s32 rcode;
ulong flags;
- spin_lock_irqsave(&io_request_lock, flags);
- if ((rcode=adpt_i2o_lct_get(pHba)) < 0){
- spin_unlock_irqrestore(&io_request_lock, flags);
- return rcode;
- }
-
- if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0){
- spin_unlock_irqrestore(&io_request_lock, flags);
- return rcode;
- }
- spin_unlock_irqrestore(&io_request_lock, flags);
- return 0;
+ spin_lock_irqsave(&pHba->host->host_lock, flags);
+ if ((rcode=adpt_i2o_lct_get(pHba)) < 0)
+ goto out;
+ if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0)
+ goto out;
+ rcode = 0;
+out: spin_unlock_irqrestore(&pHba->host->host_lock, flags);
+ return rcode;
}
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
*
+ * 01 Jan 2002 Rev. 7.20 for linux 2.5.1
+ * + Use the dynamic DMA mapping API.
+ *
+ * 19 Dec 2001 Rev. 7.02 for linux 2.5.1
+ * + Use SCpnt->sc_data_direction if set.
+ * + Use sglist.page instead of sglist.address.
+ *
* 11 Dec 2001 Rev. 7.00 for linux 2.5.1
* + Use host->host_lock instead of io_request_lock.
*
* This driver is based on the CAM (Common Access Method Committee)
* EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol.
*
- * Copyright (C) 1994-2001 Dario Ballabio (ballabio_dario@emc.com)
+ * Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com)
*
* Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it
*
u_int32_t data_len; /* If sg=0 Data Length, if sg=1 sglist length */
u_int32_t cpp_index; /* Index of address to be returned in sp */
u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */
- u_int32_t sp_addr; /* Address where sp is DMA'ed when cp completes */
+ u_int32_t sp_dma_addr; /* Address where sp is DMA'ed when cp completes */
u_int32_t sense_addr; /* Address where Sense Data is DMA'ed on error */
/* Additional fields begin here. */
Scsi_Cmnd *SCpnt;
unsigned long last_retried_pid; /* Pid of last retried command */
unsigned char subversion; /* Bus type, either ISA or EISA/PCI */
unsigned char protocol_rev; /* EATA 2.0 rev., 'A' or 'B' or 'C' */
- struct mssp sp[2]; /* Returned status for this board */
+ unsigned char is_pci; /* TRUE is bus type is PCI */
+ struct pci_dev *pdev; /* pdev for PCI bus, NULL otherwise */
+ struct mssp *sp_cpu_addr; /* cpu addr for DMA buffer sp */
+ dma_addr_t sp_dma_addr; /* dma handle for DMA buffer sp */
+ struct mssp sp; /* Local copy of sp buffer */
};
static struct Scsi_Host *sh[MAX_BOARDS + 1];
#define HD(board) ((struct hostdata *) &sh[board]->hostdata)
#define BN(board) (HD(board)->board_name)
-#define H2DEV(x) htonl(x)
-#define DEV2H(x) H2DEV(x)
+/* Device is Big Endian */
+#define H2DEV(x) cpu_to_be32(x)
+#define DEV2H(x) be32_to_cpu(x)
+
#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
-#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
static void do_interrupt_handler(int, void *, struct pt_regs *);
static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
static inline int port_detect \
(unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) {
- unsigned char irq, dma_channel, subversion, i;
+ unsigned char irq, dma_channel, subversion, i, is_pci = FALSE;
unsigned char protocol_rev;
struct eata_info info;
char *bus_type, dma_name[16], tag_type;
if (!setup_done && j > 0 && j <= MAX_PCI) {
bus_type = "PCI";
+ is_pci = TRUE;
subversion = ESA;
}
else if (port_base > MAX_EISA_ADDR || (protocol_rev == 'C' && info.pci)) {
bus_type = "PCI";
+ is_pci = TRUE;
subversion = ESA;
}
else if (port_base >= MIN_EISA_ADDR || (protocol_rev == 'C' && info.eisa)) {
}
else if (port_base > MAX_ISA_ADDR) {
bus_type = "PCI";
+ is_pci = TRUE;
subversion = ESA;
}
else {
printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
name, irq);
- pdev = get_pci_dev(port_base);
+ if (is_pci) {
+ pdev = get_pci_dev(port_base);
+ if (!pdev)
+ printk("%s: warning, failed to get pci_dev structure.\n", name);
+ }
+ else
+ pdev = NULL;
if (pdev && (irq != pdev->irq)) {
printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, pdev->irq);
/* Set board configuration */
memset((char *)&config, 0, sizeof(struct eata_config));
- config.len = (ushort) htons((ushort)510);
+ config.len = (ushort) cpu_to_be16((ushort)510);
config.ocena = TRUE;
if (do_dma(port_base, (unsigned long)&config, SET_CONFIG_DMA)) {
sh[j]->n_io_port = REGION_SIZE;
sh[j]->dma_channel = dma_channel;
sh[j]->irq = irq;
- sh[j]->sg_tablesize = (ushort) ntohs(info.scatt_size);
+ sh[j]->sg_tablesize = (ushort) be16_to_cpu(info.scatt_size);
sh[j]->this_id = (ushort) info.host_addr[3];
- sh[j]->can_queue = (ushort) ntohs(info.queue_size);
+ sh[j]->can_queue = (ushort) be16_to_cpu(info.queue_size);
sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
sh[j]->select_queue_depths = select_queue_depths;
memset(HD(j), 0, sizeof(struct hostdata));
HD(j)->subversion = subversion;
HD(j)->protocol_rev = protocol_rev;
+ HD(j)->is_pci = is_pci;
+ HD(j)->pdev = pdev;
HD(j)->board_number = j;
if (HD(j)->subversion == ESA)
unsigned long flags;
scsi_register_blocked_host(sh[j]);
sh[j]->unchecked_isa_dma = TRUE;
-
+
flags=claim_dma_lock();
disable_dma(dma_channel);
clear_dma_ff(dma_channel);
set_dma_mode(dma_channel, DMA_MODE_CASCADE);
enable_dma(dma_channel);
release_dma_lock(flags);
-
+
}
strcpy(BN(j), name);
return FALSE;
}
+ if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev,
+ sizeof(struct mssp), &HD(j)->sp_dma_addr))) {
+ printk("%s: pci_alloc_consistent failed, detaching.\n", BN(j));
+ eata2x_release(sh[j]);
+ return FALSE;
+ }
+
if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
else tag_type = 'n';
if (j == 0) {
- printk("EATA/DMA 2.0x: Copyright (C) 1994-2001 Dario Ballabio.\n");
+ printk("EATA/DMA 2.0x: Copyright (C) 1994-2002 Dario Ballabio.\n");
printk("%s config options -> tc:%c, lc:%c, mq:%d, rs:%c, et:%c.\n",
driver_name, tag_type, YESNO(linked_comm), max_queue_depth,
YESNO(rev_scan), YESNO(ext_tran));
info.pci, info.eisa, info.raidnum);
#endif
- if (pdev) pci_set_master(pdev);
+ if (HD(j)->pdev) {
+ pci_set_master(HD(j)->pdev);
+ if (pci_set_dma_mask(HD(j)->pdev, 0xffffffff))
+ printk("%s: warning, pci_set_dma_mask failed.\n", BN(j));
+ }
return TRUE;
}
return j;
}
-static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
- unsigned int k;
+static inline void map_dma(unsigned int i, unsigned int j) {
+ unsigned int k, count, pci_dir;
struct scatterlist *sgpnt;
+ struct mscp *cpp;
+ Scsi_Cmnd *SCpnt;
+
+ cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+ pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+ if (SCpnt->sense_buffer)
+ cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer,
+ sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
+
+ cpp->sense_len = sizeof SCpnt->sense_buffer;
+
+ if (!SCpnt->use_sg) {
+
+ if (!SCpnt->request_bufflen)
+ cpp->data_address = V2DEV(SCpnt->request_buffer);
+
+ else if (SCpnt->request_buffer)
+ cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev,
+ SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir));
+
+ cpp->data_len = H2DEV(SCpnt->request_bufflen);
+ return;
+ }
sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+ count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir);
- for (k = 0; k < SCpnt->use_sg; k++) {
- cpp->sglist[k].address = V2DEV(sgpnt[k].address);
- cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length);
+ for (k = 0; k < count; k++) {
+ cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k]));
+ cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k]));
}
+ cpp->sg = TRUE;
cpp->data_address = V2DEV(cpp->sglist);
cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list)));
}
-static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
- unsigned int i, j, k;
+static void unmap_dma(unsigned int i, unsigned int j) {
+ unsigned int pci_dir;
struct mscp *cpp;
- struct mssp *spp;
+ Scsi_Cmnd *SCpnt;
+
+ cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+ pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+ if (DEV2H(cpp->sense_addr))
+ pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
+ DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
+
+ if (SCpnt->use_sg)
+ pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir);
+
+ else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
+ pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address),
+ DEV2H(cpp->data_len), pci_dir);
+
+}
+
+static void sync_dma(unsigned int i, unsigned int j) {
+ unsigned int pci_dir;
+ struct mscp *cpp;
+ Scsi_Cmnd *SCpnt;
+
+ cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+ pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+ if (DEV2H(cpp->sense_addr))
+ pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
+ DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
+
+ if (SCpnt->use_sg)
+ pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer,
+ SCpnt->use_sg, pci_dir);
+
+ else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
+ pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address),
+ DEV2H(cpp->data_len), pci_dir);
+
+}
+
+static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) {
+ unsigned int k;
static const unsigned char data_out_cmds[] = {
0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
static const unsigned char data_none_cmds[] = {
0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e,
0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47,
- 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5
+ 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00
};
+ struct mscp *cpp;
+ Scsi_Cmnd *SCpnt;
+
+ cpp = &HD(j)->cp[i];
+ SCpnt = cpp->SCpnt;
+
+ if (SCpnt->sc_data_direction == SCSI_DATA_READ) {
+ cpp->din = TRUE;
+ cpp->dout = FALSE;
+ return;
+ }
+ else if (SCpnt->sc_data_direction == SCSI_DATA_WRITE) {
+ cpp->din = FALSE;
+ cpp->dout = TRUE;
+ return;
+ }
+ else if (SCpnt->sc_data_direction == SCSI_DATA_NONE) {
+ cpp->din = FALSE;
+ cpp->dout = FALSE;
+ return;
+ }
+
+ if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN)
+ panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j));
+
+ for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
+ if (SCpnt->cmnd[0] == data_out_cmds[k]) {
+ cpp->dout = TRUE;
+ break;
+ }
+
+ if ((cpp->din = !cpp->dout))
+ for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
+ if (SCpnt->cmnd[0] == data_none_cmds[k]) {
+ cpp->din = FALSE;
+ break;
+ }
+
+}
+
+static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+ unsigned int i, j, k;
+ struct mscp *cpp;
+
/* j is the board number */
j = ((struct hostdata *) SCpnt->host->hostdata)->board_number;
memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
- /* Set pointer to status packet structure */
- spp = &HD(j)->sp[0];
-
- /* The EATA protocol uses Big Endian format */
- cpp->sp_addr = V2DEV(spp);
+ /* Set pointer to status packet structure, Big Endian format */
+ cpp->sp_dma_addr = H2DEV(HD(j)->sp_dma_addr);
SCpnt->scsi_done = done;
cpp->cpp_index = i;
BN(j), i, SCpnt->channel, SCpnt->target,
SCpnt->lun, SCpnt->pid);
- for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
- if (SCpnt->cmnd[0] == data_out_cmds[k]) {
- cpp->dout = TRUE;
- break;
- }
-
- if ((cpp->din = !cpp->dout))
- for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
- if (SCpnt->cmnd[0] == data_none_cmds[k]) {
- cpp->din = FALSE;
- break;
- }
-
cpp->reqsen = TRUE;
cpp->dispri = TRUE;
#if 0
cpp->target = SCpnt->target;
cpp->lun = SCpnt->lun;
cpp->SCpnt = SCpnt;
- cpp->sense_addr = V2DEV(SCpnt->sense_buffer);
- cpp->sense_len = sizeof SCpnt->sense_buffer;
+ memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+
+ /* Use data transfer direction SCpnt->sc_data_direction */
+ scsi_to_dev_dir(i, j);
+
+ /* Map DMA buffers and SG list */
+ map_dma(i, j);
if (SCpnt->device->tagged_queue) {
cpp->mess[1] = SCpnt->device->current_tag++;
}
- if (SCpnt->use_sg) {
- cpp->sg = TRUE;
- build_sg_list(cpp, SCpnt);
- }
- else {
- cpp->data_address = V2DEV(SCpnt->request_buffer);
- cpp->data_len = H2DEV(SCpnt->request_bufflen);
- }
-
- memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
if (linked_comm && SCpnt->device->queue_depth > 2
&& TLDEV(SCpnt->device->type)) {
HD(j)->cp_stat[i] = READY;
/* Send control packet to the board */
if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) {
+ unmap_dma(i, j);
SCpnt->host_scribble = NULL;
printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
if (SCarg->eh_state == SCSI_STATE_TIMEOUT) {
+ unmap_dma(i, j);
SCarg->host_scribble = NULL;
HD(j)->cp_stat[i] = FREE;
printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n",
}
if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+ unmap_dma(i, j);
SCarg->result = DID_ABORT << 16;
SCarg->host_scribble = NULL;
HD(j)->cp_stat[i] = FREE;
if (HD(j)->cp_stat[i] == IN_RESET) {
SCpnt = HD(j)->cp[i].SCpnt;
+ unmap_dma(i, j);
SCpnt->result = DID_RESET << 16;
SCpnt->host_scribble = NULL;
else if (HD(j)->cp_stat[i] == ABORTING) {
SCpnt = HD(j)->cp[i].SCpnt;
+ unmap_dma(i, j);
SCpnt->result = DID_RESET << 16;
SCpnt->host_scribble = NULL;
static inline void ihdlr(int irq, unsigned int j) {
Scsi_Cmnd *SCpnt;
unsigned int i, k, c, status, tstatus, reg;
- struct mssp *dspp, *spp;
+ struct mssp *spp;
struct mscp *cpp;
if (sh[j]->irq != irq)
return;
}
- dspp = &HD(j)->sp[0];
- spp = &HD(j)->sp[1];
+ spp = &HD(j)->sp;
/* Make a local copy just before clearing the interrupt indication */
- memcpy(spp, dspp, sizeof(struct mssp));
+ memcpy(spp, HD(j)->sp_cpu_addr, sizeof(struct mssp));
/* Clear the completion flag and cp pointer on the dynamic copy of sp */
- memset(dspp, 0, sizeof(struct mssp));
+ memset(HD(j)->sp_cpu_addr, 0, sizeof(struct mssp));
/* Read the status register to clear the interrupt indication */
reg = inb(sh[j]->io_port + REG_STATUS);
panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
+ sync_dma(i, j);
+
if (linked_comm && SCpnt->device->queue_depth > 2
&& TLDEV(SCpnt->device->type))
flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
#else
status = DID_BUS_BUSY << 16;
#endif
+
HD(j)->retries++;
HD(j)->last_retried_pid = SCpnt->pid;
}
SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
reg, HD(j)->iocount);
+ unmap_dma(i, j);
+
/* Set the command state to inactive */
SCpnt->host_scribble = NULL;
if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
driver_name);
- if( sh[j]->unchecked_isa_dma ) {
- scsi_deregister_blocked_host(sh[j]);
- }
+ if(sh[j]->unchecked_isa_dma) scsi_deregister_blocked_host(sh[j]);
for (i = 0; i < sh[j]->can_queue; i++)
if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
+ if (HD(j)->sp_cpu_addr)
+ pci_free_consistent(HD(j)->pdev, sizeof(struct mssp),
+ HD(j)->sp_cpu_addr, HD(j)->sp_dma_addr);
+
free_irq(sh[j]->irq, &sha[j]);
if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
int eata2x_reset(Scsi_Cmnd *);
int eata2x_biosparam(Disk *, kdev_t, int *);
-#define EATA_VERSION "7.00.00"
+#define EATA_VERSION "7.20.00"
#define EATA { \
name: "EATA/DMA 2.0x rev. " EATA_VERSION " ", \
Write_FIFO = 12
};
-static int port_base = 0;
-static unsigned long bios_base = 0;
-static int bios_major = 0;
-static int bios_minor = 0;
-static int PCI_bus = 0;
-static int Quantum = 0; /* Quantum board variant */
-static int interrupt_level = 0;
-static volatile int in_command = 0;
-static Scsi_Cmnd *current_SC = NULL;
+/* .bss will zero all the static variables below */
+static int port_base;
+static unsigned long bios_base;
+static int bios_major;
+static int bios_minor;
+static int PCI_bus;
+static int Quantum; /* Quantum board variant */
+static int interrupt_level;
+static volatile int in_command;
+static Scsi_Cmnd *current_SC;
static enum chip_type chip = unknown;
-static int adapter_mask = 0;
-static int this_id = 0;
-static int setup_called = 0;
+static int adapter_mask;
+static int this_id;
+static int setup_called;
#if DEBUG_RACE
-static volatile int in_interrupt_flag = 0;
+static volatile int in_interrupt_flag;
#endif
static int SCSI_Mode_Cntl_port;
#if EVERY_ACCESS
printk( " AFAIL " );
#endif
- spin_lock_irqsave(&io_request_lock, flags);
+ spin_lock_irqsave(¤t_SC->host->host_lock, flags);
my_done( DID_BUS_BUSY << 16 );
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_unlock_irqrestore(¤t_SC->host->host_lock, flags);
return;
}
current_SC->SCp.phase = in_selection;
#if EVERY_ACCESS
printk( " SFAIL " );
#endif
- spin_lock_irqsave(&io_request_lock, flags);
+ spin_lock_irqsave(¤t_SC->host->host_lock, flags);
my_done( DID_NO_CONNECT << 16 );
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_unlock_irqrestore(¤t_SC->host->host_lock, flags);
return;
} else {
#if EVERY_ACCESS
#if EVERY_ACCESS
printk( "BEFORE MY_DONE. . ." );
#endif
- spin_lock_irqsave(&io_request_lock, flags);
+ spin_lock_irqsave(¤t_SC->host->host_lock, flags);
my_done( (current_SC->SCp.Status & 0xff)
| ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) );
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_unlock_irqrestore(¤t_SC->host->host_lock, flags);
#if EVERY_ACCESS
printk( "RETURNING.\n" );
#endif
0x0a bytes long. Heads are one less than we need to report.
*/
- if (MAJOR(dev) != SCSI_DISK0_MAJOR) {
+ if (major(dev) != SCSI_DISK0_MAJOR) {
printk("scsi: <fdomain> fdomain_16x0_biosparam: too many disks");
return 0;
}
- drive = MINOR(dev) >> 4;
+ drive = minor(dev) >> 4;
if (bios_major == 2) {
switch (Quantum) {
{
idescsi_scsi_t *scsi = drive->driver_data;
- if (MAJOR(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR)
+ if (major(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR)
return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
}
/* Get the spin_lock and disable further ints, for SMP */
- CLISPIN_LOCK(flags);
+ CLISPIN_LOCK(instance, flags);
#ifdef PROC_STATISTICS
hostdata->int_cnt++;
write1_io(0, IO_LED_OFF);
/* release the SMP spin_lock and restore irq state */
- CLISPIN_UNLOCK(flags);
+ CLISPIN_UNLOCK(instance, flags);
return;
}
write1_io(0, IO_LED_OFF);
/* release the SMP spin_lock and restore irq state */
- CLISPIN_UNLOCK(flags);
+ CLISPIN_UNLOCK(instance, flags);
return;
}
hostdata->state = S_UNCONNECTED;
/* release the SMP spin_lock and restore irq state */
- CLISPIN_UNLOCK(flags);
+ CLISPIN_UNLOCK(instance, flags);
return;
}
DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
DB(DB_INTR,printk("} "))
/* release the SMP spin_lock and restore irq state */
- CLISPIN_UNLOCK(flags);
+ CLISPIN_UNLOCK(instance, flags);
}
# define in2000__INITFUNC(function) __initfunc(function)
# define in2000__INIT __init
# define in2000__INITDATA __initdata
-# define CLISPIN_LOCK(flags) spin_lock_irqsave(&io_request_lock, flags)
-# define CLISPIN_UNLOCK(flags) spin_unlock_irqrestore(&io_request_lock, flags)
+# define CLISPIN_LOCK(host,flags) spin_lock_irqsave(&host->host_lock, flags)
+# define CLISPIN_UNLOCK(host,flags) spin_unlock_irqrestore(&host->host_lock, \
+ flags)
int in2000_detect(Scsi_Host_Template *) in2000__INIT;
int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
char *kern_area;
u_int32_t datasize;
- /* free io_request_lock */
- spin_unlock_irq(&io_request_lock);
+ spin_unlock_irq(&SC->host->host_lock);
/* wait for the command to finish */
down(&ha->ioctl_sem);
/* reobtain the lock */
- spin_lock_irq(&io_request_lock);
+ spin_lock_irq(&SC->host->host_lock);
/* command finished -- copy back */
user_area = *((char **) &SC->cmnd[4]);
/****************************************************************************/
void
do_ipsintr(int irq, void *dev_id, struct pt_regs *regs) {
- ips_ha_t *ha;
+ ips_ha_t *ha = (ips_ha_t *) dev_id;
unsigned long cpu_flags;
+ struct Scsi_Host *host = ips_sh[ha->host_num];
METHOD_TRACE("do_ipsintr", 2);
- ha = (ips_ha_t *) dev_id;
-
- spin_lock_irqsave(&io_request_lock, cpu_flags);
+ spin_lock_irqsave(&host->host_lock, cpu_flags);
if (test_and_set_bit(IPS_IN_INTR, &ha->flags)) {
- spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+ spin_unlock_irqrestore(&host->host_lock, cpu_flags);
return ;
}
if (!ha) {
clear_bit(IPS_IN_INTR, &ha->flags);
- spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+ spin_unlock_irqrestore(&host->host_lock, cpu_flags);
return;
}
if (!ha->active) {
clear_bit(IPS_IN_INTR, &ha->flags);
- spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+ spin_unlock_irqrestore(&host->host_lock, cpu_flags);
return;
}
clear_bit(IPS_IN_INTR, &ha->flags);
- spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+ spin_unlock_irqrestore(&host->host_lock, cpu_flags);
/* start the next command */
ips_next(ha, IPS_INTR_ON);
+ return;
}
/****************************************************************************/
task.routine = ips_scheduled_flash_bios;
task.data = (void *) &flash_data;
- /* Unlock the master lock */
- spin_unlock_irq(&io_request_lock);
+ /* Unlock the per-board lock */
+ spin_unlock_irq(&SC->host->host_lock);
queue_task(&task, &tq_immediate);
mark_bh(IMMEDIATE_BH);
/* Wait for the flash to complete */
down(&ha->flash_ioctl_sem);
- /* Obtain the master lock */
- spin_lock_irq(&io_request_lock);
+ /* Obtain the per-board lock */
+ spin_lock_irq(&SC->host->host_lock);
return (flash_data.retcode);
}
task.routine = ips_flash_bios_section;
task.data = (void *) &flash_data;
- /* Unlock the master lock */
- spin_unlock_irq(&io_request_lock);
+ /* Unlock the per-board lock */
+ spin_unlock_irq(&SC->host->host_lock);
queue_task(&task, &tq_immediate);
mark_bh(IMMEDIATE_BH);
/* Wait for the flash to complete */
down(&ha->flash_ioctl_sem);
- /* Obtain the master lock */
- spin_lock_irq(&io_request_lock);
+ /* Obtain the per-board lock */
+ spin_lock_irq(&SC->host->host_lock);
return (flash_data.retcode);
}
int intr_status;
unsigned long cpu_flags;
unsigned long cpu_flags2;
+ struct Scsi_Host *host;
METHOD_TRACE("ips_next", 1);
if (!ha)
return ;
+ host = ips_sh[ha->host_num];
+
/*
* Block access to the queue function so
* this command won't time out
*/
if (intr == IPS_INTR_ON) {
- spin_lock_irqsave(&io_request_lock, cpu_flags2);
+ spin_lock_irqsave(&host->host_lock, cpu_flags2);
intr_status = IPS_INTR_IORL;
} else {
intr_status = intr;
}
if (intr == IPS_INTR_ON)
- spin_unlock_irqrestore(&io_request_lock, cpu_flags2);
+ spin_unlock_irqrestore(&host->host_lock, cpu_flags2);
#ifndef NO_IPS_CMDLINE
/*
clear_bit(IPS_IN_INTR, &ha->flags);
} else if (intr == IPS_INTR_HAL) {
+ struct Scsi_Host *host = ips_sh[ha->host_num];
+
if (ha->waitflag == FALSE) {
/*
* controller generated an interrupt to
* We were called under the HA lock so we can assume that interrupts
* are masked.
*/
- spin_lock(&io_request_lock);
+ spin_lock(&host->host_lock);
while (test_and_set_bit(IPS_IN_INTR, &ha->flags))
udelay(1000);
clear_bit(IPS_IN_INTR, &ha->flags);
- spin_unlock(&io_request_lock);
+ spin_unlock(&host->host_lock);
}
udelay(1000); /* 1 milisecond */
int z;
unsigned long flags;
- /*
- * Disable interrupts, if they aren't already disabled and acquire
- * the I/O spinlock.
- */
- spin_lock_irqsave (&io_request_lock, flags);
DEB(printk ("\npci2000 received interrupt "));
for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process
if ( !shost )
{
DEB (printk ("\npci2000: not my interrupt"));
- goto irq_return;
+ goto out;
}
+ spin_lock_irqsave(&shost->host_lock, flags);
padapter = HOSTDATA(shost);
tag0 = tag & 0x7F; // mask off the error bit
outb_p (CMD_DONE, padapter->cmd); // complete the op
OpDone (SCpnt, DID_OK << 16);
-irq_return:;
- /*
- * Release the I/O spinlock and restore the original flags
- * which will enable interrupts if and only if they were
- * enabled on entry.
- */
- spin_unlock_irqrestore (&io_request_lock, flags);
- }
+irq_return:
+ spin_unlock_irqrestore(&shost->host_flag, flags);
+out:;
+}
/****************************************************************
* Name: Pci2000_QueueCommand
*
static void TimerExpiry (unsigned long data)
{
PADAPTER2220I padapter = (PADAPTER2220I)data;
+ struct Scsi_Host *host = padapter->SCpnt->host;
POUR_DEVICE pdev = padapter->pdev;
UCHAR status = IDE_STATUS_BUSY;
UCHAR temp, temp1;
* Disable interrupts, if they aren't already disabled and acquire
* the I/O spinlock.
*/
- spin_lock_irqsave (&io_request_lock, flags);
+ spin_lock_irqsave (&host->host_lock, flags);
DEB (printk ("\nPCI2220I: Timeout expired "));
if ( padapter->failinprog )
* which will enable interrupts if and only if they were
* enabled on entry.
*/
- spin_unlock_irqrestore (&io_request_lock, flags);
+ spin_unlock_irqrestore (&host->host_lock, flags);
}
/****************************************************************
* Name: SetReconstruct :LOCAL
****************************************************************/
static void ReconTimerExpiry (unsigned long data)
{
- PADAPTER2220I padapter;
+ PADAPTER2220I padapter = (PADAPTER2220I)data;
+ struct Scsi_Host *host = padapter->SCpnt->host;
POUR_DEVICE pdev;
ULONG testsize = 0;
PIDENTIFY_DATA pid;
* Disable interrupts, if they aren't already disabled and acquire
* the I/O spinlock.
*/
- spin_lock_irqsave (&io_request_lock, flags);
+ spin_lock_irqsave(&host->host_lock, flags);
- padapter = (PADAPTER2220I)data;
if ( padapter->SCpnt )
goto reconTimerExpiry;
* which will enable interrupts if and only if they were
* enabled on entry.
*/
- spin_unlock_irqrestore (&io_request_lock, flags);
+ spin_unlock_irqrestore(&host->host_lock, flags);
}
/****************************************************************
* Name: Irq_Handler :LOCAL
ULONG zl;
unsigned long flags;
- /*
- * Disable interrupts, if they aren't already disabled and acquire
- * the I/O spinlock.
- */
- spin_lock_irqsave (&io_request_lock, flags);
-
// DEB (printk ("\npci2220i received interrupt\n"));
for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process
if ( !shost )
{
DEB (printk ("\npci2220i: not my interrupt"));
- goto irq_return;
+ goto out;
}
+ spin_lock_irqsave(&shost->host_lock, flags);
padapter = HOSTDATA(shost);
pdev = padapter->pdev;
SCpnt = padapter->SCpnt;
zl = DID_OK << 16;
OpDone (padapter, zl);
-irq_return:;
- /*
- * Release the I/O spinlock and restore the original flags
- * which will enable interrupts if and only if they were
- * enabled on entry.
- */
- spin_unlock_irqrestore (&io_request_lock, flags);
+irq_return:
+ spin_unlock_irqrestore(&shost->host_lock, flags);
+out:;
}
/****************************************************************
* Name: Pci2220i_QueueCommand
/* Hardware imposed limit. */
blk_queue_max_hw_segments(q, SHpnt->sg_tablesize);
-
- /*
- * When we remove scsi_malloc soonish, this can die too
- */
- blk_queue_max_phys_segments(q, PAGE_SIZE / sizeof(struct scatterlist));
-
blk_queue_max_sectors(q, SHpnt->max_sectors);
+ /* scsi_alloc_sgtable max */
+ blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
+
if (!SHpnt->use_clustering)
clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
}
rq->q = NULL;
rq->bio = rq->biotail = NULL;
rq->nr_phys_segments = 0;
- rq->elevator_sequence = 0;
/*
* We have the option of inserting the head or the tail of the queue.
* device, or a host that is unable to accept a particular command.
*/
spin_lock_irqsave(q->queue_lock, flags);
- __elv_add_request(q, rq, !at_head, 0);
+ _elv_add_request(q, rq, !at_head, 0);
q->request_fn(q);
spin_unlock_irqrestore(q->queue_lock, flags);
}
* the bad sector.
*/
SCpnt->request.special = (void *) SCpnt;
- __elv_add_request(q, &SCpnt->request, 0, 0);
+ _elv_add_request(q, &SCpnt->request, 0, 0);
}
/*
static int sg_open(struct inode * inode, struct file * filp)
{
- int dev = MINOR(inode->i_rdev);
+ int dev = minor(inode->i_rdev);
int flags = filp->f_flags;
Sg_device * sdp;
Sg_fd * sfp;
if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) {
return -ENXIO;
}
- SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", MINOR(sdp->i_rdev)));
+ SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", minor(sdp->i_rdev)));
sg_fasync(-1, filp, 0); /* remove filp from async notification list */
if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
if (! sdp->detached) {
if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n",
- MINOR(sdp->i_rdev), (int)count));
+ minor(sdp->i_rdev), (int)count));
if (ppos != &filp->f_pos)
; /* FIXME: Hmm. Seek to the right place, or fail? */
if ((k = verify_area(VERIFY_WRITE, buf, count)))
if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n",
- MINOR(sdp->i_rdev), (int)count));
+ minor(sdp->i_rdev), (int)count));
if (sdp->detached)
return -ENODEV;
if (! ((filp->f_flags & O_NONBLOCK) ||
if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n",
- MINOR(sdp->i_rdev), (int)cmd_in));
+ minor(sdp->i_rdev), (int)cmd_in));
read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
switch(cmd_in)
else if (count < SG_MAX_QUEUE)
res |= POLLOUT | POLLWRNORM;
SCSI_LOG_TIMEOUT(3, printk("sg_poll: dev=%d, res=0x%x\n",
- MINOR(sdp->i_rdev), (int)res));
+ minor(sdp->i_rdev), (int)res));
return res;
}
if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_fasync: dev=%d, mode=%d\n",
- MINOR(sdp->i_rdev), mode));
+ minor(sdp->i_rdev), mode));
retval = fasync_helper(fd, filp, mode, &sfp->async_qp);
return (retval < 0) ? retval : 0;
static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
{
Scsi_Request * SRpnt = SCpnt->sc_request;
- int dev = MINOR(SRpnt->sr_request.rq_dev);
+ int dev = minor(SRpnt->sr_request.rq_dev);
Sg_device * sdp = NULL;
Sg_fd * sfp;
Sg_request * srp = NULL;
sdp->sgdebug = 0;
sdp->detached = 0;
sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
- sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k);
+ sdp->i_rdev = mk_kdev(SCSI_GENERIC_MAJOR, k);
sdp->de = devfs_register (scsidp->de, "generic", DEVFS_FL_DEFAULT,
SCSI_GENERIC_MAJOR, k,
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
SRpnt->sr_bufflen = 0;
SRpnt->sr_buffer = NULL;
SRpnt->sr_underflow = 0;
- SRpnt->sr_request.rq_dev = MKDEV(0, 0); /* "sg" _disowns_ command blk */
+ SRpnt->sr_request.rq_dev = mk_kdev(0, 0); /* "sg" _disowns_ command blk */
}
static int sg_ms_to_jif(unsigned int msecs)
PRINT_PROC("device %d detached ??\n", j);
continue;
}
- dev = MINOR(sdp->i_rdev);
+ dev = minor(sdp->i_rdev);
if (sg_get_nth_sfp(sdp, 0)) {
PRINT_PROC(" >>> device=sg%d ", dev);
static void
do_sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
{
+ struct Scsi_Host *host = dev_id;
unsigned long flags;
- spin_lock_irqsave(&io_request_lock, flags);
- sim710_intr_handle(irq, dev_id, regs);
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_lock_irqsave(&host->host_lock, flags);
+ sim710_intr_handle(irq, host, regs);
+ spin_unlock_irqrestore(&host->host_lock, flags);
}
static void sr_release(struct cdrom_device_info *cdi)
{
- if (scsi_CDs[MINOR(cdi->dev)].device->sector_size > 2048)
- sr_set_blocklength(MINOR(cdi->dev), 2048);
- scsi_CDs[MINOR(cdi->dev)].device->access_count--;
- if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
+ if (scsi_CDs[minor(cdi->dev)].device->sector_size > 2048)
+ sr_set_blocklength(minor(cdi->dev), 2048);
+ scsi_CDs[minor(cdi->dev)].device->access_count--;
+ if (scsi_CDs[minor(cdi->dev)].device->host->hostt->module)
+ __MOD_DEC_USE_COUNT(scsi_CDs[minor(cdi->dev)].device->host->hostt->module);
if (sr_template.module)
__MOD_DEC_USE_COUNT(sr_template.module);
}
/* no changer support */
return -EINVAL;
}
- retval = scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,
+ retval = scsi_ioctl(scsi_CDs[minor(cdi->dev)].device,
SCSI_IOCTL_TEST_UNIT_READY, 0);
if (retval) {
* and we will figure it out later once the drive is
* available again. */
- scsi_CDs[MINOR(cdi->dev)].device->changed = 1;
+ scsi_CDs[minor(cdi->dev)].device->changed = 1;
return 1; /* This will force a flush, if called from
* check_disk_change */
};
- retval = scsi_CDs[MINOR(cdi->dev)].device->changed;
- scsi_CDs[MINOR(cdi->dev)].device->changed = 0;
+ retval = scsi_CDs[minor(cdi->dev)].device->changed;
+ scsi_CDs[minor(cdi->dev)].device->changed = 0;
/* If the disk changed, the capacity will now be different,
* so we force a re-read of this information */
if (retval) {
* be trying to use something that is too small if the disc
* has changed.
*/
- scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1;
+ scsi_CDs[minor(cdi->dev)].needs_sector_size = 1;
- scsi_CDs[MINOR(cdi->dev)].device->sector_size = 2048;
+ scsi_CDs[minor(cdi->dev)].device->sector_size = 2048;
}
return retval;
}
/*
* No such device
*/
- if (MINOR(dev) >= sr_template.dev_max || !scsi_CDs[MINOR(dev)].device)
+ if (minor(dev) >= sr_template.dev_max || !scsi_CDs[minor(dev)].device)
return NULL;
- return &scsi_CDs[MINOR(dev)].device->request_queue;
+ return &scsi_CDs[minor(dev)].device->request_queue;
}
static int sr_init_command(Scsi_Cmnd * SCpnt)
{
int dev, devm, block=0, this_count, s_size;
- devm = MINOR(SCpnt->request.rq_dev);
+ devm = minor(SCpnt->request.rq_dev);
dev = DEVICE_NR(SCpnt->request.rq_dev);
SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block));
{
check_disk_change(cdi->dev);
- if (MINOR(cdi->dev) >= sr_template.dev_max
- || !scsi_CDs[MINOR(cdi->dev)].device) {
+ if (minor(cdi->dev) >= sr_template.dev_max
+ || !scsi_CDs[minor(cdi->dev)].device) {
return -ENXIO; /* No such device */
}
/*
* If the device is in error recovery, wait until it is done.
* If the device is offline, then disallow any access to it.
*/
- if (!scsi_block_when_processing_errors(scsi_CDs[MINOR(cdi->dev)].device)) {
+ if (!scsi_block_when_processing_errors(scsi_CDs[minor(cdi->dev)].device)) {
return -ENXIO;
}
- scsi_CDs[MINOR(cdi->dev)].device->access_count++;
- if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
- __MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
+ scsi_CDs[minor(cdi->dev)].device->access_count++;
+ if (scsi_CDs[minor(cdi->dev)].device->host->hostt->module)
+ __MOD_INC_USE_COUNT(scsi_CDs[minor(cdi->dev)].device->host->hostt->module);
if (sr_template.module)
__MOD_INC_USE_COUNT(sr_template.module);
* this is the case, and try again.
*/
- if (scsi_CDs[MINOR(cdi->dev)].needs_sector_size)
- get_sectorsize(MINOR(cdi->dev));
+ if (scsi_CDs[minor(cdi->dev)].needs_sector_size)
+ get_sectorsize(minor(cdi->dev));
return 0;
}
*/
static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc)
{
- Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device;
+ Scsi_Device *device = scsi_CDs[minor(cdi->dev)].device;
/* set the LUN */
if (device->scsi_level <= SCSI_2)
cgc->cmd[1] |= device->lun << 5;
- cgc->stat = sr_do_ioctl(MINOR(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense);
+ cgc->stat = sr_do_ioctl(minor(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense);
return cgc->stat;
}
scsi_CDs[i].cdi.ops = &sr_dops;
scsi_CDs[i].cdi.handle = &scsi_CDs[i];
- scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR, i);
+ scsi_CDs[i].cdi.dev = mk_kdev(MAJOR_NR, i);
scsi_CDs[i].cdi.mask = 0;
scsi_CDs[i].cdi.capacity = 1;
/*
* the device.
* We should be kind to our buffer cache, however.
*/
- invalidate_device(MKDEV(MAJOR_NR, i), 0);
+ invalidate_device(mk_kdev(MAJOR_NR, i), 0);
/*
* Reset things back to a sane state so that one can
sr_cmd[6] = trk1_te.cdte_addr.msf.minute;
sr_cmd[7] = trk1_te.cdte_addr.msf.second;
sr_cmd[8] = trk1_te.cdte_addr.msf.frame;
- return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
+ return sr_do_ioctl(minor(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
}
/* We do our own retries because we want to know what the specific
u_char sr_cmd[10];
sr_cmd[0] = GPCMD_START_STOP_UNIT;
- sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
- ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
+ sr_cmd[1] = (scsi_CDs[minor(cdi->dev)].device->scsi_level <= SCSI_2) ?
+ ((scsi_CDs[minor(cdi->dev)].device->lun) << 5) : 0;
sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
- return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
+ return sr_do_ioctl(minor(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
}
int sr_lock_door(struct cdrom_device_info *cdi, int lock)
{
- return scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,
+ return scsi_ioctl(scsi_CDs[minor(cdi->dev)].device,
lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK,
0);
}
/* we have no changer support */
return -EINVAL;
}
- if (0 == test_unit_ready(MINOR(cdi->dev)))
+ if (0 == test_unit_ready(minor(cdi->dev)))
return CDS_DISC_OK;
return CDS_TRAY_OPEN;
if (!have_datatracks)
return CDS_AUDIO;
- if (scsi_CDs[MINOR(cdi->dev)].xa_flag)
+ if (scsi_CDs[minor(cdi->dev)].xa_flag)
return CDS_XA_2_1;
else
return CDS_DATA_1;
int sr_get_last_session(struct cdrom_device_info *cdi,
struct cdrom_multisession *ms_info)
{
- ms_info->addr.lba = scsi_CDs[MINOR(cdi->dev)].ms_offset;
- ms_info->xa_flag = scsi_CDs[MINOR(cdi->dev)].xa_flag ||
- (scsi_CDs[MINOR(cdi->dev)].ms_offset > 0);
+ ms_info->addr.lba = scsi_CDs[minor(cdi->dev)].ms_offset;
+ ms_info->xa_flag = scsi_CDs[minor(cdi->dev)].xa_flag ||
+ (scsi_CDs[minor(cdi->dev)].ms_offset > 0);
return 0;
}
int result;
sr_cmd[0] = GPCMD_READ_SUBCHANNEL;
- sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
- ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
+ sr_cmd[1] = (scsi_CDs[minor(cdi->dev)].device->scsi_level <= SCSI_2) ?
+ ((scsi_CDs[minor(cdi->dev)].device->lun) << 5) : 0;
sr_cmd[2] = 0x40; /* I do want the subchannel info */
sr_cmd[3] = 0x02; /* Give me medium catalog number info */
sr_cmd[4] = sr_cmd[5] = 0;
sr_cmd[8] = 24;
sr_cmd[9] = 0;
- result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ, NULL);
+ result = sr_do_ioctl(minor(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ, NULL);
memcpy(mcn->medium_catalog_number, buffer + 9, 13);
mcn->medium_catalog_number[13] = 0;
memset(sr_cmd, 0, MAX_COMMAND_SIZE);
sr_cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */
- sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
- ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
+ sr_cmd[1] = (scsi_CDs[minor(cdi->dev)].device->scsi_level <= SCSI_2) ?
+ ((scsi_CDs[minor(cdi->dev)].device->lun) << 5) : 0;
sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */
sr_cmd[3] = speed & 0xff; /* LSB */
- if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL))
+ if (sr_do_ioctl(minor(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL))
return -EIO;
return 0;
}
int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
{
u_char sr_cmd[10];
- int result, target = MINOR(cdi->dev);
+ int result, target = minor(cdi->dev);
unsigned char buffer[32];
memset(sr_cmd, 0, sizeof(sr_cmd));
{
int target;
- target = MINOR(cdi->dev);
+ target = minor(cdi->dev);
switch (cmd) {
case BLKGETSIZE:
unsigned char cmd[MAX_COMMAND_SIZE]; /* the scsi-command */
int rc, no_multi, minor;
- minor = MINOR(cdi->dev);
+ minor = minor(cdi->dev);
if (scsi_CDs[minor].cdi.mask & CDC_MULTI_SESSION)
return 0;
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
+ * 01 Jan 2002 Rev. 7.20 for linux 2.5.1
+ * + Use the dynamic DMA mapping API.
+ *
+ * 19 Dec 2001 Rev. 7.02 for linux 2.5.1
+ * + Use SCpnt->sc_data_direction if set.
+ * + Use sglist.page instead of sglist.address.
+ *
* 11 Dec 2001 Rev. 7.00 for linux 2.5.1
* + Use host->host_lock instead of io_request_lock.
*
*
* Multiple U14F and/or U34F host adapters are supported.
*
- * Copyright (C) 1994-2001 Dario Ballabio (ballabio_dario@emc.com)
+ * Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com)
*
* Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it
*
#include "u14-34f.h"
#include <linux/stat.h>
#include <linux/config.h>
+#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ctype.h>
#include <linux/spinlock.h>
unsigned char clink_id; /* identifies command in chain */
unsigned char use_sg; /* (if sg is set) 8 bytes per list */
unsigned char sense_len;
- unsigned char scsi_cdbs_len; /* 6, 10, or 12 */
- unsigned char scsi_cdbs[12]; /* SCSI commands */
+ unsigned char cdb_len; /* 6, 10, or 12 */
+ unsigned char cdb[12]; /* SCSI Command Descriptor Block */
unsigned char adapter_status; /* non-zero indicates HA error */
unsigned char target_status; /* non-zero indicates target error */
unsigned int sense_addr PACKED;
Scsi_Cmnd *SCpnt;
- unsigned int index; /* cp index */
+ unsigned int cpp_index; /* cp index */
struct sg_list *sglist;
};
unsigned int retries; /* Number of internal retries */
unsigned long last_retried_pid; /* Pid of last retried command */
unsigned char subversion; /* Bus type, either ISA or ESA */
+ struct pci_dev *pdev; /* Always NULL */
unsigned char heads;
unsigned char sectors;
#define HD(board) ((struct hostdata *) &sh[board]->hostdata)
#define BN(board) (HD(board)->board_name)
-#define SWAP_BYTE(x) ((unsigned long)( \
- (((unsigned long)(x) & 0x000000ffU) << 24) | \
- (((unsigned long)(x) & 0x0000ff00U) << 8) | \
- (((unsigned long)(x) & 0x00ff0000U) >> 8) | \
- (((unsigned long)(x) & 0xff000000U) >> 24)))
+/* Device is Little Endian */
+#define H2DEV(x) cpu_to_le32(x)
+#define DEV2H(x) le32_to_cpu(x)
-#if defined(__BIG_ENDIAN)
-#define H2DEV(x) SWAP_BYTE(x)
-#else
-#define H2DEV(x) (x)
-#endif
-
-#define DEV2H(x) H2DEV(x)
#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
-#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
static void do_interrupt_handler(int, void *, struct pt_regs *);
static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
cpp->xdir = DTD_IN;
cpp->data_address = V2DEV(HD(j)->board_id);
cpp->data_len = H2DEV(sizeof(HD(j)->board_id));
- cpp->scsi_cdbs_len = 6;
- cpp->scsi_cdbs[0] = HA_CMD_INQUIRY;
+ cpp->cdb_len = 6;
+ cpp->cdb[0] = HA_CMD_INQUIRY;
if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
printk("%s: board_inquiry, adapter busy.\n", BN(j));
unsigned long flags;
scsi_register_blocked_host(sh[j]);
sh[j]->unchecked_isa_dma = TRUE;
-
+
flags=claim_dma_lock();
disable_dma(dma_channel);
clear_dma_ff(dma_channel);
set_dma_mode(dma_channel, DMA_MODE_CASCADE);
enable_dma(dma_channel);
release_dma_lock(flags);
-
+
sh[j]->dma_channel = dma_channel;
sprintf(BN(j), "U14F%d", j);
bus_type = "ISA";
if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
if (j == 0) {
- printk("UltraStor 14F/34F: Copyright (C) 1994-2001 Dario Ballabio.\n");
+ printk("UltraStor 14F/34F: Copyright (C) 1994-2002 Dario Ballabio.\n");
printk("%s config options -> of:%c, lc:%c, mq:%d, et:%c.\n",
driver_name, YESNO(have_old_firmware), YESNO(linked_comm),
max_queue_depth, YESNO(ext_tran));
return 1;
}
-int u14_34f_detect(Scsi_Host_Template *tpnt)
-{
+int u14_34f_detect(Scsi_Host_Template *tpnt) {
unsigned int j = 0, k;
tpnt->proc_name = "u14-34f";
return j;
}
-static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
- unsigned int k, data_len = 0;
+static inline void map_dma(unsigned int i, unsigned int j) {
+ unsigned int data_len = 0;
+ unsigned int k, count, pci_dir;
struct scatterlist *sgpnt;
+ struct mscp *cpp;
+ Scsi_Cmnd *SCpnt;
+
+ cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+ pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+ if (SCpnt->sense_buffer)
+ cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer,
+ sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
+
+ cpp->sense_len = sizeof SCpnt->sense_buffer;
+
+ if (!SCpnt->use_sg) {
+
+ if (!SCpnt->request_bufflen)
+ cpp->data_address = V2DEV(SCpnt->request_buffer);
+
+ else if (SCpnt->request_buffer)
+ cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev,
+ SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir));
+
+ cpp->data_len = H2DEV(SCpnt->request_bufflen);
+ return;
+ }
sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+ count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir);
- for (k = 0; k < SCpnt->use_sg; k++) {
- cpp->sglist[k].address = V2DEV(sgpnt[k].address);
- cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length);
+ for (k = 0; k < count; k++) {
+ cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k]));
+ cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k]));
data_len += sgpnt[k].length;
}
+ cpp->sg = TRUE;
cpp->use_sg = SCpnt->use_sg;
cpp->data_address = V2DEV(cpp->sglist);
cpp->data_len = H2DEV(data_len);
}
-static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
- unsigned int i, j, k;
+static void unmap_dma(unsigned int i, unsigned int j) {
+ unsigned int pci_dir;
+ struct mscp *cpp;
+ Scsi_Cmnd *SCpnt;
+
+ cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+ pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+ if (DEV2H(cpp->sense_addr))
+ pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
+ DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
+
+ if (SCpnt->use_sg)
+ pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir);
+
+ else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
+ pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address),
+ DEV2H(cpp->data_len), pci_dir);
+
+}
+
+static void sync_dma(unsigned int i, unsigned int j) {
+ unsigned int pci_dir;
struct mscp *cpp;
+ Scsi_Cmnd *SCpnt;
+
+ cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+ pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction);
+
+ if (DEV2H(cpp->sense_addr))
+ pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
+ DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
+
+ if (SCpnt->use_sg)
+ pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer,
+ SCpnt->use_sg, pci_dir);
+
+ else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len))
+ pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address),
+ DEV2H(cpp->data_len), pci_dir);
+
+}
+
+static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) {
+ unsigned int k;
static const unsigned char data_out_cmds[] = {
0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
static const unsigned char data_none_cmds[] = {
0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e,
0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47,
- 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5
+ 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00
};
+ struct mscp *cpp;
+ Scsi_Cmnd *SCpnt;
+
+ cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+
+ if (SCpnt->sc_data_direction == SCSI_DATA_READ) {
+ cpp->xdir = DTD_IN;
+ return;
+ }
+ else if (SCpnt->sc_data_direction == SCSI_DATA_WRITE) {
+ cpp->xdir = DTD_OUT;
+ return;
+ }
+ else if (SCpnt->sc_data_direction == SCSI_DATA_NONE) {
+ cpp->xdir = DTD_NONE;
+ return;
+ }
+
+ if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN)
+ panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j));
+
+ cpp->xdir = DTD_IN;
+
+ for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
+ if (SCpnt->cmnd[0] == data_out_cmds[k]) {
+ cpp->xdir = DTD_OUT;
+ break;
+ }
+
+ if (cpp->xdir == DTD_IN)
+ for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
+ if (SCpnt->cmnd[0] == data_none_cmds[k]) {
+ cpp->xdir = DTD_NONE;
+ break;
+ }
+
+}
+
+static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+ unsigned int i, j, k;
+ struct mscp *cpp;
+
/* j is the board number */
j = ((struct hostdata *) SCpnt->host->hostdata)->board_number;
memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
SCpnt->scsi_done = done;
- cpp->index = i;
- SCpnt->host_scribble = (unsigned char *) &cpp->index;
+ cpp->cpp_index = i;
+ SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index;
if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
BN(j), i, SCpnt->channel, SCpnt->target,
SCpnt->lun, SCpnt->pid);
- cpp->xdir = DTD_IN;
-
- for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
- if (SCpnt->cmnd[0] == data_out_cmds[k]) {
- cpp->xdir = DTD_OUT;
- break;
- }
-
- if (cpp->xdir == DTD_IN)
- for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
- if (SCpnt->cmnd[0] == data_none_cmds[k]) {
- cpp->xdir = DTD_NONE;
- break;
- }
-
cpp->opcode = OP_SCSI;
cpp->channel = SCpnt->channel;
cpp->target = SCpnt->target;
cpp->lun = SCpnt->lun;
cpp->SCpnt = SCpnt;
- cpp->sense_addr = V2DEV(SCpnt->sense_buffer);
- cpp->sense_len = sizeof SCpnt->sense_buffer;
+ cpp->cdb_len = SCpnt->cmd_len;
+ memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
- if (SCpnt->use_sg) {
- cpp->sg = TRUE;
- build_sg_list(cpp, SCpnt);
- }
- else {
- cpp->data_address = V2DEV(SCpnt->request_buffer);
- cpp->data_len = H2DEV(SCpnt->request_bufflen);
- }
+ /* Use data transfer direction SCpnt->sc_data_direction */
+ scsi_to_dev_dir(i, j);
- cpp->scsi_cdbs_len = SCpnt->cmd_len;
- memcpy(cpp->scsi_cdbs, SCpnt->cmnd, cpp->scsi_cdbs_len);
+ /* Map DMA buffers and SG list */
+ map_dma(i, j);
if (linked_comm && SCpnt->device->queue_depth > 2
&& TLDEV(SCpnt->device->type)) {
}
if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+ unmap_dma(i, j);
SCpnt->host_scribble = NULL;
printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
if (SCarg->eh_state == SCSI_STATE_TIMEOUT) {
+ unmap_dma(i, j);
SCarg->host_scribble = NULL;
HD(j)->cp_stat[i] = FREE;
printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n",
}
if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+ unmap_dma(i, j);
SCarg->result = DID_ABORT << 16;
SCarg->host_scribble = NULL;
HD(j)->cp_stat[i] = FREE;
#endif
HD(j)->in_reset = TRUE;
-
+
spin_unlock_irq(&sh[j]->host_lock);
time = jiffies;
while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
spin_lock_irq(&sh[j]->host_lock);
-
+
printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
for (i = 0; i < sh[j]->can_queue; i++) {
if (HD(j)->cp_stat[i] == IN_RESET) {
SCpnt = HD(j)->cp[i].SCpnt;
+ unmap_dma(i, j);
SCpnt->result = DID_RESET << 16;
SCpnt->host_scribble = NULL;
else if (HD(j)->cp_stat[i] == ABORTING) {
SCpnt = HD(j)->cp[i].SCpnt;
+ unmap_dma(i, j);
SCpnt->result = DID_RESET << 16;
SCpnt->host_scribble = NULL;
return;
}
- spp = (struct mscp *)DEV2V(ret = inl(sh[j]->io_port + REG_ICM));
- cpp = spp;
+ ret = inl(sh[j]->io_port + REG_ICM);
/* Clear interrupt pending flag */
outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
-#if defined(DEBUG_GENERATE_ABORTS)
- if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return;
-#endif
-
/* Find the mailbox to be serviced on this board */
- i = cpp - HD(j)->cp;
+ for (i = 0; i < sh[j]->can_queue; i++)
+ if (V2DEV(&(HD(j)->cp[i])) == ret) break;
- if (cpp < HD(j)->cp || cpp >= HD(j)->cp + sh[j]->can_queue
- || i >= sh[j]->can_queue)
+ if (i >= sh[j]->can_queue)
panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j),
- (void *)ret, HD(j)->cp);
+ (void *)ret, (void *)V2DEV(HD(j)->cp));
+
+ cpp = &(HD(j)->cp[i]);
+ spp = cpp;
+
+#if defined(DEBUG_GENERATE_ABORTS)
+ if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return;
+#endif
if (HD(j)->cp_stat[i] == IGNORE) {
HD(j)->cp_stat[i] = FREE;
panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
+ sync_dma(i, j);
+
if (linked_comm && SCpnt->device->queue_depth > 2
&& TLDEV(SCpnt->device->type))
flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
reg, HD(j)->iocount);
+ unmap_dma(i, j);
+
/* Set the command state to inactive */
SCpnt->host_scribble = NULL;
if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
driver_name);
- if( sh[j]->unchecked_isa_dma ) {
- scsi_deregister_blocked_host(sh[j]);
- }
+ if(sh[j]->unchecked_isa_dma) scsi_deregister_blocked_host(sh[j]);
for (i = 0; i < sh[j]->can_queue; i++)
if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
int u14_34f_reset(Scsi_Cmnd *);
int u14_34f_biosparam(Disk *, kdev_t, int *);
-#define U14_34F_VERSION "7.00.00"
+#define U14_34F_VERSION "7.20.00"
#define ULTRASTOR_14_34F { \
name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
static int cs4281_open_mixdev(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct cs4281_state *s=NULL;
struct list_head *entry;
static int cs4281_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct cs4281_state *s=NULL;
struct list_head *entry;
static int cs4281_midi_open(struct inode *inode, struct file *file)
{
unsigned long flags, temp1;
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct cs4281_state *s=NULL;
struct list_head *entry;
list_for_each(entry, &cs4281_devs)
static int cs_midi_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct cs_card *card=NULL;
unsigned long flags;
struct list_head *entry;
struct cs_state *state = NULL;
struct dmabuf *dmabuf = NULL;
struct list_head *entry;
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
int ret=0;
unsigned int tmp;
static int cs_open_mixdev(struct inode *inode, struct file *file)
{
int i=0;
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct cs_card *card=NULL;
struct list_head *entry;
unsigned int tmp;
static int cs_release_mixdev(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct cs_card *card=NULL;
struct list_head *entry;
int i;
static int es1370_open_mixdev(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct list_head *list;
struct es1370_state *s;
static int es1370_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
struct list_head *list;
static int es1370_open_dac(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
struct list_head *list;
static int es1370_midi_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
struct list_head *list;
static int solo1_open_mixdev(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct solo1_state *s = NULL;
struct pci_dev *pci_dev;
static int solo1_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
struct solo1_state *s = NULL;
struct pci_dev *pci_dev;
static int solo1_midi_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
struct solo1_state *s = NULL;
static int solo1_dmfm_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
struct solo1_state *s = NULL;
struct pci_dev *pci_dev;
static int i810_open_mixdev(struct inode *inode, struct file *file)
{
int i;
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct i810_card *card = devs;
for (card = devs; card != NULL; card = card->next)
/* --------------------------------------------------------------------- */
static int ess_open_mixdev(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct ess_card *card = NULL;
struct pci_dev *pdev;
struct pci_driver *drvr;
static int
ess_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct ess_state *s = NULL;
unsigned char fmtm = ~0, fmts = 0;
struct pci_dev *pdev;
static int m3_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct m3_card *c;
struct m3_state *s = NULL;
int i;
/* OSS /dev/mixer file operation methods */
static int m3_open_mixdev(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct m3_card *card = devs;
for (card = devs; card != NULL; card = card->next) {
static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
- int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+ int dev = minor(file->f_dentry->d_inode->i_rdev);
int ret = -EINVAL;
/*
static ssize_t sound_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
- int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+ int dev = minor(file->f_dentry->d_inode->i_rdev);
int ret = -EINVAL;
lock_kernel();
static int sound_open(struct inode *inode, struct file *file)
{
- int dev = MINOR(inode->i_rdev);
+ int dev = minor(inode->i_rdev);
int retval;
DEB(printk("sound_open(dev=%d)\n", dev));
static int sound_release(struct inode *inode, struct file *file)
{
- int dev = MINOR(inode->i_rdev);
+ int dev = minor(inode->i_rdev);
lock_kernel();
DEB(printk("sound_release(dev=%d)\n", dev));
unsigned int cmd, unsigned long arg)
{
int err, len = 0, dtype;
- int dev = MINOR(inode->i_rdev);
+ int dev = minor(inode->i_rdev);
if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) {
/*
static unsigned int sound_poll(struct file *file, poll_table * wait)
{
struct inode *inode = file->f_dentry->d_inode;
- int dev = MINOR(inode->i_rdev);
+ int dev = minor(inode->i_rdev);
DEB(printk("sound_poll(dev=%d)\n", dev));
switch (dev & 0x0f) {
int dev_class;
unsigned long size;
struct dma_buffparms *dmap = NULL;
- int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+ int dev = minor(file->f_dentry->d_inode->i_rdev);
dev_class = dev & 0x0f;
dev >>= 4;
bool ' Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT
fi
-comment 'USB Controllers'
+comment 'USB Host Controller Drivers'
+source drivers/usb/hcd/Config.in
if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
fi
dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
dep_tristate ' USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
dep_tristate ' USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
+ dep_tristate ' USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV
+ dep_tristate ' USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
fi
# Objects that export symbols.
-export-objs := usb.o
+export-objs := usb.o hcd.o ov511.o pwc-uncompress.o
# Multipart objects.
-list-multi := usbcore.o hid.o
-usbcore-objs := usb.o usb-debug.o hub.o
+list-multi := usbcore.o hid.o pwc.o
+usbcore-objs := usb.o usb-debug.o hub.o hcd.o
hid-objs := hid-core.o hid-input.o
-
-ifneq ($(CONFIG_USB_PWC),n)
- export-objs += pwc-uncompress.o
- list-multi += pwc.o
-endif
-
pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o
obj-$(CONFIG_USB_MDC800) += mdc800.o
obj-$(CONFIG_USB_USS720) += uss720.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
+obj-$(CONFIG_USB_VICAM) += vicam.o
obj-$(CONFIG_USB_OV511) += ov511.o
obj-$(CONFIG_USB_SE401) += se401.o
+obj-$(CONFIG_USB_STV680) += stv680.o
obj-$(CONFIG_USB_PEGASUS) += pegasus.o
obj-$(CONFIG_USB_CATC) += catc.o
obj-$(CONFIG_USB_KAWETH) += kaweth.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
# Object files in subdirectories
+mod-subdirs := serial hcd
+subdir-$(CONFIG_USB_EHCI_HCD) += hcd
subdir-$(CONFIG_USB_SERIAL) += serial
subdir-$(CONFIG_USB_STORAGE) += storage
+ifeq ($(CONFIG_USB_EHCI_HCD),y)
+ obj-y += hcd/ehci-hcd.o
+endif
+
ifeq ($(CONFIG_USB_SERIAL),y)
obj-y += serial/usb-serial.o
endif
static int acm_tty_open(struct tty_struct *tty, struct file *filp)
{
- struct acm *acm = acm_table[MINOR(tty->device)];
+ struct acm *acm = acm_table[minor(tty->device)];
if (!acm || !acm->dev) return -EINVAL;
static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct list_head *devs, *mdevs;
struct usb_mixerdev *ms;
struct usb_audio_state *s;
static int usb_audio_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
struct list_head *devs, *adevs;
struct usb_audiodev *as;
tty->driver_data = NULL;
/* get the bluetooth object associated with this tty pointer */
- bluetooth = get_bluetooth_by_minor (MINOR(tty->device));
+ bluetooth = get_bluetooth_by_minor (minor(tty->device));
if (bluetooth_paranoia_check (bluetooth, __FUNCTION__)) {
return -ENODEV;
static int dabusb_open (struct inode *inode, struct file *file)
{
- int devnum = MINOR (inode->i_rdev);
+ int devnum = minor (inode->i_rdev);
pdabusb_t s;
if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
int value = 0;
down (&state_table_mutex);
- subminor = MINOR (inode->i_rdev) - USB_CAMERA_MINOR_BASE;
+ subminor = minor (inode->i_rdev) - USB_CAMERA_MINOR_BASE;
if (subminor < 0 || subminor >= MAX_CAMERAS
|| !(camera = minor_data [subminor])) {
up (&state_table_mutex);
#
# USB Host Controller Drivers
#
-dep_tristate ' EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-# dep_tristate ' OHCI HCD support (EXPERIMENTAL)' CONFIG_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-# dep_tristate ' UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+dep_tristate ' EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+# dep_tristate ' OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+# dep_tristate ' UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
static int hiddev_open(struct inode * inode, struct file * file) {
struct hiddev_list *list;
- int i = MINOR(inode->i_rdev) - HIDDEV_MINOR_BASE;
+ int i = minor(inode->i_rdev) - HIDDEV_MINOR_BASE;
if (i >= HIDDEV_MINORS || !hiddev_table[i])
return -ENODEV;
static int usblp_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev) - USBLP_MINOR_BASE;
+ int minor = minor(inode->i_rdev) - USBLP_MINOR_BASE;
struct usblp *usblp;
int retval;
struct scn_usb_data *scn;
struct usb_device *dev;
- kdev_t scn_minor;
+ int scn_minor;
int err=0;
{
struct scn_usb_data *scn;
- kdev_t scn_minor;
+ int scn_minor;
scn_minor = USB_SCN_MINOR (inode);
ssize_t bytes_written = 0; /* Overall count of bytes written */
ssize_t ret = 0;
- kdev_t scn_minor;
+ int scn_minor;
int this_write; /* Number of bytes to write */
int partial; /* Number of bytes successfully written */
ssize_t bytes_read; /* Overall count of bytes_read */
ssize_t ret;
- kdev_t scn_minor;
-
+ int scn_minor;
int partial; /* Number of bytes successfully read */
int this_read; /* Max number of bytes to read */
int result;
{
struct usb_device *dev;
- kdev_t scn_minor;
+ int scn_minor;
scn_minor = USB_SCN_MINOR(inode);
int ep_cnt;
int ix;
-
- kdev_t scn_minor;
+ int scn_minor;
char valid_device = 0;
char have_bulk_in, have_bulk_out, have_intr;
#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
#define IS_EP_INTR(ep) ((ep).bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0)
-#define USB_SCN_MINOR(X) MINOR((X)->i_rdev) - SCN_BASE_MNR
+#define USB_SCN_MINOR(X) minor((X)->i_rdev) - SCN_BASE_MNR
#ifdef DEBUG
#define SCN_DEBUG(X) X
devfs_handle_t devfs; /* devfs device */
struct urb scn_irq;
unsigned int ifnum; /* Interface number of the USB device */
- kdev_t scn_minor; /* Scanner minor - used in disconnect() */
+ int scn_minor; /* Scanner minor - used in disconnect() */
unsigned char button; /* Front panel buffer */
char isopen; /* Not zero if the device is open */
char present; /* Not zero if device is present */
dep_tristate ' USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
+dep_tristate ' USB Compaq iPAQ Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
dep_tristate ' USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_mbool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W $CONFIG_USB_SERIAL_KEYSPAN
dep_mbool ' USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W $CONFIG_USB_SERIAL_KEYSPAN
dep_tristate ' USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate ' USB KL5KUSB105 (Palmconnect) Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KLSI $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB Prolific 2303 Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB Xircom / Entregra Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
obj-$(CONFIG_USB_SERIAL) += usbserial.o
obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
+obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o
obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o
-
+obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o
+
# Objects that export symbols.
export-objs := usbserial.o
static LIST_HEAD(usb_serial_driver_list);
-static struct usb_serial *get_serial_by_minor (int minor)
+static struct usb_serial *get_serial_by_minor (unsigned int minor)
{
return serial_table[minor];
}
-static struct usb_serial *get_free_serial (int num_ports, int *minor)
+static struct usb_serial *get_free_serial (int num_ports, unsigned int *minor)
{
struct usb_serial *serial = NULL;
- int i, j;
+ unsigned int i, j;
int good_spot;
dbg(__FUNCTION__ " %d", num_ports);
{
struct usb_serial *serial;
struct usb_serial_port *port;
- int portNumber;
+ unsigned int portNumber;
dbg(__FUNCTION__);
tty->driver_data = NULL;
/* get the serial object associated with this tty pointer */
- serial = get_serial_by_minor (MINOR(tty->device));
+ serial = get_serial_by_minor (minor(tty->device));
if (serial_paranoia_check (serial, __FUNCTION__)) {
return -ENODEV;
}
/* set up our port structure making the tty driver remember our port object, and us it */
- portNumber = MINOR(tty->device) - serial->minor;
+ portNumber = minor(tty->device) - serial->minor;
port = &serial->port[portNumber];
tty->driver_data = port;
port->tty = tty;
--- /dev/null
+/*
+ * STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net)
+ *
+ * Thanks to STMicroelectronics for information on the usb commands, and
+ * to Steve Miller at STM for his help and encouragement while I was
+ * writing this driver.
+ *
+ * This driver is based heavily on the
+ * Endpoints (formerly known as AOX) se401 USB Camera Driver
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
+ *
+ * Still somewhat based on the Linux ov511 driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ * ver 0.1 October, 2001. Initial attempt.
+ *
+ * ver 0.2 November, 2001. Fixed asbility to resize, added brightness
+ * function, made more stable (?)
+ *
+ * ver 0.21 Nov, 2001. Added gamma correction and white balance,
+ * due to Alexander Schwartz. Still trying to
+ * improve stablility. Moved stuff into stv680.h
+ *
+ * ver 0.22 Nov, 2001. Added sharpen function (by Michael Sweet,
+ * mike@easysw.com) from GIMP, also used in pencam.
+ * Simple, fast, good integer math routine.
+ *
+ * ver 0.23 Dec, 2001 (gkh)
+ * Took out sharpen function, ran code through
+ * Lindent, and did other minor tweaks to get
+ * things to work properly with 2.5.1
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/pagemap.h>
+#include <linux/wrapper.h>
+#include <linux/smp_lock.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+
+#include "stv680.h"
+
+static int video_nr = -1;
+static int swapRGB = 0;
+
+static unsigned int debug = 0;
+
+#define PDEBUG(level, fmt, args...) \
+ do { \
+ if (debug >= level) \
+ info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args); \
+ } while (0)
+
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.23"
+#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
+#define DRIVER_DESC "STV0680 USB Camera Driver"
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE ("GPL");
+MODULE_PARM (debug, "i");
+MODULE_PARM_DESC (debug, "Debug enabled or not");
+MODULE_PARM (swapRGB, "i");
+MODULE_PARM_DESC (swapRGB, "Swap red and blue, e.g., for xawtv");
+MODULE_PARM (video_nr, "i");
+EXPORT_NO_SYMBOLS;
+
+/********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet -jerdfelt
+ *
+ * So I copied it again for the ov511 driver -claudio
+ *
+ * Same for the se401 driver -Jeroen
+ *
+ * And the STV0680 driver - Kevin
+ ********************************************************************/
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva (pgd_t * pgd, unsigned long adr)
+{
+ unsigned long ret = 0UL;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ if (!pgd_none (*pgd)) {
+ pmd = pmd_offset (pgd, adr);
+ if (!pmd_none (*pmd)) {
+ ptep = pte_offset (pmd, adr);
+ pte = *ptep;
+ if (pte_present (pte)) {
+ ret = (unsigned long) page_address (pte_page (pte));
+ ret |= (adr & (PAGE_SIZE - 1));
+ }
+ }
+ }
+ return ret;
+}
+
+/* Here we want the physical address of the memory. This is used when
+ * initializing the contents of the area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa (unsigned long adr)
+{
+ unsigned long va, kva, ret;
+
+ va = VMALLOC_VMADDR (adr);
+ kva = uvirt_to_kva (pgd_offset_k (va), va);
+ ret = __pa (kva);
+ return ret;
+}
+
+static void *rvmalloc (unsigned long size)
+{
+ void *mem;
+ unsigned long adr, page;
+
+ /* Round it off to PAGE_SIZE */
+ size += (PAGE_SIZE - 1);
+ size &= ~(PAGE_SIZE - 1);
+
+ mem = vmalloc_32 (size);
+ if (!mem)
+ return NULL;
+
+ memset (mem, 0, size); /* Clear the ram out, no junk to the user */
+ adr = (unsigned long) mem;
+ while (size > 0) {
+ page = kvirt_to_pa (adr);
+ mem_map_reserve (virt_to_page (__va (page)));
+ adr += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+ return mem;
+}
+
+static void rvfree (void *mem, unsigned long size)
+{
+ unsigned long adr, page;
+
+ if (!mem)
+ return;
+
+ size += (PAGE_SIZE - 1);
+ size &= ~(PAGE_SIZE - 1);
+
+ adr = (unsigned long) mem;
+ while (size > 0) {
+ page = kvirt_to_pa (adr);
+ mem_map_unreserve (virt_to_page (__va (page)));
+ adr += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+ vfree (mem);
+}
+
+
+/*********************************************************************
+ * pencam read/write functions
+ ********************************************************************/
+
+static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size)
+{
+ int ret = -1;
+
+ switch (set) {
+ case 0: /* 0xc1 */
+ ret = usb_control_msg (stv680->udev,
+ usb_rcvctrlpipe (stv680->udev, 0),
+ req,
+ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
+ value, 0, buffer, size, PENCAM_TIMEOUT);
+ break;
+
+ case 1: /* 0x41 */
+ ret = usb_control_msg (stv680->udev,
+ usb_sndctrlpipe (stv680->udev, 0),
+ req,
+ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
+ value, 0, buffer, size, PENCAM_TIMEOUT);
+ break;
+
+ case 2: /* 0x80 */
+ ret = usb_control_msg (stv680->udev,
+ usb_rcvctrlpipe (stv680->udev, 0),
+ req,
+ (USB_DIR_IN | USB_RECIP_DEVICE),
+ value, 0, buffer, size, PENCAM_TIMEOUT);
+ break;
+
+ case 3: /* 0x40 */
+ ret = usb_control_msg (stv680->udev,
+ usb_sndctrlpipe (stv680->udev, 0),
+ req,
+ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
+ value, 0, buffer, size, PENCAM_TIMEOUT);
+ break;
+
+ }
+ if ((ret < 0) && (req != 0x0a)) {
+ PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret);
+ }
+ return ret;
+}
+
+static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate)
+{
+
+ if (usb_set_configuration (dev->udev, configuration) < 0) {
+ PDEBUG (1, "STV(e): FAILED to set configuration %i", configuration);
+ return -1;
+ }
+ if (usb_set_interface (dev->udev, interface, alternate) < 0) {
+ PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate);
+ return -1;
+ }
+ return 0;
+}
+
+static int stv_stop_video (struct usb_stv *dev)
+{
+ int i;
+ unsigned char *buf;
+
+ buf = kmalloc (40, GFP_KERNEL);
+ if (buf == NULL) {
+ PDEBUG (0, "STV(e): Out of (small buf) memory");
+ return -1;
+ }
+
+ /* this is a high priority command; it stops all lower order commands */
+ if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) {
+ i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02); /* Get Last Error; 2 = busy */
+ PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buf[0], buf[1]);
+ } else {
+ PDEBUG (1, "STV(i): Camera reset to idle mode.");
+ }
+
+ if ((i = stv_set_config (dev, 1, 0, 0)) < 0)
+ PDEBUG (1, "STV(e): Reset config during exit failed");
+
+ /* get current mode */
+ buf[0] = 0xf0;
+ if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08) /* get mode */
+ PDEBUG (0, "STV(e): Stop_video: problem setting original mode");
+ if (dev->origMode != buf[0]) {
+ memset (buf, 0, 8);
+ buf[0] = (unsigned char) dev->origMode;
+ if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) {
+ PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed");
+ i = -1;
+ }
+ buf[0] = 0xf0;
+ i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08);
+ if ((i != 0x08) || (buf[0] != dev->origMode)) {
+ PDEBUG (0, "STV(e): camera NOT set to original resolution.");
+ i = -1;
+ } else
+ PDEBUG (0, "STV(i): Camera set to original resolution");
+ }
+ /* origMode */
+ kfree (buf);
+ return i;
+}
+
+static int stv_set_video_mode (struct usb_stv *dev)
+{
+ int i, stop_video = 1;
+ unsigned char *buf;
+
+ buf = kmalloc (40, GFP_KERNEL);
+ if (buf == NULL) {
+ PDEBUG (0, "STV(e): Out of (small buf) memory");
+ return -1;
+ }
+
+ if ((i = stv_set_config (dev, 1, 0, 0)) < 0) {
+ kfree (buf);
+ return i;
+ }
+
+ i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12);
+ if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) {
+ PDEBUG (1, "STV(e): Could not get descriptor 0100.");
+ goto error;
+ }
+
+ /* set alternate interface 1 */
+ if ((i = stv_set_config (dev, 1, 0, 1)) < 0)
+ goto error;
+
+ if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10)
+ goto error;
+ PDEBUG (1, "STV(i): Setting video mode.");
+ /* Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240) */
+ if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) {
+ stop_video = 0;
+ goto error;
+ }
+ goto exit;
+
+error:
+ kfree (buf);
+ if (stop_video == 1)
+ stv_stop_video (dev);
+ return -1;
+
+exit:
+ kfree (buf);
+ return 0;
+}
+
+static int stv_init (struct usb_stv *stv680)
+{
+ int i = 0;
+ unsigned char *buffer;
+ unsigned long int bufsize;
+
+ buffer = kmalloc (40, GFP_KERNEL);
+ if (buffer == NULL) {
+ PDEBUG (0, "STV(e): Out of (small buf) memory");
+ return -1;
+ }
+ memset (buffer, 0, 40);
+ udelay (100);
+
+ /* set config 1, interface 0, alternate 0 */
+ if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) {
+ kfree (buffer);
+ PDEBUG (0, "STV(e): set config 1,0,0 failed");
+ return -1;
+ }
+ /* ping camera to be sure STV0680 is present */
+ if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02)
+ goto error;
+ if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) {
+ PDEBUG (1, "STV(e): camera ping failed!!");
+ goto error;
+ }
+
+ /* get camera descriptor */
+ if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09)
+ goto error;
+ i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22);
+ if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) {
+ PDEBUG (1, "STV(e): Could not get descriptor 0200.");
+ goto error;
+ }
+ if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02)
+ goto error;
+ if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24)
+ goto error;
+ if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
+ goto error;
+
+ stv680->SupportedModes = buffer[7];
+ i = stv680->SupportedModes;
+ stv680->CIF = 0;
+ stv680->VGA = 0;
+ stv680->QVGA = 0;
+ if (i & 1)
+ stv680->CIF = 1;
+ if (i & 2)
+ stv680->VGA = 1;
+ if (i & 8)
+ stv680->QVGA = 1;
+ if (stv680->SupportedModes == 0) {
+ PDEBUG (0, "STV(e): There are NO supported STV680 modes!!");
+ i = -1;
+ goto error;
+ } else {
+ if (stv680->CIF)
+ PDEBUG (0, "STV(i): CIF is supported");
+ if (stv680->QVGA)
+ PDEBUG (0, "STV(i): QVGA is supported");
+ }
+ /* FW rev, ASIC rev, sensor ID */
+ PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]);
+ PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]);
+ PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4));
+
+ /* set alternate interface 1 */
+ if ((i = stv_set_config (stv680, 1, 0, 1)) < 0)
+ goto error;
+
+ if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
+ goto error;
+ if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08)
+ goto error;
+ i = buffer[3];
+ PDEBUG (0, "STV(i): Camera has %i pictures.", i);
+
+ /* get current mode */
+ if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08)
+ goto error;
+ stv680->origMode = buffer[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */
+
+ /* This will attemp CIF mode, if supported. If not, set to QVGA */
+ memset (buffer, 0, 8);
+ if (stv680->CIF)
+ buffer[0] = 0x00;
+ else if (stv680->QVGA)
+ buffer[0] = 0x03;
+ if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) {
+ PDEBUG (0, "STV(i): Set_Camera_Mode failed");
+ i = -1;
+ goto error;
+ }
+ buffer[0] = 0xf0;
+ stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08);
+ if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) {
+ PDEBUG (0, "STV(e): Error setting camera video mode!");
+ i = -1;
+ goto error;
+ } else {
+ if (buffer[0] == 0) {
+ stv680->VideoMode = 0x0000;
+ PDEBUG (0, "STV(i): Video Mode set to CIF");
+ }
+ if (buffer[0] == 0x03) {
+ stv680->VideoMode = 0x0300;
+ PDEBUG (0, "STV(i): Video Mode set to QVGA");
+ }
+ }
+ if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10)
+ goto error;
+ bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);
+ stv680->cwidth = (buffer[4] << 8) | (buffer[5]); /* ->camera = 322, 356, 644 */
+ stv680->cheight = (buffer[6] << 8) | (buffer[7]); /* ->camera = 242, 292, 484 */
+ stv680->origGain = buffer[12];
+
+ goto exit;
+
+error:
+ i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02); /* Get Last Error */
+ PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buffer[0], buffer[1]);
+ kfree (buffer);
+ return -1;
+
+exit:
+ kfree (buffer);
+
+ /* video = 320x240, 352x288 */
+ if (stv680->CIF == 1) {
+ stv680->maxwidth = 352;
+ stv680->maxheight = 288;
+ stv680->vwidth = 352;
+ stv680->vheight = 288;
+ }
+ if (stv680->QVGA == 1) {
+ stv680->maxwidth = 320;
+ stv680->maxheight = 240;
+ stv680->vwidth = 320;
+ stv680->vheight = 240;
+ }
+
+ stv680->rawbufsize = bufsize; /* must be ./. by 8 */
+ stv680->maxframesize = bufsize * 3; /* RGB size */
+ PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight);
+ PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize);
+
+ /* some default values */
+ stv680->bulk_in_endpointAddr = 0x82;
+ stv680->dropped = 0;
+ stv680->error = 0;
+ stv680->framecount = 0;
+ stv680->readcount = 0;
+ stv680->streaming = 0;
+ /* bright, white, colour, hue, contrast are set by software, not in stv0680 */
+ stv680->brightness = 32767;
+ stv680->chgbright = 0;
+ stv680->whiteness = 0; /* only for greyscale */
+ stv680->colour = 32767;
+ stv680->contrast = 32767;
+ stv680->hue = 32767;
+ stv680->palette = STV_VIDEO_PALETTE;
+ stv680->depth = 24; /* rgb24 bits */
+ swapRGB = 0;
+ PDEBUG (1, "STV(i): swapRGB is OFF");
+
+ if (stv_set_video_mode (stv680) < 0) {
+ PDEBUG (0, "STV(e): Could not set video mode in stv_init");
+ return -1;
+ }
+
+ return 0;
+}
+
+/***************** last of pencam routines *******************/
+
+/********************************************************************
+ * /proc interface
+ *******************************************************************/
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+
+static struct proc_dir_entry *stv680_proc_entry = NULL;
+extern struct proc_dir_entry *video_proc_entry;
+
+#define YES_NO(x) ((x) ? "yes" : "no")
+
+static int stv680_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ char *out = page;
+ int len;
+ struct usb_stv *stv680 = data;
+
+ /* Stay under PAGE_SIZE or else bla bla bla.... */
+
+ out += sprintf (out, "driver_version : %s\n", DRIVER_VERSION);
+ out += sprintf (out, "model : %s\n", stv680->camera_name);
+ out += sprintf (out, "in use : %s\n", YES_NO (stv680->user));
+ out += sprintf (out, "streaming : %s\n", YES_NO (stv680->streaming));
+ out += sprintf (out, "num_frames : %d\n", STV680_NUMFRAMES);
+
+ out += sprintf (out, "Current size : %ix%i\n", stv680->vwidth, stv680->vheight);
+ out += sprintf (out, "swapRGB : %s\n", YES_NO (swapRGB));
+ out += sprintf (out, "Palette : %i", stv680->palette);
+
+ out += sprintf (out, "\n");
+
+ out += sprintf (out, "Frames total : %d\n", stv680->readcount);
+ out += sprintf (out, "Frames read : %d\n", stv680->framecount);
+ out += sprintf (out, "Packets dropped : %d\n", stv680->dropped);
+ out += sprintf (out, "Decoding Errors : %d\n", stv680->error);
+
+ len = out - page;
+ len -= off;
+ if (len < count) {
+ *eof = 1;
+ if (len <= 0)
+ return 0;
+ } else
+ len = count;
+
+ *start = page + off;
+ return len;
+}
+
+static int create_proc_stv680_cam (struct usb_stv *stv680)
+{
+ char name[9];
+ struct proc_dir_entry *ent;
+
+ if (!stv680_proc_entry || !stv680)
+ return -1;
+
+ sprintf (name, "video%d", stv680->vdev.minor);
+
+ ent = create_proc_entry (name, S_IFREG | S_IRUGO | S_IWUSR, stv680_proc_entry);
+ if (!ent)
+ return -1;
+
+ ent->data = stv680;
+ ent->read_proc = stv680_read_proc;
+ stv680->proc_entry = ent;
+ return 0;
+}
+
+static void destroy_proc_stv680_cam (struct usb_stv *stv680)
+{
+ /* One to much, just to be sure :) */
+ char name[9];
+
+ if (!stv680 || !stv680->proc_entry)
+ return;
+
+ sprintf (name, "video%d", stv680->vdev.minor);
+ remove_proc_entry (name, stv680_proc_entry);
+ stv680->proc_entry = NULL;
+}
+
+static int proc_stv680_create (void)
+{
+ if (video_proc_entry == NULL) {
+ PDEBUG (0, "STV(e): /proc/video/ doesn't exist!");
+ return -1;
+ }
+ stv680_proc_entry = create_proc_entry ("stv680", S_IFDIR, video_proc_entry);
+
+ if (stv680_proc_entry) {
+ stv680_proc_entry->owner = THIS_MODULE;
+ } else {
+ PDEBUG (0, "STV(e): Unable to initialize /proc/video/stv680");
+ return -1;
+ }
+ return 0;
+}
+
+static void proc_stv680_destroy (void)
+{
+ if (stv680_proc_entry == NULL)
+ return;
+
+ remove_proc_entry ("stv", video_proc_entry);
+}
+#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
+
+/********************************************************************
+ * Camera control
+ *******************************************************************/
+
+static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p)
+{
+ /* This sets values for v4l interface. max/min = 65535/0 */
+
+ p->brightness = stv680->brightness;
+ p->whiteness = stv680->whiteness; /* greyscale */
+ p->colour = stv680->colour;
+ p->contrast = stv680->contrast;
+ p->hue = stv680->hue;
+ p->palette = stv680->palette;
+ p->depth = stv680->depth;
+ return 0;
+}
+
+static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
+{
+ /* See above stv680_get_pict */
+
+ if (p->palette != STV_VIDEO_PALETTE) {
+ PDEBUG (2, "STV(e): Palette set error in _set_pic");
+ return 1;
+ }
+
+ if (stv680->brightness != p->brightness) {
+ stv680->chgbright = 1;
+ stv680->brightness = p->brightness;
+ } else {
+ stv680->chgbright = 0;
+ }
+
+ stv680->whiteness = p->whiteness; /* greyscale */
+ stv680->colour = p->colour;
+ stv680->contrast = p->contrast;
+ stv680->hue = p->hue;
+ stv680->palette = p->palette;
+ stv680->depth = p->depth;
+
+ return 0;
+}
+
+static void stv680_video_irq (struct urb *urb)
+{
+ struct usb_stv *stv680 = urb->context;
+ int length = urb->actual_length;
+
+ if (length < stv680->rawbufsize)
+ PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length);
+
+ /* ohoh... */
+ if (!stv680->streaming)
+ return;
+
+ if (!stv680->udev) {
+ PDEBUG (0, "STV(e): device vapourished in video_irq");
+ return;
+ }
+
+ /* 0 sized packets happen if we are to fast, but sometimes the camera
+ keeps sending them forever...
+ */
+ if (length && !urb->status) {
+ stv680->nullpackets = 0;
+ switch (stv680->scratch[stv680->scratch_next].state) {
+ case BUFFER_READY:
+ case BUFFER_BUSY:
+ stv680->dropped++;
+ break;
+
+ case BUFFER_UNUSED:
+ memcpy (stv680->scratch[stv680->scratch_next].data,
+ (unsigned char *) urb->transfer_buffer, length);
+ stv680->scratch[stv680->scratch_next].state = BUFFER_READY;
+ stv680->scratch[stv680->scratch_next].length = length;
+ if (waitqueue_active (&stv680->wq)) {
+ wake_up_interruptible (&stv680->wq);
+ }
+ stv680->scratch_overflow = 0;
+ stv680->scratch_next++;
+ if (stv680->scratch_next >= STV680_NUMSCRATCH)
+ stv680->scratch_next = 0;;
+ break;
+ } /* switch */
+ } else {
+ stv680->nullpackets++;
+ if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
+ if (waitqueue_active (&stv680->wq)) {
+ wake_up_interruptible (&stv680->wq);
+ }
+ }
+ } /* if - else */
+
+ /* Resubmit urb for new data */
+ urb->status = 0;
+ urb->dev = stv680->udev;
+ if (usb_submit_urb (urb))
+ PDEBUG (0, "STV(e): urb burned down in video irq");
+ return;
+} /* _video_irq */
+
+static int stv680_start_stream (struct usb_stv *stv680)
+{
+ urb_t *urb;
+ int err = 0, i;
+
+ stv680->streaming = 1;
+
+ /* Do some memory allocation */
+ for (i = 0; i < STV680_NUMFRAMES; i++) {
+ stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize;
+ stv680->frame[i].curpix = 0;
+ }
+ /* packet size = 4096 */
+ for (i = 0; i < STV680_NUMSBUF; i++) {
+ stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
+ if (stv680->sbuf[i].data == NULL) {
+ PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i);
+ return -1;
+ }
+ }
+
+ stv680->scratch_next = 0;
+ stv680->scratch_use = 0;
+ stv680->scratch_overflow = 0;
+ for (i = 0; i < STV680_NUMSCRATCH; i++) {
+ stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
+ if (stv680->scratch[i].data == NULL) {
+ PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i);
+ return -1;
+ }
+ stv680->scratch[i].state = BUFFER_UNUSED;
+ }
+
+ for (i = 0; i < STV680_NUMSBUF; i++) {
+ urb = usb_alloc_urb (0);
+ if (!urb)
+ return ENOMEM;
+
+ /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */
+ usb_fill_bulk_urb (urb, stv680->udev,
+ usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr),
+ stv680->sbuf[i].data, stv680->rawbufsize,
+ stv680_video_irq, stv680);
+ urb->timeout = PENCAM_TIMEOUT * 2;
+ urb->transfer_flags |= USB_QUEUE_BULK;
+ stv680->urb[i] = urb;
+ err = usb_submit_urb (stv680->urb[i]);
+ if (err)
+ PDEBUG (0, "STV(e): urb burned down in start stream");
+ } /* i STV680_NUMSBUF */
+
+ stv680->framecount = 0;
+ return 0;
+}
+
+static int stv680_stop_stream (struct usb_stv *stv680)
+{
+ int i;
+
+ if (!stv680->streaming || !stv680->udev)
+ return 1;
+
+ stv680->streaming = 0;
+
+ for (i = 0; i < STV680_NUMSBUF; i++)
+ if (stv680->urb[i]) {
+ stv680->urb[i]->next = NULL;
+ usb_unlink_urb (stv680->urb[i]);
+ usb_free_urb (stv680->urb[i]);
+ stv680->urb[i] = NULL;
+ kfree (stv680->sbuf[i].data);
+ }
+ for (i = 0; i < STV680_NUMSCRATCH; i++) {
+ kfree (stv680->scratch[i].data);
+ stv680->scratch[i].data = NULL;
+ }
+
+ return 0;
+}
+
+static int stv680_set_size (struct usb_stv *stv680, int width, int height)
+{
+ int wasstreaming = stv680->streaming;
+
+ /* Check to see if we need to change */
+ if ((stv680->vwidth == width) && (stv680->vheight == height))
+ return 0;
+
+ PDEBUG (1, "STV(i): size request for %i x %i", width, height);
+ /* Check for a valid mode */
+ if ((!width || !height) || ((width & 1) || (height & 1))) {
+ PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
+ return 1;
+ }
+
+ if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) {
+ width = stv680->maxwidth / 2;
+ height = stv680->maxheight / 2;
+ } else if ((width >= 158) && (width <= 166)) {
+ width = 160;
+ height = 120;
+ } else if ((width >= 172) && (width <= 180)) {
+ width = 176;
+ height = 144;
+ } else if ((width >= 318) && (width <= 350)) {
+ width = 320;
+ height = 240;
+ } else if ((width >= 350) && (width <= 358)) {
+ width = 352;
+ height = 288;
+ }
+
+ /* Stop a current stream and start it again at the new size */
+ if (wasstreaming)
+ stv680_stop_stream (stv680);
+ stv680->vwidth = width;
+ stv680->vheight = height;
+ PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight);
+ if (wasstreaming)
+ stv680_start_stream (stv680);
+
+ return 0;
+}
+
+/**********************************************************************
+ * Video Decoding
+ **********************************************************************/
+
+/******* routines from the pencam program; hey, they work! ********/
+
+/*
+ * STV0680 Vision Camera Chipset Driver
+ * Copyright (C) 2000 Adam Harrison <adam@antispin.org>
+*/
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define AD(x, y, w) (((y)*(w)+(x))*3)
+
+static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer)
+{
+ int x, y, i;
+ int w = stv680->cwidth;
+ int vw = stv680->cwidth, vh = stv680->cheight, vstep = 1;
+ unsigned int p = 0;
+ int colour = 0, bayer = 0;
+ unsigned char *raw = buffer->data;
+ struct stv680_frame *frame = &stv680->frame[stv680->curframe];
+ unsigned char *output = frame->data;
+ unsigned char *temp = frame->data;
+ int offset = buffer->offset;
+
+ if (frame->curpix == 0) {
+ if (frame->grabstate == FRAME_READY) {
+ frame->grabstate = FRAME_GRABBING;
+ }
+ }
+ if (offset != frame->curpix) { /* Regard frame as lost :( */
+ frame->curpix = 0;
+ stv680->error++;
+ return;
+ }
+
+ if ((stv680->vwidth == 322) || (stv680->vwidth == 320)) {
+ vw = 320;
+ vh = 240;
+ vstep = 1;
+ }
+ if ((stv680->vwidth == 352)) {
+ vw = 352;
+ vh = 288;
+ vstep = 1;
+ }
+ if ((stv680->vwidth == 160)) {
+ vw = 160;
+ vh = 120;
+ vstep = 2;
+ }
+ if ((stv680->vwidth == 176)) {
+ vw = 176;
+ vh = 144;
+ vstep = 2;
+ }
+ memset (output, 0, 3 * vw * vh); /* clear output matrix. Maybe not necessary. */
+
+ for (y = 0; y < vh; y++) {
+ for (x = 0; x < vw; x++) {
+
+ switch (vstep) {
+ case 1:
+ if (x & 1)
+ p = *(raw + y * w + (x >> 1));
+ else
+ p = *(raw + y * w + (x >> 1) + (w >> 1));
+ break;
+
+ case 2:
+ if (x & 1)
+ p = *(raw + ((y * w) << 1) + x);
+ else
+ p = *(raw + ((y * w) << 1) + x + (w >> 1));
+ break;
+ }
+
+ if (y & 1)
+ bayer = 2;
+ else
+ bayer = 0;
+ if (x & 1)
+ bayer++;
+
+ switch (bayer) {
+ case 0:
+ case 3:
+ colour = 1;
+ break;
+ case 1:
+ colour = 0;
+ break;
+ case 2:
+ colour = 2;
+ break;
+ }
+ i = (y * vw + x) * 3; /* output already zeroed out with memset */
+ *(output + i + colour) = (unsigned char) p;
+ } /* for x */
+ } /* for y */
+
+ /****** gamma correction plus hardcoded white balance */
+ /* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code.
+ Correction values red[], green[], blue[], are generated by
+ (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255.
+ White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and
+ converted to unsigned char. Values are in stv680.h */
+ for (y = 0; y < vh; y++) {
+ for (x = 0; x < vw; x++) {
+ i = (y * vw + x) * 3;
+ *(output + i) = red[*(output + i)];
+ *(output + i + 1) = green[*(output + i + 1)];
+ *(output + i + 2) = blue[*(output + i + 2)];
+ }
+ }
+
+ /****** bayer demosaic ******/
+ for (y = 1; y < (vh - 1); y++) {
+ for (x = 1; x < (vw - 1); x++) { /* work out pixel type */
+ if (y & 1)
+ bayer = 0;
+ else
+ bayer = 2;
+ if (!(x & 1))
+ bayer++;
+
+ switch (bayer) {
+ case 0: /* green. blue lr, red tb */
+ *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1;
+ *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1;
+ break;
+
+ case 1: /* blue. green lrtb, red diagonals */
+ *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
+ *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2;
+ break;
+
+ case 2: /* red. green lrtb, blue diagonals */
+ *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
+ *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2;
+ break;
+
+ case 3: /* green. red lr, blue tb */
+ *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1;
+ *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1;
+ break;
+ } /* switch */
+ } /* for x */
+ } /* for y - end demosaic */
+
+ /* output is RGB; some programs want BGR */
+ if (swapRGB == 1) {
+ for (y = 0; y < vh; y++) {
+ for (x = 0; x < vw; x++) {
+ i = (y * vw + x) * 3;
+ *(temp) = *(output + i);
+ *(output + i) = *(output + i + 2);
+ *(output + i + 2) = *(temp);
+ }
+ }
+ }
+ /* brightness */
+ if (stv680->chgbright == 1) {
+ if (stv680->brightness >= 32767) {
+ p = (stv680->brightness - 32767) / 256;
+ for (x = 0; x < (vw * vh * 3); x++) {
+ if ((*(output + x) + (unsigned char) p) > 255)
+ *(output + x) = 255;
+ else
+ *(output + x) += (unsigned char) p;
+ } /* for */
+ } else {
+ p = (32767 - stv680->brightness) / 256;
+ for (x = 0; x < (vw * vh * 3); x++) {
+ if ((unsigned char) p > *(output + x))
+ *(output + x) = 0;
+ else
+ *(output + x) -= (unsigned char) p;
+ } /* for */
+ } /* else */
+ }
+ /* if */
+ frame->curpix = 0;
+ frame->curlinepix = 0;
+ frame->grabstate = FRAME_DONE;
+ stv680->framecount++;
+ stv680->readcount++;
+ if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) {
+ stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1);
+ }
+
+} /* bayer_unshuffle */
+
+/******* end routines from the pencam program *********/
+
+static int stv680_newframe (struct usb_stv *stv680, int framenr)
+{
+ int errors = 0;
+
+ while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) {
+ if (!stv680->frame[framenr].curpix) {
+ errors++;
+ }
+ wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY));
+
+ if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
+ stv680->nullpackets = 0;
+ PDEBUG (2, "STV(i): too many null length packets, restarting capture");
+ stv680_stop_stream (stv680);
+ stv680_start_stream (stv680);
+ } else {
+ if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) {
+ stv680->frame[framenr].grabstate = FRAME_ERROR;
+ PDEBUG (2, "STV(e): FRAME_ERROR in _newframe");
+ return -EIO;
+ }
+ stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY;
+
+ bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]);
+
+ stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED;
+ stv680->scratch_use++;
+ if (stv680->scratch_use >= STV680_NUMSCRATCH)
+ stv680->scratch_use = 0;
+ if (errors > STV680_MAX_ERRORS) {
+ errors = 0;
+ PDEBUG (2, "STV(i): too many errors, restarting capture");
+ stv680_stop_stream (stv680);
+ stv680_start_stream (stv680);
+ }
+ } /* else */
+ } /* while */
+ return 0;
+}
+
+/*********************************************************************
+ * Video4Linux
+ *********************************************************************/
+
+static int stv_open (struct video_device *dev, int flags)
+{
+ struct usb_stv *stv680 = (struct usb_stv *) dev;
+ int err = 0;
+
+ /* we are called with the BKL held */
+ MOD_INC_USE_COUNT;
+ stv680->user = 1;
+ err = stv_init (stv680); /* main initialization routine for camera */
+
+ if (err >= 0) {
+ stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES);
+ if (!stv680->fbuf) {
+ PDEBUG (0, "STV(e): Could not rvmalloc frame bufer");
+ err = -ENOMEM;
+ }
+ }
+ if (err) {
+ MOD_DEC_USE_COUNT;
+ stv680->user = 0;
+ }
+
+ return err;
+}
+
+static void stv_close (struct video_device *dev)
+{
+ /* called with BKL held */
+ struct usb_stv *stv680 = (struct usb_stv *) dev;
+ int i;
+
+ for (i = 0; i < STV680_NUMFRAMES; i++)
+ stv680->frame[i].grabstate = FRAME_UNUSED;
+ if (stv680->streaming)
+ stv680_stop_stream (stv680);
+
+ if ((i = stv_stop_video (stv680)) < 0)
+ PDEBUG (1, "STV(e): stop_video failed in stv_close");
+
+ rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES);
+ stv680->user = 0;
+
+ if (stv680->removed) {
+ video_unregister_device (&stv680->vdev);
+ kfree (stv680);
+ stv680 = NULL;
+ PDEBUG (0, "STV(i): device unregistered");
+ }
+ MOD_DEC_USE_COUNT;
+}
+
+static long stv680_write (struct video_device *dev, const char *buf, unsigned long count, int noblock)
+{
+ return -EINVAL;
+}
+
+static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg)
+{
+ struct usb_stv *stv680 = (struct usb_stv *) vdev;
+
+ if (!stv680->udev)
+ return -EIO;
+
+ switch (cmd) {
+ case VIDIOCGCAP:{
+ struct video_capability b;
+
+ strcpy (b.name, stv680->camera_name);
+ b.type = VID_TYPE_CAPTURE;
+ b.channels = 1;
+ b.audios = 0;
+ b.maxwidth = stv680->maxwidth;
+ b.maxheight = stv680->maxheight;
+ b.minwidth = stv680->maxwidth / 2;
+ b.minheight = stv680->maxheight / 2;
+
+ if (copy_to_user (arg, &b, sizeof (b))) {
+ PDEBUG (2, "STV(e): VIDIOCGGAP failed");
+ return -EFAULT;
+ }
+ return 0;
+ }
+ case VIDIOCGCHAN:{
+ struct video_channel v;
+
+ if (copy_from_user (&v, arg, sizeof (v)))
+ return -EFAULT;
+ if (v.channel != 0)
+ return -EINVAL;
+
+ v.flags = 0;
+ v.tuners = 0;
+ v.type = VIDEO_TYPE_CAMERA;
+ strcpy (v.name, "STV Camera");
+
+ if (copy_to_user (arg, &v, sizeof (v))) {
+ PDEBUG (2, "STV(e): VIDIOCGCHAN failed");
+ return -EFAULT;
+ }
+ return 0;
+ }
+ case VIDIOCSCHAN:{
+ int v;
+
+ if (copy_from_user (&v, arg, sizeof (v))) {
+ PDEBUG (2, "STV(e): VIDIOCSCHAN failed");
+ return -EFAULT;
+ }
+ if (v != 0)
+ return -EINVAL;
+
+ return 0;
+ }
+ case VIDIOCGPICT:{
+ struct video_picture p;
+
+ stv680_get_pict (stv680, &p);
+ if (copy_to_user (arg, &p, sizeof (p))) {
+ PDEBUG (2, "STV(e): VIDIOCGPICT failed");
+ return -EFAULT;
+ }
+ return 0;
+ }
+ case VIDIOCSPICT:{
+ struct video_picture p;
+
+ if (copy_from_user (&p, arg, sizeof (p))) {
+ PDEBUG (2, "STV(e): VIDIOCSPICT failed");
+ return -EFAULT;
+ }
+ copy_from_user (&p, arg, sizeof (p));
+ PDEBUG (2, "STV(i): palette set to RGB in VIDIOSPICT");
+
+ if (stv680_set_pict (stv680, &p))
+ return -EINVAL;
+ return 0;
+ }
+ case VIDIOCSWIN:{
+ struct video_window vw;
+
+ if (copy_from_user (&vw, arg, sizeof (vw)))
+ return -EFAULT;
+ if (vw.flags)
+ return -EINVAL;
+ if (vw.clipcount)
+ return -EINVAL;
+ if (vw.width != stv680->vwidth) {
+ if (stv680_set_size (stv680, vw.width, vw.height)) {
+ PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN");
+ return -EINVAL;
+ }
+ }
+ return 0;
+ }
+ case VIDIOCGWIN:{
+ struct video_window vw;
+
+ vw.x = 0; /* FIXME */
+ vw.y = 0;
+ vw.chromakey = 0;
+ vw.flags = 0;
+ vw.clipcount = 0;
+ vw.width = stv680->vwidth;
+ vw.height = stv680->vheight;
+
+ if (copy_to_user (arg, &vw, sizeof (vw))) {
+ PDEBUG (2, "STV(e): VIDIOCGWIN failed");
+ return -EFAULT;
+ }
+ return 0;
+ }
+ case VIDIOCGMBUF:{
+ struct video_mbuf vm;
+ int i;
+
+ memset (&vm, 0, sizeof (vm));
+ vm.size = STV680_NUMFRAMES * stv680->maxframesize;
+ vm.frames = STV680_NUMFRAMES;
+ for (i = 0; i < STV680_NUMFRAMES; i++)
+ vm.offsets[i] = stv680->maxframesize * i;
+
+ if (copy_to_user ((void *) arg, (void *) &vm, sizeof (vm))) {
+ PDEBUG (2, "STV(e): VIDIOCGMBUF failed");
+ return -EFAULT;
+ }
+
+ return 0;
+ }
+ case VIDIOCMCAPTURE:{
+ struct video_mmap vm;
+
+ if (copy_from_user (&vm, arg, sizeof (vm))) {
+ PDEBUG (2, "STV(e): VIDIOCMCAPTURE failed");
+ return -EFAULT;
+ }
+ if (vm.format != STV_VIDEO_PALETTE) {
+ PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
+ vm.format, STV_VIDEO_PALETTE);
+ if (vm.format == 3) {
+ PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is ON");
+ /* this may fix those apps (e.g., xawtv) that want BGR */
+ swapRGB = 1;
+ }
+ return -EINVAL;
+ }
+ if (vm.frame >= STV680_NUMFRAMES) {
+ PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
+ return -EINVAL;
+ }
+ if (stv680->frame[vm.frame].grabstate != FRAME_UNUSED) {
+ PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate != FRAME_UNUSED");
+ return -EBUSY;
+ }
+ /* Is this according to the v4l spec??? */
+ if (stv680->vwidth != vm.width) {
+ if (stv680_set_size (stv680, vm.width, vm.height)) {
+ PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed");
+ return -EINVAL;
+ }
+ }
+ stv680->frame[vm.frame].grabstate = FRAME_READY;
+
+ if (!stv680->streaming)
+ stv680_start_stream (stv680);
+
+ return 0;
+ }
+ case VIDIOCSYNC:{
+ int frame, ret = 0;
+
+ if (copy_from_user ((void *) &frame, arg, sizeof (int))) {
+ PDEBUG (2, "STV(e): VIDIOCSYNC failed");
+ return -EFAULT;
+ }
+ if (frame < 0 || frame >= STV680_NUMFRAMES) {
+ PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC");
+ return -EINVAL;
+ }
+ ret = stv680_newframe (stv680, frame);
+ stv680->frame[frame].grabstate = FRAME_UNUSED;
+ return ret;
+ }
+ case VIDIOCGFBUF:{
+ struct video_buffer vb;
+
+ memset (&vb, 0, sizeof (vb));
+ vb.base = NULL; /* frame buffer not supported, not used */
+
+ if (copy_to_user ((void *) arg, (void *) &vb, sizeof (vb))) {
+ PDEBUG (2, "STV(e): VIDIOCSYNC failed");
+ return -EFAULT;
+ }
+ return 0;
+ }
+ case VIDIOCKEY:
+ return 0;
+ case VIDIOCCAPTURE:
+ {
+ PDEBUG (2, "STV(e): VIDIOCCAPTURE failed");
+ return -EINVAL;
+ }
+ case VIDIOCSFBUF:
+ return -EINVAL;
+ case VIDIOCGTUNER:
+ case VIDIOCSTUNER:
+ return -EINVAL;
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
+ return -EINVAL;
+ case VIDIOCGAUDIO:
+ case VIDIOCSAUDIO:
+ return -EINVAL;
+ default:
+ return -ENOIOCTLCMD;
+ } /* end switch */
+
+ return 0;
+}
+
+static int stv680_mmap (struct video_device *dev, const char *adr, unsigned long size)
+{
+ struct usb_stv *stv680 = (struct usb_stv *) dev;
+ unsigned long start = (unsigned long) adr;
+ unsigned long page, pos;
+
+ down (&stv680->lock);
+
+ if (stv680->udev == NULL) {
+ up (&stv680->lock);
+ return -EIO;
+ }
+ if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
+ & ~(PAGE_SIZE - 1))) {
+ up (&stv680->lock);
+ return -EINVAL;
+ }
+ pos = (unsigned long) stv680->fbuf;
+ while (size > 0) {
+ page = kvirt_to_pa (pos);
+ if (remap_page_range (start, page, PAGE_SIZE, PAGE_SHARED)) {
+ up (&stv680->lock);
+ return -EAGAIN;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+ up (&stv680->lock);
+
+ return 0;
+}
+
+static long stv680_read (struct video_device *dev, char *buf, unsigned long count, int noblock)
+{
+ unsigned long int realcount = count;
+ int ret = 0;
+ struct usb_stv *stv680 = (struct usb_stv *) dev;
+ unsigned long int i;
+
+ if (STV680_NUMFRAMES != 2) {
+ PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!");
+ return -1;
+ }
+ if (stv680->udev == NULL)
+ return -EIO;
+ if (realcount > (stv680->vwidth * stv680->vheight * 3))
+ realcount = stv680->vwidth * stv680->vheight * 3;
+
+ /* Shouldn't happen: */
+ if (stv680->frame[0].grabstate == FRAME_GRABBING) {
+ PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read");
+ return -EBUSY;
+ }
+ stv680->frame[0].grabstate = FRAME_READY;
+ stv680->frame[1].grabstate = FRAME_UNUSED;
+ stv680->curframe = 0;
+
+ if (!stv680->streaming)
+ stv680_start_stream (stv680);
+
+ if (!stv680->streaming) {
+ ret = stv680_newframe (stv680, 0); /* ret should = 0 */
+ }
+
+ ret = stv680_newframe (stv680, 0);
+
+ if (!ret) {
+ if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) {
+ PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i);
+ return -EFAULT;
+ }
+ } else {
+ realcount = ret;
+ }
+ stv680->frame[0].grabstate = FRAME_UNUSED;
+ return realcount;
+} /* stv680_read */
+
+static int stv_init_done (struct video_device *dev)
+{
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+ if (create_proc_stv680_cam ((struct usb_stv *) dev) < 0)
+ return -1;
+#endif
+ return 0;
+}
+
+static struct video_device stv680_template = {
+ owner: THIS_MODULE,
+ name: "STV0680 USB camera",
+ type: VID_TYPE_CAPTURE,
+ hardware: VID_HARDWARE_SE401,
+ open: stv_open,
+ close: stv_close,
+ read: stv680_read,
+ write: stv680_write,
+ ioctl: stv680_ioctl,
+ mmap: stv680_mmap,
+ initialize: stv_init_done,
+};
+
+static void *__devinit stv680_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
+{
+ struct usb_interface_descriptor *interface;
+ struct usb_stv *stv680;
+ char *camera_name = NULL;
+
+ /* We don't handle multi-config cameras */
+ if (dev->descriptor.bNumConfigurations != 1) {
+ PDEBUG (0, "STV(e): Number of Configurations != 1");
+ return NULL;
+ }
+
+ interface = &dev->actconfig->interface[ifnum].altsetting[0];
+ /* Is it a STV680? */
+ if ((dev->descriptor.idVendor == USB_PENCAM_VENDOR_ID) && (dev->descriptor.idProduct == USB_PENCAM_PRODUCT_ID)) {
+ camera_name = "STV0680";
+ PDEBUG (0, "STV(i): STV0680 camera found.");
+ } else {
+ PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 values.");
+ PDEBUG (0, "STV(e): Check that the STV0680 camera is connected to the computer.");
+ return NULL;
+ }
+ /* We found one */
+ if ((stv680 = kmalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
+ PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
+ return NULL;
+ }
+
+ memset (stv680, 0, sizeof (*stv680));
+
+ stv680->udev = dev;
+ stv680->camera_name = camera_name;
+
+ memcpy (&stv680->vdev, &stv680_template, sizeof (stv680_template));
+ memcpy (stv680->vdev.name, stv680->camera_name, strlen (stv680->camera_name));
+ init_waitqueue_head (&stv680->wq);
+ init_MUTEX (&stv680->lock);
+ wmb ();
+
+ if (video_register_device (&stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+ kfree (stv680);
+ PDEBUG (0, "STV(e): video_register_device failed");
+ return NULL;
+ }
+ PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev.minor);
+
+ return stv680;
+}
+
+static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680)
+{
+ int i;
+
+ stv680->udev = NULL;
+ stv680->frame[0].grabstate = FRAME_ERROR;
+ stv680->frame[1].grabstate = FRAME_ERROR;
+ stv680->streaming = 0;
+
+ wake_up_interruptible (&stv680->wq);
+
+ for (i = 0; i < STV680_NUMSBUF; i++)
+ if (stv680->urb[i]) {
+ stv680->urb[i]->next = NULL;
+ usb_unlink_urb (stv680->urb[i]);
+ usb_free_urb (stv680->urb[i]);
+ stv680->urb[i] = NULL;
+ kfree (stv680->sbuf[i].data);
+ }
+ for (i = 0; i < STV680_NUMSCRATCH; i++)
+ if (stv680->scratch[i].data) {
+ kfree (stv680->scratch[i].data);
+ }
+ PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name);
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+ destroy_proc_stv680_cam (stv680);
+#endif
+ /* Free the memory */
+ kfree (stv680);
+}
+
+static void stv680_disconnect (struct usb_device *dev, void *ptr)
+{
+ struct usb_stv *stv680 = (struct usb_stv *) ptr;
+
+ lock_kernel ();
+ /* We don't want people trying to open up the device */
+ if (!stv680->user) {
+ video_unregister_device (&stv680->vdev);
+ usb_stv680_remove_disconnected (stv680);
+ } else {
+ stv680->removed = 1;
+ }
+ unlock_kernel ();
+}
+
+static struct usb_driver stv680_driver = {
+ name: "stv680",
+ probe: stv680_probe,
+ disconnect: stv680_disconnect,
+ id_table: device_table
+};
+
+/********************************************************************
+ * Module routines
+ ********************************************************************/
+
+static int __init usb_stv680_init (void)
+{
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+ if (proc_stv680_create () < 0)
+ return -1;
+#endif
+ if (usb_register (&stv680_driver) < 0) {
+ PDEBUG (0, "STV(e): Could not setup STV0680 driver");
+ return -1;
+ }
+ PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION);
+
+ info(DRIVER_DESC " " DRIVER_VERSION);
+ return 0;
+}
+
+static void __exit usb_stv680_exit (void)
+{
+ usb_deregister (&stv680_driver);
+ PDEBUG (0, "STV(i): driver deregistered");
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+ proc_stv680_destroy ();
+#endif
+}
+
+module_init (usb_stv680_init);
+module_exit (usb_stv680_exit);
--- /dev/null
+/****************************************************************************
+ *
+ * Filename: stv680.h
+ *
+ * Description:
+ * This is a USB driver for STV0680 based usb video cameras.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+/* size of usb transfers */
+#define STV680_PACKETSIZE 4096
+
+/* number of queued bulk transfers to use, may have problems if > 1 */
+#define STV680_NUMSBUF 1
+
+/* number of frames supported by the v4l part */
+#define STV680_NUMFRAMES 2
+
+/* scratch buffers for passing data to the decoders: 2 or 4 are good */
+#define STV680_NUMSCRATCH 2
+
+/* number of nul sized packets to receive before kicking the camera */
+#define STV680_MAX_NULLPACKETS 200
+
+/* number of decoding errors before kicking the camera */
+#define STV680_MAX_ERRORS 100
+
+#define USB_PENCAM_VENDOR_ID 0x0553
+#define USB_PENCAM_PRODUCT_ID 0x0202
+#define PENCAM_TIMEOUT 1000
+/* fmt 4 */
+#define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24
+
+static __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
+ {}
+};
+MODULE_DEVICE_TABLE (usb, device_table);
+
+struct stv680_sbuf {
+ unsigned char *data;
+};
+
+enum {
+ FRAME_UNUSED, /* Unused (no MCAPTURE) */
+ FRAME_READY, /* Ready to start grabbing */
+ FRAME_GRABBING, /* In the process of being grabbed into */
+ FRAME_DONE, /* Finished grabbing, but not been synced yet */
+ FRAME_ERROR, /* Something bad happened while processing */
+};
+
+enum {
+ BUFFER_UNUSED,
+ BUFFER_READY,
+ BUFFER_BUSY,
+ BUFFER_DONE,
+};
+
+/* raw camera data <- sbuf (urb transfer buf) */
+struct stv680_scratch {
+ unsigned char *data;
+ volatile int state;
+ int offset;
+ int length;
+};
+
+/* processed data for display ends up here, after bayer */
+struct stv680_frame {
+ unsigned char *data; /* Frame buffer */
+ volatile int grabstate; /* State of grabbing */
+ unsigned char *curline;
+ int curlinepix;
+ int curpix;
+};
+
+/* this is almost the video structure uvd_t, with extra parameters for stv */
+struct usb_stv {
+ struct video_device vdev;
+
+ struct usb_device *udev;
+
+ unsigned char bulk_in_endpointAddr; /* __u8 the address of the bulk in endpoint */
+ char *camera_name;
+
+ unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */
+ int SupportedModes;
+ int CIF;
+ int VGA;
+ int QVGA;
+ int cwidth; /* camera width */
+ int cheight; /* camera height */
+ int maxwidth; /* max video width */
+ int maxheight; /* max video height */
+ int vwidth; /* current width for video window */
+ int vheight; /* current height for video window */
+ unsigned long int rawbufsize;
+ unsigned long int maxframesize; /* rawbufsize * 3 for RGB */
+
+ int origGain;
+ int origMode; /* original camera mode */
+
+ struct semaphore lock; /* to lock the structure */
+ int user; /* user count for exclusive use */
+ int removed; /* device disconnected */
+ int streaming; /* Are we streaming video? */
+ char *fbuf; /* Videodev buffer area */
+ urb_t *urb[STV680_NUMSBUF]; /* # of queued bulk transfers */
+ int curframe; /* Current receiving frame */
+ struct stv680_frame frame[STV680_NUMFRAMES]; /* # frames supported by v4l part */
+ int readcount;
+ int framecount;
+ int error;
+ int dropped;
+ int scratch_next;
+ int scratch_use;
+ int scratch_overflow;
+ struct stv680_scratch scratch[STV680_NUMSCRATCH]; /* for decoders */
+ struct stv680_sbuf sbuf[STV680_NUMSBUF];
+
+ unsigned int brightness;
+ unsigned int chgbright;
+ unsigned int whiteness;
+ unsigned int colour;
+ unsigned int contrast;
+ unsigned int hue;
+ unsigned int palette;
+ unsigned int depth; /* rgb24 in bits */
+
+ wait_queue_head_t wq; /* Processes waiting */
+
+ struct proc_dir_entry *proc_entry; /* /proc/stv680/videoX */
+ int nullpackets;
+};
+
+unsigned char red[256] = {
+ 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
+ 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
+ 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
+ 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
+ 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
+ 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
+ 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
+ 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
+ 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
+ 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
+ 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
+ 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
+ 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
+ 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
+ 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
+ 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
+ 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
+ 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
+ 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
+ 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
+ 245, 245, 246, 246
+};
+
+unsigned char green[256] = {
+ 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 32, 39, 45, 50, 54,
+ 58, 62, 65, 69, 71, 74, 77, 79, 83, 85, 87, 90,
+ 92, 93, 95, 98, 100, 101, 104, 106, 107, 109, 111, 113,
+ 114, 116, 118, 119, 121, 122, 124, 126, 127, 128, 129, 132,
+ 133, 134, 135, 136, 138, 140, 141, 142, 143, 145, 146, 147,
+ 148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161,
+ 162, 163, 164, 166, 167, 168, 168, 169, 170, 171, 173, 174,
+ 175, 176, 176, 177, 179, 180, 181, 182, 182, 183, 184, 186,
+ 187, 187, 188, 189, 190, 191, 191, 193, 194, 195, 195, 196,
+ 197, 198, 198, 200, 201, 201, 202, 203, 204, 204, 205, 207,
+ 207, 208, 209, 209, 210, 211, 212, 212, 214, 215, 215, 216,
+ 217, 217, 218, 218, 219, 221, 221, 222, 223, 223, 224, 225,
+ 225, 226, 226, 228, 229, 229, 230, 231, 231, 232, 232, 233,
+ 235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242,
+ 243, 243, 244, 244, 245, 245, 246, 248, 248, 249, 249, 250,
+ 250, 251, 251, 252, 253, 253, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255
+};
+
+unsigned char blue[256] = {
+ 0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 41, 50, 57, 63, 69,
+ 74, 78, 82, 87, 90, 94, 97, 100, 105, 108, 111, 113,
+ 116, 118, 121, 124, 127, 128, 131, 134, 136, 139, 140, 143,
+ 145, 148, 149, 150, 153, 155, 156, 159, 161, 162, 164, 167,
+ 168, 170, 171, 173, 174, 177, 179, 180, 182, 183, 185, 186,
+ 187, 189, 190, 192, 193, 195, 196, 198, 199, 201, 202, 204,
+ 205, 207, 208, 210, 211, 213, 213, 214, 216, 217, 219, 220,
+ 222, 223, 223, 224, 226, 227, 229, 230, 230, 232, 233, 235,
+ 236, 236, 238, 239, 241, 242, 242, 244, 245, 247, 247, 248,
+ 250, 251, 251, 253, 254, 254, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255
+};
--- /dev/null
+/* -*- linux-c -*-
+ * USB ViCAM driver
+ *
+ * Copyright (c) 2001 Christopher L Cheney (ccheney@cheney.cx)
+ * Copyright (c) 2001 Pavel Machek (pavel@suse.cz) sponsored by SuSE
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This driver is for the Vista Imaging ViCAM and 3Com HomeConnect USB
+ *
+ * Thanks to Greg Kroah-Hartman for the USB Skeleton driver
+ *
+ * TODO:
+ * - find out the ids for the Vista Imaging ViCAM
+ *
+ * History:
+ *
+ * 2001_07_07 - 0.1 - christopher: first version
+ * 2001_08_28 - 0.2 - pavel: messed it up, but for some fun, try
+ while true; do dd if=/dev/video of=/dev/fb0 bs=$[0x1e480] count=1 2> /dev/null; done
+ yep, moving pictures.
+ * 2001_08_29 - 0.3 - pavel: played a little bit more. Experimental mmap support. For some fun,
+ get gqcam-0.9, compile it and run. Better than dd ;-).
+ * 2001_08_29 - 0.4 - pavel: added shutter speed control (not much functional)
+ kill update_params if it does not seem to work for you.
+ * 2001_08_30 - 0.5 - pavel: fixed stupid bug with update_params & vicam_bulk
+
+ *
+ * FIXME: It crashes on rmmod with camera plugged.
+ */
+#define DEBUG 1
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/usb.h>
+
+#include <asm/io.h>
+#include <linux/wrapper.h>
+#include <linux/vmalloc.h>
+
+#include <linux/videodev.h>
+
+#include "vicam.h"
+#include "vicamurbs.h"
+
+/* Version Information */
+#define DRIVER_VERSION "v0"
+#define DRIVER_AUTHOR "Christopher L Cheney <ccheney@cheney.cx>, Pavel Machek <pavel@suse.cz>"
+#define DRIVER_DESC "USB ViCAM Driver"
+
+/* Define these values to match your device */
+#define USB_VICAM_VENDOR_ID 0x04C1
+#define USB_VICAM_PRODUCT_ID 0x009D
+
+/* table of devices that work with this driver */
+static struct usb_device_id vicam_table [] = {
+ { USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, vicam_table);
+
+static int video_nr = -1; /* next avail video device */
+static struct usb_driver vicam_driver;
+
+static char *buf, *buf2;
+static int change_pending = 0;
+
+static int vicam_parameters(struct usb_vicam *vicam);
+
+/******************************************************************************
+ *
+ * Memory management functions
+ *
+ * Taken from bttv-drivers.c 2.4.7-pre3
+ *
+ ******************************************************************************/
+
+/* [DaveM] I've recoded most of this so that:
+ * 1) It's easier to tell what is happening
+ * 2) It's more portable, especially for translating things
+ * out of vmalloc mapped areas in the kernel.
+ * 3) Less unnecessary translations happen.
+ *
+ * The code used to assume that the kernel vmalloc mappings
+ * existed in the page tables of every process, this is simply
+ * not guarenteed. We now use pgd_offset_k which is the
+ * defined way to get at the kernel page tables.
+ */
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+ unsigned long ret = 0UL;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ if (!pgd_none(*pgd)) {
+ pmd = pmd_offset(pgd, adr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset(pmd, adr);
+ pte = *ptep;
+ if(pte_present(pte)) {
+ ret = (unsigned long) page_address(pte_page(pte));
+ ret |= (adr & (PAGE_SIZE - 1));
+
+ }
+ }
+ }
+ return ret;
+}
+
+static inline unsigned long uvirt_to_bus(unsigned long adr)
+{
+ unsigned long kva, ret;
+
+ kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
+ ret = virt_to_bus((void *)kva);
+ return ret;
+}
+
+static inline unsigned long kvirt_to_bus(unsigned long adr)
+{
+ unsigned long va, kva, ret;
+
+ va = VMALLOC_VMADDR(adr);
+ kva = uvirt_to_kva(pgd_offset_k(va), va);
+ ret = virt_to_bus((void *)kva);
+ return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+ unsigned long va, kva, ret;
+
+ va = VMALLOC_VMADDR(adr);
+ kva = uvirt_to_kva(pgd_offset_k(va), va);
+ ret = __pa(kva);
+ return ret;
+}
+
+static void * rvmalloc(signed long size)
+{
+ void * mem;
+ unsigned long adr, page;
+
+ mem=vmalloc_32(size);
+ if (mem)
+ {
+ memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+ adr=(unsigned long) mem;
+ while (size > 0)
+ {
+ page = kvirt_to_pa(adr);
+ mem_map_reserve(virt_to_page(__va(page)));
+ adr+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ }
+ return mem;
+}
+
+static void rvfree(void * mem, signed long size)
+{
+ unsigned long adr, page;
+
+ if (mem)
+ {
+ adr=(unsigned long) mem;
+ while (size > 0)
+ {
+ page = kvirt_to_pa(adr);
+ mem_map_unreserve(virt_to_page(__va(page)));
+ adr+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ vfree(mem);
+ }
+}
+
+/******************************************************************************
+ *
+ * Foo Bar
+ *
+ ******************************************************************************/
+
+/**
+ * usb_vicam_debug_data
+ */
+static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data)
+{
+ int i;
+
+ if (!debug)
+ return;
+
+ printk (KERN_DEBUG __FILE__": %s - length = %d, data = ",
+ function, size);
+ for (i = 0; i < size; ++i) {
+ printk ("%.2x ", data[i]);
+ }
+ printk ("\n");
+}
+
+/*****************************************************************************
+ *
+ * Send command to vicam
+ *
+ *****************************************************************************/
+
+static int vicam_sndctrl(int set, struct usb_vicam *vicam, unsigned short req,
+ unsigned short value, unsigned char *cp, int size)
+{
+ int ret;
+ unsigned char *transfer_buffer = kmalloc (size, GFP_KERNEL);
+
+ /* Needs to return data I think, works for sending though */
+ memcpy(transfer_buffer, cp, size);
+
+ ret = usb_control_msg ( vicam->udev, set ? usb_sndctrlpipe(vicam->udev, 0) : usb_rcvctrlpipe(vicam->udev, 0), req, (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, transfer_buffer, size, HZ);
+
+ kfree(transfer_buffer);
+ if (ret)
+ printk("vicam: error: %d\n", ret);
+ mdelay(100);
+ return ret;
+}
+
+
+/*****************************************************************************
+ *
+ * Video4Linux Helpers
+ *
+ *****************************************************************************/
+
+static int vicam_get_capability(struct usb_vicam *vicam, struct video_capability *b)
+{
+ dbg("vicam_get_capability");
+
+ strcpy(b->name, vicam->camera_name);
+ b->type = VID_TYPE_CAPTURE | VID_TYPE_MONOCHROME;
+ b->channels = 1;
+ b->audios = 0;
+
+ b->maxwidth = vicam->width[vicam->sizes-1];
+ b->maxheight = vicam->height[vicam->sizes-1];
+ b->minwidth = vicam->width[0];
+ b->minheight = vicam->height[0];
+
+ return 0;
+}
+
+static int vicam_get_channel(struct usb_vicam *vicam, struct video_channel *v)
+{
+ dbg("vicam_get_channel");
+
+ if (v->channel != 0)
+ return -EINVAL;
+
+ v->flags = 0;
+ v->tuners = 0;
+ v->type = VIDEO_TYPE_CAMERA;
+ strcpy(v->name, "Camera");
+
+ return 0;
+}
+
+static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v)
+{
+ dbg("vicam_set_channel");
+
+ if (v->channel != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm)
+{
+ int i;
+
+ dbg("vicam_get_mmapbuffer");
+
+ memset(vm, 0, sizeof(vm));
+ vm->size = VICAM_NUMFRAMES * vicam->maxframesize;
+ vm->frames = VICAM_NUMFRAMES;
+
+ for (i=0; i<VICAM_NUMFRAMES; i++)
+ vm->offsets[i] = vicam->maxframesize * i;
+
+ return 0;
+}
+
+static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p)
+{
+ dbg("vicam_get_picture");
+
+ /* This is probably where that weird 0x56 call goes */
+ p->brightness = vicam->win.brightness;
+ p->hue = vicam->win.hue;
+ p->colour = vicam->win.colour;
+ p->contrast = vicam->win.contrast;
+ p->whiteness = vicam->win.whiteness;
+ p->depth = vicam->win.depth;
+ p->palette = vicam->win.palette;
+
+ return 0;
+}
+
+static void synchronize(struct usb_vicam *vicam)
+{
+ change_pending = 1;
+ interruptible_sleep_on(&vicam->wait);
+ vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
+ mdelay(10);
+ vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
+ mdelay(10);
+}
+
+static void params_changed(struct usb_vicam *vicam)
+{
+#if 1
+ synchronize(vicam);
+ mdelay(10);
+ vicam_parameters(vicam);
+ printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+#endif
+}
+
+static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p)
+{
+ int changed = 0;
+ info("vicam_set_picture (%d)", p->brightness);
+
+
+#define SET(x) \
+ if (vicam->win.x != p->x) \
+ vicam->win.x = p->x, changed = 1;
+ SET(brightness);
+ SET(hue);
+ SET(colour);
+ SET(contrast);
+ SET(whiteness);
+ SET(depth);
+ SET(palette);
+ if (changed)
+ params_changed(vicam);
+
+ return 0;
+ /* Investigate what should be done maybe 0x56 type call */
+ if (p->depth != 8) return 1;
+ if (p->palette != VIDEO_PALETTE_GREY) return 1;
+
+ return 0;
+}
+
+/* FIXME - vicam_sync_frame - important */
+static int vicam_sync_frame(struct usb_vicam *vicam, int frame)
+{
+ dbg("vicam_sync_frame");
+
+ if(frame <0 || frame >= VICAM_NUMFRAMES)
+ return -EINVAL;
+
+ /* Probably need to handle various cases */
+/* ret=vicam_newframe(vicam, frame);
+ vicam->frame[frame].grabstate=FRAME_UNUSED;
+*/
+ return 0;
+}
+
+static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw)
+{
+ dbg("vicam_get_window");
+
+ vw->x = 0;
+ vw->y = 0;
+ vw->chromakey = 0;
+ vw->flags = 0;
+ vw->clipcount = 0;
+ vw->width = vicam->win.width;
+ vw->height = vicam->win.height;
+
+ return 0;
+}
+
+static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw)
+{
+ info("vicam_set_window");
+
+ if (vw->flags)
+ return -EINVAL;
+ if (vw->clipcount)
+ return -EINVAL;
+
+ if (vicam->win.width == vw->width && vicam->win.height == vw->height)
+ return 0;
+
+ /* Pick largest mode that is smaller than specified res */
+ /* If specified res is too small reject */
+
+ /* Add urb send to device... */
+
+ vicam->win.width = vw->width;
+ vicam->win.height = vw->height;
+ params_changed(vicam);
+
+ return 0;
+}
+
+/* FIXME - vicam_mmap_capture - important */
+static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm)
+{
+ dbg("vicam_mmap_capture");
+
+ /* usbvideo.c looks good for using here */
+
+ /*
+ if (vm->frame >= VICAM_NUMFRAMES)
+ return -EINVAL;
+ if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED)
+ return -EBUSY;
+ vicam->frame[vm->frame].grabstate=FRAME_READY;
+ */
+
+ /* No need to vicam_set_window here according to Alan */
+
+ /*
+ if (!vicam->streaming)
+ vicam_start_stream(vicam);
+ */
+
+ /* set frame as ready */
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * Video4Linux
+ *
+ *****************************************************************************/
+
+static int vicam_v4l_open(struct video_device *vdev, int flags)
+{
+ struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+ int err = 0;
+
+ dbg("vicam_v4l_open");
+
+ MOD_INC_USE_COUNT;
+ down(&vicam->sem);
+
+ if (vicam->open_count) /* Maybe not needed? */
+ err = -EBUSY;
+ else {
+ vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES);
+ if (!vicam->fbuf)
+ err=-ENOMEM;
+ else {
+ vicam->open_count = 1;
+ }
+#ifdef BLINKING
+ vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
+ info ("led on");
+ vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
+#endif
+ }
+
+ up(&vicam->sem);
+ if (err)
+ MOD_DEC_USE_COUNT;
+ return err;
+}
+
+static void vicam_v4l_close(struct video_device *vdev)
+{
+ struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+
+ dbg("vicam_v4l_close");
+
+ down(&vicam->sem);
+
+#ifdef BLINKING
+ info ("led off");
+ vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
+// vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); Leave it on
+#endif
+
+ rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES);
+ vicam->fbuf = 0;
+ vicam->open_count=0;
+
+ up(&vicam->sem);
+ /* Why does se401.c have a usbdevice check here? */
+ /* If device is unplugged while open, I guess we only may unregister now */
+ MOD_DEC_USE_COUNT;
+}
+
+static long vicam_v4l_read(struct video_device *vdev, char *user_buf, unsigned long buflen, int noblock)
+{
+ //struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+
+ dbg("vicam_v4l_read(%ld)", buflen);
+
+ if (!vdev || !buf)
+ return -EFAULT;
+
+ if (copy_to_user(user_buf, buf2, buflen))
+ return -EFAULT;
+ return buflen;
+}
+
+static long vicam_v4l_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
+{
+ info("vicam_v4l_write");
+ return -EINVAL;
+}
+
+static int vicam_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+{
+ struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+ int ret = -EL3RST;
+
+ if (!vicam->udev)
+ return -EIO;
+
+ down(&vicam->sem);
+
+ switch (cmd) {
+ case VIDIOCGCAP:
+ {
+ struct video_capability b;
+ ret = vicam_get_capability(vicam,&b);
+ dbg("name %s",b.name);
+ if (copy_to_user(arg, &b, sizeof(b)))
+ ret = -EFAULT;
+ }
+ case VIDIOCGFBUF:
+ {
+ struct video_buffer vb;
+ info("vicam_v4l_ioctl - VIDIOCGBUF - query frame buffer param");
+ /* frame buffer not supported, not used */
+ memset(&vb, 0, sizeof(vb));
+ vb.base = NULL;
+
+ /* FIXME - VIDIOCGFBUF - why the void */
+ if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
+ ret = -EFAULT;
+ ret = 0;
+ }
+ case VIDIOCGWIN:
+ {
+ struct video_window vw;
+ ret = vicam_get_window(vicam, &vw);
+ if (copy_to_user(arg, &vw, sizeof(vw)))
+ ret = -EFAULT;
+ }
+ case VIDIOCSWIN:
+ {
+ struct video_window vw;
+ if (copy_from_user(&vw, arg, sizeof(vw)))
+ ret = -EFAULT;
+ else
+ ret = vicam_set_window(vicam, &vw);
+ return ret;
+ }
+ case VIDIOCGCHAN:
+ {
+ struct video_channel v;
+
+ if (copy_from_user(&v, arg, sizeof(v)))
+ ret = -EFAULT;
+ else {
+ ret = vicam_get_channel(vicam,&v);
+ if (copy_to_user(arg, &v, sizeof(v)))
+ ret = -EFAULT;
+ }
+ }
+ case VIDIOCSCHAN:
+ {
+ struct video_channel v;
+ if (copy_from_user(&v, arg, sizeof(v)))
+ ret = -EFAULT;
+ else
+ ret = vicam_set_channel(vicam,&v);
+ }
+ case VIDIOCGPICT:
+ {
+ struct video_picture p;
+ ret = vicam_get_picture(vicam, &p);
+ if (copy_to_user(arg, &p, sizeof(p)))
+ ret = -EFAULT;
+ }
+ case VIDIOCSPICT:
+ {
+ struct video_picture p;
+ if (copy_from_user(&p, arg, sizeof(p)))
+ ret = -EFAULT;
+ else
+ ret = vicam_set_picture(vicam, &p);
+ }
+ case VIDIOCGMBUF:
+ {
+ struct video_mbuf vm;
+ ret = vicam_get_mmapbuffer(vicam,&vm);
+ /* FIXME - VIDIOCGMBUF - why the void */
+ if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+ ret = -EFAULT;
+ }
+ case VIDIOCMCAPTURE:
+ {
+ struct video_mmap vm;
+ ret = vicam_mmap_capture(vicam, &vm);
+ /* FIXME: This is probably not right */
+ }
+ case VIDIOCSYNC:
+ {
+ int frame;
+ /* FIXME - VIDIOCSYNC - why the void */
+ if (copy_from_user((void *)&frame, arg, sizeof(int)))
+ ret = -EFAULT;
+ else
+ ret = vicam_sync_frame(vicam,frame);
+ }
+
+ case VIDIOCKEY:
+ ret = 0;
+
+ case VIDIOCCAPTURE:
+ case VIDIOCSFBUF:
+ case VIDIOCGTUNER:
+ case VIDIOCSTUNER:
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
+ case VIDIOCGAUDIO:
+ case VIDIOCSAUDIO:
+ case VIDIOCGUNIT:
+ ret = -EINVAL;
+
+ default:
+ {
+ info("vicam_v4l_ioctl - %ui",cmd);
+ ret = -ENOIOCTLCMD;
+ }
+ } /* end switch */
+
+ up(&vicam->sem);
+ return ret;
+}
+
+static int vicam_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+ struct usb_vicam *vicam = (struct usb_vicam *)dev;
+ unsigned long start = (unsigned long)adr;
+ unsigned long page, pos;
+
+ down(&vicam->sem);
+
+ if (vicam->udev == NULL) {
+ up(&vicam->sem);
+ return -EIO;
+ }
+#if 0
+ if (size > (((VICAM_NUMFRAMES * vicam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
+ up(&vicam->sem);
+ return -EINVAL;
+ }
+#endif
+ pos = (unsigned long)vicam->fbuf;
+ while (size > 0) {
+ page = kvirt_to_pa(pos);
+ if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+ up(&vicam->sem);
+ return -EAGAIN;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+ up(&vicam->sem);
+
+ return 0;
+}
+
+/* FIXME - vicam_v4l_init */
+static int vicam_v4l_init(struct video_device *dev)
+{
+ /* stick proc fs stuff in here if wanted */
+ dbg("vicam_v4l_init");
+ return 0;
+}
+
+/* FIXME - vicam_template - important */
+static struct video_device vicam_template = {
+ name: "vicam USB camera",
+ type: VID_TYPE_CAPTURE,
+ hardware: VID_HARDWARE_SE401, /* need to ask for own id */
+ open: vicam_v4l_open,
+ close: vicam_v4l_close,
+ read: vicam_v4l_read,
+ write: vicam_v4l_write,
+ ioctl: vicam_v4l_ioctl,
+ mmap: vicam_v4l_mmap,
+ initialize: vicam_v4l_init,
+};
+
+/******************************************************************************
+ *
+ * Some Routines
+ *
+ ******************************************************************************/
+
+/*
+Flash the led
+vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
+info ("led on");
+vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
+info ("led off");
+vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
+vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
+*/
+
+static void vicam_bulk(struct urb *urb)
+{
+ struct usb_vicam *vicam = urb->context;
+
+ /* if (!vicam || !vicam->dev || !vicam->used)
+ return;
+ */
+
+ if (urb->status)
+ printk("vicam%d: nonzero read/write bulk status received: %d",
+ 0, urb->status);
+
+ urb->actual_length = 0;
+ urb->dev = vicam->udev;
+
+ memcpy(buf2, buf+64, 0x1e480);
+ if (vicam->fbuf)
+ memcpy(vicam->fbuf, buf+64, 0x1e480);
+
+ if (!change_pending) {
+ if (usb_submit_urb(urb))
+ dbg("failed resubmitting read urb");
+ } else {
+ change_pending = 0;
+ wake_up_interruptible(&vicam->wait);
+ }
+}
+
+static int vicam_parameters(struct usb_vicam *vicam)
+{
+ unsigned char req[0x10];
+ unsigned int shutter;
+ shutter = 10;
+
+ switch (vicam->win.width) {
+ case 512:
+ default:
+ memcpy(req, s512x242bw, 0x10);
+ break;
+ case 256:
+ memcpy(req, s256x242bw, 0x10);
+ break;
+ case 128:
+ memcpy(req, s128x122bw, 0x10);
+ break;
+ }
+
+
+ mdelay(10);
+ vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
+ info ("led on");
+ vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
+
+ mdelay(10);
+
+ shutter = vicam->win.contrast / 256;
+ if (shutter == 0)
+ shutter = 1;
+ printk("vicam_parameters: brightness %d, shutter %d\n", vicam->win.brightness, shutter );
+ req[0] = vicam->win.brightness /256;
+ shutter = 15600/shutter - 1;
+ req[6] = shutter & 0xff;
+ req[7] = (shutter >> 8) & 0xff;
+ vicam_sndctrl(1, vicam, VICAM_REQ_CAPTURE, 0x80, req, 0x10);
+ mdelay(10);
+ vicam_sndctrl(0, vicam, VICAM_REQ_GET_SOMETHIN, 0, buf, 0x10);
+ mdelay(10);
+
+ return 0;
+}
+
+static int vicam_init(struct usb_vicam *vicam)
+{
+ int width[] = {128, 256, 512};
+ int height[] = {122, 242, 242};
+
+ dbg("vicam_init");
+ buf = kmalloc(0x1e480, GFP_KERNEL);
+ buf2 = kmalloc(0x1e480, GFP_KERNEL);
+ if ((!buf) || (!buf2)) {
+ printk("Not enough memory for vicam!\n");
+ goto error;
+ }
+
+ /* do we do aspect correction in kernel or not? */
+ vicam->sizes = 3;
+ vicam->width = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL);
+ vicam->height = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL);
+ memcpy(vicam->width, &width, sizeof(width));
+ memcpy(vicam->height, &height, sizeof(height));
+ vicam->maxframesize = vicam->width[vicam->sizes-1] * vicam->height[vicam->sizes-1];
+
+ /* Download firmware to camera */
+ vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware1, sizeof(firmware1));
+ vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex1, sizeof(findex1));
+ vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup));
+ vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware2, sizeof(firmware2));
+ vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex2, sizeof(findex2));
+ vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup));
+
+ vicam_parameters(vicam);
+
+ FILL_BULK_URB(&vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
+ buf, 0x1e480, vicam_bulk, vicam);
+ printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+
+ return 0;
+error:
+ if (buf)
+ kfree(buf);
+ if (buf2)
+ kfree(buf2);
+ return 1;
+}
+
+static void * __devinit vicam_probe(struct usb_device *udev, unsigned int ifnum,
+ const struct usb_device_id *id)
+{
+ struct usb_vicam *vicam;
+ char *camera_name=NULL;
+
+ dbg("vicam_probe");
+
+ /* See if the device offered us matches what we can accept */
+ if ((udev->descriptor.idVendor != USB_VICAM_VENDOR_ID) ||
+ (udev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) {
+ return NULL;
+ }
+
+ camera_name="3Com HomeConnect USB";
+ info("ViCAM camera found: %s", camera_name);
+
+ vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL);
+ if (vicam == NULL) {
+ err ("couldn't kmalloc vicam struct");
+ return NULL;
+ }
+ memset(vicam, 0, sizeof(*vicam));
+
+ vicam->udev = udev;
+ vicam->camera_name = camera_name;
+ vicam->win.brightness = 128;
+ vicam->win.contrast = 10;
+
+ /* FIXME */
+ if (vicam_init(vicam))
+ return NULL;
+ memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template));
+ memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name));
+
+ if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+ err("video_register_device");
+ return NULL;
+ }
+
+ info("registered new video device: video%d", vicam->vdev.minor);
+
+ init_MUTEX (&vicam->sem);
+ init_waitqueue_head(&vicam->wait);
+
+ return vicam;
+}
+
+
+/* FIXME - vicam_disconnect - important */
+static void vicam_disconnect(struct usb_device *udev, void *ptr)
+{
+ struct usb_vicam *vicam;
+
+ vicam = (struct usb_vicam *) ptr;
+
+ if (!vicam->open_count)
+ video_unregister_device(&vicam->vdev);
+ vicam->udev = NULL;
+/*
+ vicam->frame[0].grabstate = FRAME_ERROR;
+ vicam->frame[1].grabstate = FRAME_ERROR;
+*/
+
+ /* Free buffers and shit */
+
+ info("%s disconnected", vicam->camera_name);
+ synchronize(vicam);
+
+ if (!vicam->open_count) {
+ /* Other random junk */
+ kfree(vicam);
+ vicam = NULL;
+ }
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver vicam_driver = {
+ name: "vicam",
+ probe: vicam_probe,
+ disconnect: vicam_disconnect,
+ id_table: vicam_table,
+};
+
+/******************************************************************************
+ *
+ * Module Routines
+ *
+ ******************************************************************************/
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/* Module paramaters */
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+static int __init usb_vicam_init(void)
+{
+ int result;
+
+ printk("VICAM: initializing\n");
+ /* register this driver with the USB subsystem */
+ result = usb_register(&vicam_driver);
+ if (result < 0) {
+ err("usb_register failed for the "__FILE__" driver. Error number %d",
+ result);
+ return -1;
+ }
+
+ info(DRIVER_VERSION " " DRIVER_AUTHOR);
+ info(DRIVER_DESC);
+ return 0;
+}
+
+static void __exit usb_vicam_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&vicam_driver);
+}
+
+module_init(usb_vicam_init);
+module_exit(usb_vicam_exit);
--- /dev/null
+/*
+ *
+ * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver
+ * Christopher L Cheney (C) 2001
+ *
+ */
+
+#ifndef __LINUX_VICAM_H
+#define __LINUX_VICAM_H
+
+
+#ifdef CONFIG_USB_DEBUG
+ static int debug = 1;
+#else
+ static int debug;
+#endif
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)
+
+#define VICAM_NUMFRAMES 30
+#define VICAM_NUMSBUF 1
+
+/* USB REQUEST NUMBERS */
+#define VICAM_REQ_VENDOR 0xff
+#define VICAM_REQ_CAMERA_POWER 0x50
+#define VICAM_REQ_CAPTURE 0x51
+#define VICAM_REQ_LED_CONTROL 0x55
+#define VICAM_REQ_GET_SOMETHIN 0x56
+
+/* not required but lets you know camera is on */
+/* camera must be on to turn on led */
+/* 0x01 always on 0x03 on when picture taken (flashes) */
+
+struct picture_parm
+{
+ int width;
+ int height;
+ int brightness;
+ int hue;
+ int colour;
+ int contrast;
+ int whiteness;
+ int depth;
+ int palette;
+};
+
+struct vicam_scratch {
+ unsigned char *data;
+ volatile int state;
+ int offset;
+ int length;
+};
+
+/* Structure to hold all of our device specific stuff */
+struct usb_vicam
+{
+ struct video_device vdev;
+ struct usb_device *udev;
+
+ int open_count; /* number of times this port has been opened */
+ struct semaphore sem; /* locks this structure */
+ wait_queue_head_t wait; /* Processes waiting */
+
+ int streaming;
+
+ /* v4l stuff */
+ char *camera_name;
+ char *fbuf;
+ urb_t *urb[VICAM_NUMSBUF];
+ int sizes;
+ int *width;
+ int *height;
+ int maxframesize;
+ struct picture_parm win;
+ struct proc_dir_entry *proc_entry; /* /proc/se401/videoX */
+ struct urb readurb;
+};
+
+#endif
--- /dev/null
+/*
+ *
+ * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver
+ * Christopher L Cheney (C) 2001
+ *
+ */
+
+
+#ifndef __LINUX_VICAMURBS_H
+#define __LINUX_VICAMURBS_H
+
+/* -------------------------------------------------------------------------- */
+
+/* FIXME - Figure out transfers so that this doesn't need to be here
+ *
+ * Notice: in pieces below, "0" means other code will fill it while "0x00" means this is zero */
+
+/* Request 0x51 Image Setup */
+
+/* 128x98 ? 0x3180 size */
+static unsigned char s128x98bw[] = {
+ 0, 0x34, 0xC4, 0x00, 0x00, 0x00, 0, 0,
+ 0x18, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
+};
+
+/* 128x122 3D80 size */
+static unsigned char s128x122bw[] = {
+ 0, 0x34, 0xF4, 0x00, 0x00, 0x00, 0, 0,
+ 0x00, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
+};
+
+/* 256x242 ? 0xF280 size */
+static unsigned char s256x242bw[] = {
+ 0, 0x03, 0xC8, 0x03, 0x00, 0x00, 0, 0,
+ 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
+};
+
+/* 512x242 0x1E480 size */
+static unsigned char s512x242bw[] = {
+ 0, 0x05, 0x90, 0x07, 0x00, 0x00, 0, 0,
+ 0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
+};
+
+/* In s512x242:
+ byte 0: gain -- higher number means brighter image
+ byte 6, 7: shutter speed, little-endian; set this to 15600 * (shutter speed) - 1. (Where shutter speed is something like 1/1000).
+*/
+
+/* -------------------------------------------------------------------------- */
+
+static unsigned char fsetup[] = {
+ 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64,
+
+ 0x00, 0x00
+};
+
+static unsigned char firmware1[] = {
+ 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64,
+
+ 0xE7, 0x67, 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09,
+ 0xDE, 0x00, 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03,
+ 0xC0, 0x17, 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07,
+ 0x00, 0x00, 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
+};
+
+static unsigned char findex1[] = {
+ 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64,
+
+ 0x18, 0x00, 0x00, 0x00
+};
+
+static unsigned char firmware2[] = {
+ 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64,
+
+ 0xE7, 0x07, 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07,
+ 0x00, 0x00, 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01,
+ 0xAA, 0x00, 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00,
+ 0xE7, 0x07, 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07,
+ 0x7C, 0x00, 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00,
+ 0x18, 0x00, 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0,
+ 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07,
+ 0xFF, 0xFF, 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00,
+ 0x24, 0xC0, 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0,
+ 0xE7, 0x07, 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87,
+ 0x01, 0x00, 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09,
+ 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0,
+ 0x09, 0xC1, 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01,
+ 0xE7, 0x09, 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07,
+ 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0,
+ 0xC0, 0xDF, 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00,
+ 0x17, 0x02, 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77,
+ 0x01, 0x00, 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57,
+ 0xFF, 0xFF, 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57,
+ 0x00, 0x00, 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF,
+ 0xC6, 0x00, 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05,
+ 0xC1, 0x05, 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF,
+ 0x27, 0xDA, 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00,
+ 0x0B, 0x06, 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01,
+ 0x9F, 0xAF, 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09,
+ 0xFC, 0x05, 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06,
+ 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0,
+ 0xE7, 0x09, 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09,
+ 0x02, 0x06, 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06,
+ 0xFC, 0x05, 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06,
+ 0x27, 0xDA, 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00,
+ 0xFA, 0x05, 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF,
+ 0x9F, 0xAF, 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07,
+ 0x40, 0x00, 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05,
+ 0x9F, 0xAF, 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17,
+ 0x02, 0x00, 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06,
+ 0x9F, 0xA0, 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00,
+ 0x09, 0x06, 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57,
+ 0x01, 0x00, 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03,
+ 0xE7, 0x07, 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF,
+ 0x47, 0xAF, 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07,
+ 0x2E, 0x00, 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00,
+ 0x09, 0x06, 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00,
+ 0xC0, 0x57, 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02,
+ 0xC0, 0x57, 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57,
+ 0x55, 0x00, 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00,
+ 0x9F, 0xC0, 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02,
+ 0xC1, 0x0B, 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90,
+ 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B,
+ 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF,
+ 0x2F, 0x0E, 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07,
+ 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF,
+ 0x28, 0x05, 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E,
+ 0x02, 0x00, 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00,
+ 0x09, 0x06, 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67,
+ 0x7F, 0xFF, 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD,
+ 0x22, 0xC0, 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0,
+ 0xE7, 0x87, 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF,
+ 0xB8, 0x05, 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0,
+ 0x9F, 0xAF, 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00,
+ 0x24, 0xC0, 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0,
+ 0xC8, 0x07, 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00,
+ 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+ 0x9F, 0xAF, 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00,
+ 0x9F, 0xAF, 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE,
+ 0x24, 0xC0, 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87,
+ 0x00, 0x01, 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02,
+ 0x0F, 0xC1, 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0,
+ 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
+ 0x08, 0x00, 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1,
+ 0xEF, 0x07, 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF,
+ 0xEF, 0x07, 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF,
+ 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07,
+ 0x00, 0x00, 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF,
+ 0x09, 0x06, 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06,
+ 0xE7, 0x67, 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67,
+ 0x17, 0xD8, 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00,
+ 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0,
+ 0x97, 0xCF, 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF,
+ 0xDA, 0x02, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05,
+ 0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07,
+ 0x0E, 0x06, 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02,
+ 0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07,
+ 0x00, 0x80, 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C,
+ 0x02, 0x00, 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00,
+ 0x06, 0x06, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05,
+ 0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07,
+ 0xE2, 0x05, 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02,
+ 0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07,
+ 0x00, 0x80, 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF,
+ 0x66, 0x04, 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF,
+ 0x97, 0xCF, 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B,
+ 0x0C, 0x06, 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05,
+ 0xC0, 0x07, 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05,
+ 0x68, 0x00, 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF,
+ 0x44, 0x05, 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00,
+ 0xE0, 0x07, 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06,
+ 0xE8, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02,
+ 0xE0, 0x07, 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF,
+ 0x97, 0xCF, 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05,
+ 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07,
+ 0x0E, 0x06, 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06,
+ 0xFE, 0x05, 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01,
+ 0xE7, 0x07, 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07,
+ 0x07, 0x00, 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07,
+ 0x02, 0x00, 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01,
+ 0xEF, 0x77, 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0,
+ 0x14, 0x04, 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06,
+ 0x37, 0xC0, 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06,
+ 0x0F, 0xC1, 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06,
+ 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
+ 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00,
+ 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+ 0xC8, 0x07, 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05,
+ 0xC0, 0x07, 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05,
+ 0xC1, 0x77, 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA,
+ 0x75, 0xC1, 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1,
+ 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00,
+ 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00,
+ 0x06, 0x06, 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00,
+ 0xC1, 0x07, 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+ 0xEF, 0x07, 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF,
+ 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57,
+ 0x01, 0x00, 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07,
+ 0x01, 0x00, 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF,
+ 0x28, 0x05, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
+ 0x30, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
+ 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
+ 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67,
+ 0x03, 0x00, 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0,
+ 0x08, 0xDA, 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00,
+ 0xC1, 0x07, 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00,
+ 0x06, 0x06, 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00,
+ 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00,
+ 0xC1, 0x0B, 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05,
+ 0xC0, 0x07, 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05,
+ 0xE7, 0x09, 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8,
+ 0xFA, 0x05, 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05,
+ 0xE7, 0x07, 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07,
+ 0x40, 0x00, 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05,
+ 0x9F, 0xAF, 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B,
+ 0xE2, 0x05, 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17,
+ 0x23, 0x00, 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07,
+ 0x04, 0x00, 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF,
+ 0x28, 0x05, 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09,
+ 0xE6, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+ 0x07, 0x00, 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1,
+ 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00,
+ 0xC1, 0x09, 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05,
+ 0xC0, 0x07, 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05,
+ 0xC1, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+ 0x0D, 0x00, 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF,
+ 0x28, 0x05, 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07,
+ 0x32, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+ 0x0F, 0x00, 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF,
+ 0x28, 0x05, 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9,
+ 0x24, 0xC0, 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00,
+ 0xC0, 0x67, 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0,
+ 0xE7, 0x87, 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67,
+ 0xFF, 0xF9, 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA,
+ 0x72, 0xC1, 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0,
+ 0x97, 0xCF, 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87,
+ 0xFF, 0x00, 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF,
+ 0x24, 0xC0, 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0,
+ 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF,
+ 0x9F, 0xAF, 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0,
+ 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
+ 0x40, 0x00, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
+ 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05,
+ 0xE7, 0x67, 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67,
+ 0xFF, 0xFE, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
+ 0x24, 0xC0, 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87,
+ 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07,
+ 0x40, 0x00, 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67,
+ 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
+ 0x24, 0xC0, 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0,
+ 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA,
+ 0xE8, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00,
+ 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
+ 0x00, 0xDA, 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1,
+ 0xE7, 0x87, 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF,
+ 0xE7, 0x07, 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77,
+ 0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF,
+ 0xE7, 0x07, 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77,
+ 0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF,
+ 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80,
+ 0x96, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static unsigned char findex2[] = {
+ 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64,
+
+ 0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00,
+ 0x26, 0x00, 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00,
+ 0x92, 0x00, 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00,
+ 0xB8, 0x00, 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00,
+ 0xCE, 0x00, 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00,
+ 0xE0, 0x00, 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00,
+ 0xEC, 0x00, 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01,
+ 0x0A, 0x01, 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01,
+ 0x22, 0x01, 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01,
+ 0x36, 0x01, 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01,
+ 0x72, 0x01, 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01,
+ 0x88, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01,
+ 0xA0, 0x01, 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01,
+ 0xB4, 0x01, 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01,
+ 0xF6, 0x01, 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02,
+ 0x3C, 0x02, 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02,
+ 0x56, 0x02, 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02,
+ 0x84, 0x02, 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02,
+ 0x8E, 0x02, 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02,
+ 0xAE, 0x02, 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02,
+ 0xC0, 0x02, 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02,
+ 0xD4, 0x02, 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02,
+ 0xF8, 0x02, 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03,
+ 0x24, 0x03, 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03,
+ 0x3C, 0x03, 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03,
+ 0x58, 0x03, 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03,
+ 0x7A, 0x03, 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03,
+ 0xB2, 0x03, 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03,
+ 0xD4, 0x03, 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03,
+ 0xFC, 0x03, 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04,
+ 0x32, 0x04, 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04,
+ 0x42, 0x04, 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04,
+ 0x54, 0x04, 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04,
+ 0x62, 0x04, 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04,
+ 0x80, 0x04, 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04,
+ 0x9A, 0x04, 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04,
+ 0xB4, 0x04, 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04,
+ 0x2A, 0x05, 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
+};
+
+#endif
/* XXX Should report error here? */
return fgc;
- if (MINOR(current->tty->device) < 1)
+ if (minor(current->tty->device) < 1)
return fgc;
- return MINOR(current->tty->device) - 1;
+ return minor(current->tty->device) - 1;
}
#if 1 /* to go away in 2.5.0 */
int GET_FB_IDX(kdev_t rdev)
{
- int fbidx = MINOR(rdev);
+ int fbidx = minor(rdev);
if (fbidx >= 32) {
int newfbidx = fbidx >> 5;
static int warned;
for (i = 0 ; i < FB_MAX; i++)
if (!registered_fb[i])
break;
- fb_info->node = MKDEV(FB_MAJOR, i);
+ fb_info->node = mk_kdev(FB_MAJOR, i);
registered_fb[i] = fb_info;
if (!fb_ever_opened[i]) {
struct module *owner = fb_info->fbops->owner;
strcpy(fb_info.modename, "VESA VGA");
fb_info.changevar = NULL;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &vesafb_ops;
fb_info.disp=&disp;
fb_info.switch_con=&vesafb_switch;
* blocks, we will have to change it.
*/
- blocks = blk_size[MAJOR(dev)] ? blk_size[MAJOR(dev)][MINOR(dev)] : 0;
+ blocks = blk_size[major(dev)] ? blk_size[major(dev)][minor(dev)] : 0;
if (!blocks) {
printk(KERN_ERR "AFFS: Could not determine device size\n");
goto out_error;
inode = file->f_dentry->d_inode;
if(!inode || !S_ISCHR(inode->i_mode) ||
- MAJOR(inode->i_rdev) != CODA_PSDEV_MAJOR) {
+ major(inode->i_rdev) != CODA_PSDEV_MAJOR) {
if(file)
fput(file);
return -1;
}
- idx = MINOR(inode->i_rdev);
+ idx = minor(inode->i_rdev);
fput(file);
if(idx < 0 || idx >= MAX_CODADEVS) {
struct buffer_head * read_array[BLKS_PER_BUF];
unsigned i, blocknr, buffer, unread;
unsigned long devsize;
- int major, minor;
+ unsigned int major, minor;
char *data;
}
devsize = ~0UL;
- major = MAJOR(sb->s_dev);
- minor = MINOR(sb->s_dev);
+ major = major(sb->s_dev);
+ minor = minor(sb->s_dev);
if (blk_size[major])
devsize = blk_size[major][minor] >> 2;
if ( ( new = _devfs_alloc_entry (".devfsd", 0, S_IFCHR |S_IRUSR |S_IWUSR) )
== NULL ) return NULL;
devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR);
- new->u.fcb.u.device.major = MAJOR (devnum);
- new->u.fcb.u.device.minor = MINOR (devnum);
+ new->u.fcb.u.device.major = major (devnum);
+ new->u.fcb.u.device.minor = minor (devnum);
new->u.fcb.ops = &devfsd_fops;
_devfs_append_entry (root_entry, new, FALSE, NULL);
#ifdef CONFIG_DEVFS_DEBUG
if ( ( new = _devfs_alloc_entry (".stat", 0, S_IFCHR | S_IRUGO | S_IWUGO) )
== NULL ) return NULL;
devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR);
- new->u.fcb.u.device.major = MAJOR (devnum);
- new->u.fcb.u.device.minor = MINOR (devnum);
+ new->u.fcb.u.device.major = major (devnum);
+ new->u.fcb.u.device.minor = minor (devnum);
new->u.fcb.ops = &stat_fops;
_devfs_append_entry (root_entry, new, FALSE, NULL);
#endif
name, S_ISCHR (mode) ? "char" : "block");
return NULL;
}
- major = MAJOR (devnum);
- minor = MINOR (devnum);
+ major = major (devnum);
+ minor = minor (devnum);
}
if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL )
{
semaphore = &block_semaphore;
list = &block_list;
}
- major = MAJOR (devnum);
- minor = MINOR (devnum);
+ major = major (devnum);
+ minor = minor (devnum);
down (semaphore);
for (entry = list->first; entry != NULL; entry = entry->next)
{
goto out;
}
- ret = -NODEV;
+ ret = -ENODEV;
if (sb && sb_has_quota_enabled(sb, type))
ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr);
out:
struct ext3_super_block * es;
int fatal = 0, err;
- if (!inode->i_dev) {
+ if (kdev_none(inode->i_dev)) {
printk ("ext3_free_inode: inode has no device\n");
return;
}
list_for_each(l, &sbi->s_orphan) {
struct inode *inode = orphan_list_entry(l);
printk(KERN_ERR " "
- "inode 0x%04x:%ld at %p: mode %o, nlink %d, next %d\n",
- inode->i_dev, inode->i_ino, inode,
+ "inode 0x%04x.0x%04x:%ld at %p: mode %o, nlink %d, next %d\n",
+ major(inode->i_dev), minor(inode->i_dev), inode->i_ino, inode,
inode->i_mode, inode->i_nlink,
le32_to_cpu(NEXT_ORPHAN(inode)));
}
J_ASSERT(list_empty(&sbi->s_orphan));
invalidate_buffers(sb->s_dev);
- if (j_dev != sb->s_dev) {
+ if (!kdev_same(j_dev, sb->s_dev)) {
/*
* Invalidate the journal device's buffers. We don't want them
* floating about in memory - the physical journal device may
sbi->s_resuid = EXT3_DEF_RESUID;
sbi->s_resgid = EXT3_DEF_RESGID;
if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0)) {
- sb->s_dev = 0;
+ sb->s_dev = NODEV;
goto out_fail;
}
}
static journal_t *ext3_get_dev_journal(struct super_block *sb,
- int dev)
+ kdev_t j_dev)
{
struct buffer_head * bh;
journal_t *journal;
int hblock, blocksize;
unsigned long sb_block;
unsigned long offset;
- kdev_t journal_dev = to_kdev_t(dev);
struct ext3_super_block * es;
struct block_device *bdev;
- bdev = ext3_blkdev_get(journal_dev);
+ bdev = ext3_blkdev_get(j_dev);
if (bdev == NULL)
return NULL;
blocksize = sb->s_blocksize;
- hblock = get_hardsect_size(journal_dev);
+ hblock = get_hardsect_size(j_dev);
if (blocksize < hblock) {
printk(KERN_ERR
"EXT3-fs: blocksize too small for journal device.\n");
sb_block = EXT3_MIN_BLOCK_SIZE / blocksize;
offset = EXT3_MIN_BLOCK_SIZE % blocksize;
- set_blocksize(dev, blocksize);
- if (!(bh = bread(dev, sb_block, blocksize))) {
+ set_blocksize(j_dev, blocksize);
+ if (!(bh = bread(j_dev, sb_block, blocksize))) {
printk(KERN_ERR "EXT3-fs: couldn't read superblock of "
"external journal\n");
goto out_bdev;
start = sb_block + 1;
brelse(bh); /* we're done with the superblock */
- journal = journal_init_dev(journal_dev, sb->s_dev,
+ journal = journal_init_dev(j_dev, sb->s_dev,
start, len, blocksize);
if (!journal) {
printk(KERN_ERR "EXT3-fs: failed to create device journal\n");
{
journal_t *journal;
int journal_inum = le32_to_cpu(es->s_journal_inum);
- int journal_dev = le32_to_cpu(es->s_journal_dev);
+ kdev_t journal_dev = to_kdev_t(le32_to_cpu(es->s_journal_dev));
int err = 0;
int really_read_only;
}
}
- if (journal_inum && journal_dev) {
+ if (journal_inum && !kdev_none(journal_dev)) {
printk(KERN_ERR "EXT3-fs: filesystem has both journal "
"and inode journals!\n");
return -EINVAL;
bhb = bhe = buflist;
if (reada) {
- if (blocks < read_ahead[MAJOR(dev)] / (HFS_SECTOR_SIZE>>9)) {
- blocks = read_ahead[MAJOR(dev)] / (HFS_SECTOR_SIZE>>9);
+ if (blocks < read_ahead[major(dev)] / (HFS_SECTOR_SIZE>>9)) {
+ blocks = read_ahead[major(dev)] / (HFS_SECTOR_SIZE>>9);
}
if (block + blocks > size) {
blocks = size - block;
{
int minor;
- if ( MAJOR(file->f_dentry->d_inode->i_rdev) != PRESTO_PSDEV_MAJOR ) {
+ if ( major(file->f_dentry->d_inode->i_rdev) != PRESTO_PSDEV_MAJOR ) {
EXIT;
return NULL;
}
- minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ minor = minor(file->f_dentry->d_inode->i_rdev);
if ( minor < 0 || minor >= MAX_PRESTODEV ) {
EXIT;
return NULL;
{
struct nameidata nd;
struct dentry *dentry;
- kdev_t devno = 0;
+ kdev_t devno = NODEV;
int error;
ENTRY;
}
devno = dentry->d_inode->i_rdev;
- if ( MAJOR(devno) != PRESTO_PSDEV_MAJOR ) {
+ if ( major(devno) != PRESTO_PSDEV_MAJOR ) {
EXIT;
goto out;
}
- if ( MINOR(devno) >= MAX_PRESTODEV ) {
+ if ( minor(devno) >= MAX_PRESTODEV ) {
EXIT;
goto out;
}
EXIT;
out:
- *minor = MINOR(devno);
+ *minor = minor(devno);
path_release(&nd);
return 0;
}
D1(printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n",
kdevname(dev)));
- if (MAJOR(dev) != MTD_BLOCK_MAJOR) {
+ if (major(dev) != MTD_BLOCK_MAJOR) {
printk(KERN_WARNING "JFFS: Trying to mount a "
"non-mtd device.\n");
return 0;
if ((mode & S_IFMT) == S_IFBLK ||
(mode & S_IFMT) == S_IFCHR) {
- dev = (MAJOR(to_kdev_t(rdev)) << 8) | MINOR(to_kdev_t(rdev));
+ dev = (MAJOR(rdev) << 8) | MINOR(rdev);
devlen = sizeof(dev);
}
if ((inode->i_mode & S_IFMT) == S_IFBLK ||
(inode->i_mode & S_IFMT) == S_IFCHR) {
/* For these, we don't actually need to read the old node */
- dev = (MAJOR(to_kdev_t(dentry->d_inode->i_rdev)) << 8) |
- MINOR(to_kdev_t(dentry->d_inode->i_rdev));
+ dev = (major(dentry->d_inode->i_rdev) << 8) |
+ minor(dentry->d_inode->i_rdev);
mdata = (char *)&dev;
mdatalen = sizeof(dev);
D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
if ((inode->i_mode & S_IFMT) == S_IFBLK ||
(inode->i_mode & S_IFMT) == S_IFCHR) {
/* For these, we don't actually need to read the old node */
- dev = (MAJOR(to_kdev_t(inode->i_rdev)) << 8) |
- MINOR(to_kdev_t(inode->i_rdev));
+ dev = (major(inode->i_rdev) << 8) |
+ minor(inode->i_rdev);
mdata = (char *)&dev;
mdatalen = sizeof(dev);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen));
D1(printk(KERN_DEBUG "jffs2: read_super for device %s\n", kdevname(sb->s_dev)));
- if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) {
+ if (major(sb->s_dev) != MTD_BLOCK_MAJOR) {
if (!silent)
printk(KERN_DEBUG "jffs2: attempt to mount non-MTD device %s\n", kdevname(sb->s_dev));
return NULL;
goto exit_lock;
error = -EXDEV;
- if (!kdev_same(dir->i_dev, inode->i_dev))
+ if (dir->i_sb != inode->i_sb)
goto exit_lock;
/*
if (error)
return error;
- if (!kdev_same(new_dir->i_dev, old_dir->i_dev))
+ if (new_dir->i_sb != old_dir->i_sb)
return -EXDEV;
if (!new_dentry->d_inode)
if (error)
return error;
- if (!kdev_same(new_dir->i_dev, old_dir->i_dev))
+ if (new_dir->i_sb != old_dir->i_sb)
return -EXDEV;
if (!new_dentry->d_inode)
inode->i_nlink = 1;
inode->i_uid = server->m.uid;
inode->i_gid = server->m.gid;
- inode->i_rdev = 0;
+ inode->i_rdev = NODEV;
inode->i_blksize = NCP_BLOCK_SIZE;
inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req);
- dprintk("NFS: commit (%x/%Ld %d@%Ld)",
- req->wb_inode->i_dev,
+ dprintk("NFS: commit (%02x:%02x/%Ld %d@%Ld)",
+ major(req->wb_inode->i_dev),
+ minor(req->wb_inode->i_dev),
(long long)NFS_FILEID(req->wb_inode),
req->wb_bytes,
(long long)(page_offset(req->wb_page) + req->wb_offset));
p = xdr_encode_hyper(p, (u64)(inode->i_size +511)& ~511);
else
p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
- *p++ = htonl((u32) MAJOR(inode->i_rdev));
- *p++ = htonl((u32) MINOR(inode->i_rdev));
- p = xdr_encode_hyper(p, (u64) inode->i_dev);
+ *p++ = htonl((u32) major(inode->i_rdev));
+ *p++ = htonl((u32) minor(inode->i_rdev));
+ p = xdr_encode_hyper(p, (u64) kdev_t_to_nr(inode->i_dev));
p = xdr_encode_hyper(p, (u64) inode->i_ino);
p = encode_time3(p, inode->i_atime);
p = encode_time3(p, lease_get_mtime(inode));
p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
}
p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
- *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
- *p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
- p = xdr_encode_hyper(p, (u64) inode->i_dev);
+ *p++ = htonl((u32) major(fhp->fh_post_rdev));
+ *p++ = htonl((u32) minor(fhp->fh_post_rdev));
+ p = xdr_encode_hyper(p, (u64) kdev_t_to_nr(inode->i_dev));
p = xdr_encode_hyper(p, (u64) inode->i_ino);
p = encode_time3(p, fhp->fh_post_atime);
p = encode_time3(p, fhp->fh_post_mtime);
extern void xd_set_geometry(kdev_t dev, unsigned char, unsigned char,
unsigned long, unsigned int);
- if (MAJOR(dev) == MFM_ACORN_MAJOR) {
+ if (major(dev) == MFM_ACORN_MAJOR) {
unsigned long totalblocks = hd->part[MINOR(dev)].nr_sects;
xd_set_geometry(dev, secspertrack, heads, totalblocks, 1);
}
return 0;
if (ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo);
return 0;
- blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
+ blocksize = hardsect_size[major(dev)][minor(dev)];
if ( blocksize <= 0 ) {
return 0;
}
default:
/* depending on MBZ for sock/fifos */
nextfh = ntohl(ri.spec);
- nextfh = kdev_t_to_nr(MKDEV(nextfh>>16,nextfh&0xffff));
+ /* convert back and forth for typechecking and
+ * source tagging */
+ nextfh = kdev_t_to_nr(mk_kdev(nextfh>>16,nextfh&0xffff));
init_special_inode(i, ino, nextfh);
}
}
ChangeLog for smbfs.
+2001-12-31 René Scharfe <l.s.r@web.de>
+
+ * inode.c: added smb_show_options to show mount options in /proc/mounts
+ * inode.c, getopt.c, getopt.h: merged flag and has_arg in struct option
+ * inode.c: use S_IRWXUGO where appropriate
+
+2001-12-22 Urban Widmark <urban@teststation.com>
+
+ * file.c, proc.c: Fix problems triggered by the "fsx test"
+
2001-09-17 Urban Widmark <urban@teststation.com>
* proc.c: Use 4096 (was 512) as the blocksize for better write
static int smb_prepare_write(struct file *file, struct page *page,
unsigned offset, unsigned to)
{
- kmap(page);
return 0;
}
lock_kernel();
status = smb_updatepage(file, page, offset, to-offset);
unlock_kernel();
- kunmap(page);
return status;
}
smb_file_release(struct inode *inode, struct file * file)
{
lock_kernel();
- if (!--inode->u.smbfs_i.openers)
+ if (!--inode->u.smbfs_i.openers) {
+ /* We must flush any dirty pages now as we won't be able to
+ write anything after close. mmap can trigger this.
+ "openers" should perhaps include mmap'ers ... */
+ filemap_fdatasync(inode->i_mapping);
+ filemap_fdatawait(inode->i_mapping);
smb_close(inode);
+ }
unlock_kernel();
return 0;
}
for (i = 0; opts[i].name != NULL; i++) {
if (!strcmp(opts[i].name, token)) {
- if (opts[i].has_arg && (!val || !*val)) {
+ if (!opts[i].flag && (!val || !*val)) {
printk("%s: the %s option requires an argument\n",
caller, token);
return -1;
struct option {
const char *name;
- int has_arg;
unsigned long flag;
int val;
};
#include <linux/dcache.h>
#include <linux/smp_lock.h>
#include <linux/nls.h>
+#include <linux/seq_file.h>
#include <linux/smb_fs.h>
#include <linux/smbno.h>
#define SMB_NLS_REMOTE ""
#endif
+#define SMB_TTL_DEFAULT 1000
+
static void smb_delete_inode(struct inode *);
static void smb_put_super(struct super_block *);
static int smb_statfs(struct super_block *, struct statfs *);
+static int smb_show_options(struct seq_file *, struct vfsmount *);
static struct super_operations smb_sops =
{
delete_inode: smb_delete_inode,
put_super: smb_put_super,
statfs: smb_statfs,
+ show_options: smb_show_options,
};
clear_inode(ino);
}
-/* FIXME: flags and has_arg could probably be merged. */
static struct option opts[] = {
- { "version", 1, 0, 'v' },
- { "win95", 0, SMB_MOUNT_WIN95, 1 },
- { "oldattr", 0, SMB_MOUNT_OLDATTR, 1 },
- { "dirattr", 0, SMB_MOUNT_DIRATTR, 1 },
- { "case", 0, SMB_MOUNT_CASE, 1 },
- { "uid", 1, 0, 'u' },
- { "gid", 1, 0, 'g' },
- { "file_mode", 1, 0, 'f' },
- { "dir_mode", 1, 0, 'd' },
- { "iocharset", 1, 0, 'i' },
- { "codepage", 1, 0, 'c' },
- { "ttl", 1, 0, 't' },
- { NULL, 0, 0, 0}
+ { "version", 0, 'v' },
+ { "win95", SMB_MOUNT_WIN95, 1 },
+ { "oldattr", SMB_MOUNT_OLDATTR, 1 },
+ { "dirattr", SMB_MOUNT_DIRATTR, 1 },
+ { "case", SMB_MOUNT_CASE, 1 },
+ { "uid", 0, 'u' },
+ { "gid", 0, 'g' },
+ { "file_mode", 0, 'f' },
+ { "dir_mode", 0, 'd' },
+ { "iocharset", 0, 'i' },
+ { "codepage", 0, 'c' },
+ { "ttl", 0, 't' },
+ { NULL, 0, 0}
};
static int
mnt->gid = value;
break;
case 'f':
- mnt->file_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO);
- mnt->file_mode |= S_IFREG;
+ mnt->file_mode = (value & S_IRWXUGO) | S_IFREG;
break;
case 'd':
- mnt->dir_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO);
- mnt->dir_mode |= S_IFDIR;
+ mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR;
break;
case 'i':
strncpy(mnt->codepage.local_name, optarg,
return c;
}
+/*
+ * smb_show_options() is for displaying mount options in /proc/mounts.
+ * It tries to avoid showing settings that were not changed from their
+ * defaults.
+ */
+static int
+smb_show_options(struct seq_file *s, struct vfsmount *m)
+{
+ struct smb_mount_data_kernel *mnt = m->mnt_sb->u.smbfs_sb.mnt;
+ int i;
+
+ for (i = 0; opts[i].name != NULL; i++)
+ if (mnt->flags & opts[i].flag)
+ seq_printf(s, ",%s", opts[i].name);
+
+ if (mnt->uid != 0)
+ seq_printf(s, ",uid=%d", mnt->uid);
+ if (mnt->gid != 0)
+ seq_printf(s, ",gid=%d", mnt->gid);
+ if (mnt->mounted_uid != 0)
+ seq_printf(s, ",mounted_uid=%d", mnt->mounted_uid);
+
+ /*
+ * Defaults for file_mode and dir_mode are unknown to us; they
+ * depend on the current umask of the user doing the mount.
+ */
+ seq_printf(s, ",file_mode=%04o", mnt->file_mode & S_IRWXUGO);
+ seq_printf(s, ",dir_mode=%04o", mnt->dir_mode & S_IRWXUGO);
+
+ if (strcmp(mnt->codepage.local_name, CONFIG_NLS_DEFAULT))
+ seq_printf(s, ",iocharset=%s", mnt->codepage.local_name);
+ if (strcmp(mnt->codepage.remote_name, SMB_NLS_REMOTE))
+ seq_printf(s, ",codepage=%s", mnt->codepage.remote_name);
+
+ if (mnt->ttl != SMB_TTL_DEFAULT)
+ seq_printf(s, ",ttl=%d", mnt->ttl);
+
+ return 0;
+}
static void
smb_put_super(struct super_block *sb)
strncpy(mnt->codepage.remote_name, SMB_NLS_REMOTE,
SMB_NLS_MAXNAMELEN);
- mnt->ttl = 1000;
+ mnt->ttl = SMB_TTL_DEFAULT;
if (ver == SMB_MOUNT_OLDVERSION) {
mnt->version = oldmnt->version;
mnt->uid = oldmnt->uid;
mnt->gid = oldmnt->gid;
- mnt->file_mode =
- oldmnt->file_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
- mnt->dir_mode =
- oldmnt->dir_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
- mnt->file_mode |= S_IFREG;
- mnt->dir_mode |= S_IFDIR;
+ mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG;
+ mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR;
mnt->flags = (oldmnt->file_mode >> 9);
} else {
{
struct inode *inode = dentry->d_inode;
struct smb_sb_info *server = server_from_dentry(dentry);
- unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
+ unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXUGO);
int error, changed, refresh = 0;
struct smb_fattr fattr;
VERBOSE("changing %s/%s, old size=%ld, new size=%ld\n",
DENTRY_PATH(dentry),
(long) inode->i_size, (long) attr->ia_size);
+
+ filemap_fdatasync(inode->i_mapping);
+ filemap_fdatawait(inode->i_mapping);
+
error = smb_open(dentry, O_WRONLY);
if (error)
goto out;
void UMSDOS_put_super (struct super_block *sb)
{
Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n"));
- if (saved_root && pseudo_root && sb->s_dev == ROOT_DEV) {
+ if (saved_root && pseudo_root && kdev_same(sb->s_dev, ROOT_DEV)) {
shrink_dcache_parent(saved_root);
dput(saved_root);
saved_root = NULL;
* must check like this, because we can be used with initrd
*/
- if (sb->s_dev != ROOT_DEV)
+ if (!kdev_same(sb->s_dev, ROOT_DEV))
goto out_noroot;
/*
#define _BLK_H
#include <linux/blkdev.h>
+#include <linux/elevator.h>
#include <linux/locks.h>
#include <linux/config.h>
#include <linux/spinlock.h>
static inline void blkdev_dequeue_request(struct request *req)
{
list_del(&req->queuelist);
-}
-#define __elv_next_request(q) (q)->elevator.elevator_next_req_fn((q))
+ if (req->q)
+ elv_remove_request(req->q, req);
+}
extern inline struct request *elv_next_request(request_queue_t *q)
{
return rq;
}
-#define __elv_add_request_core(q, rq, where, plug) \
+#define _elv_add_request_core(q, rq, where, plug) \
do { \
if ((plug)) \
blk_plug_device((q)); \
(q)->elevator.elevator_add_req_fn((q), (rq), (where)); \
} while (0)
-#define __elv_add_request(q, rq, back, p) do { \
+#define _elv_add_request(q, rq, back, p) do { \
if ((back)) \
- __elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \
+ _elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \
else \
- __elv_add_request_core((q), (rq), &(q)->queue_head, 0); \
+ _elv_add_request_core((q), (rq), &(q)->queue_head, 0); \
} while (0)
-#define elv_add_request(q, rq, back) __elv_add_request((q), (rq), (back), 1)
+#define elv_add_request(q, rq, back) _elv_add_request((q), (rq), (back), 1)
#if defined(MAJOR_NR) || defined(IDE_DRIVER)
struct list_head queuelist; /* looking for ->queue? you must _not_
* access it directly, use
* blkdev_dequeue_request! */
- int elevator_sequence;
+ void *elevator_private;
unsigned char cmd[16];
typedef struct request *(elevator_next_req_fn) (request_queue_t *);
typedef void (elevator_add_req_fn) (request_queue_t *, struct request *, struct list_head *);
+typedef int (elevator_queue_empty_fn) (request_queue_t *);
+typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *);
typedef int (elevator_init_fn) (request_queue_t *, elevator_t *);
typedef void (elevator_exit_fn) (request_queue_t *, elevator_t *);
struct elevator_s
{
- int latency[2];
-
elevator_merge_fn *elevator_merge_fn;
elevator_merge_cleanup_fn *elevator_merge_cleanup_fn;
elevator_merge_req_fn *elevator_merge_req_fn;
elevator_next_req_fn *elevator_next_req_fn;
elevator_add_req_fn *elevator_add_req_fn;
+ elevator_remove_req_fn *elevator_remove_req_fn;
+
+ elevator_queue_empty_fn *elevator_queue_empty_fn;
elevator_init_fn *elevator_init_fn;
elevator_exit_fn *elevator_exit_fn;
+
+ void *elevator_data;
};
-int elevator_noop_merge(request_queue_t *, struct request **, struct bio *);
-void elevator_noop_merge_cleanup(request_queue_t *, struct request *, int);
-void elevator_noop_merge_req(struct request *, struct request *);
+/*
+ * block elevator interface
+ */
+extern void __elv_add_request(request_queue_t *, struct request *,
+ struct list_head *);
+extern struct request *__elv_next_request(request_queue_t *);
+extern void elv_merge_cleanup(request_queue_t *, struct request *, int);
+extern int elv_merge(request_queue_t *, struct request **, struct bio *);
+extern void elv_merge_requests(request_queue_t *, struct request *,
+ struct request *);
+extern void elv_remove_request(request_queue_t *, struct request *);
+
+/*
+ * noop I/O scheduler. always merges, always inserts new request at tail
+ */
+extern elevator_t elevator_noop;
-int elevator_linus_merge(request_queue_t *, struct request **, struct bio *);
-void elevator_linus_merge_cleanup(request_queue_t *, struct request *, int);
-void elevator_linus_merge_req(struct request *, struct request *);
-int elv_linus_init(request_queue_t *, elevator_t *);
-void elv_linus_exit(request_queue_t *, elevator_t *);
-struct request *elv_next_request_fn(request_queue_t *);
-void elv_add_request_fn(request_queue_t *, struct request *,struct list_head *);
+/*
+ * elevator linus. based on linus ideas of starvation control, using
+ * sequencing to manage inserts and merges.
+ */
+extern elevator_t elevator_linus;
+#define elv_linus_sequence(rq) ((long)(rq)->elevator_private)
/*
* use the /proc/iosched interface, all the below is history ->
#define ELEVATOR_FRONT_MERGE 1
#define ELEVATOR_BACK_MERGE 2
-#define elevator_request_latency(e, rw) ((e)->latency[(rw) & 1])
-
/*
* will change once we move to a more complex data structure than a simple
* list for pending requests
*/
#define elv_queue_empty(q) list_empty(&(q)->queue_head)
-/*
- * elevator private data
- */
-struct elv_linus_data {
- unsigned long flags;
-};
-
-#define ELV_DAT(e) ((struct elv_linus_data *)(e)->elevator_data)
-
-#define ELV_LINUS_BACK_MERGE 1
-#define ELV_LINUS_FRONT_MERGE 2
-
-#define ELEVATOR_NOOP \
-((elevator_t) { \
- { 0, 0}, \
- elevator_noop_merge, /* elevator_merge_fn */ \
- elevator_noop_merge_cleanup, /* elevator_merge_cleanup_fn */ \
- elevator_noop_merge_req, /* elevator_merge_req_fn */ \
- elv_next_request_fn, \
- elv_add_request_fn, \
- elv_linus_init, \
- elv_linus_exit, \
- })
-
-#define ELEVATOR_LINUS \
-((elevator_t) { \
- { 8192, 16384 }, \
- elevator_linus_merge, /* elevator_merge_fn */ \
- elevator_linus_merge_cleanup, /* elevator_merge_cleanup_fn */ \
- elevator_linus_merge_req, /* elevator_merge_req_fn */ \
- elv_next_request_fn, \
- elv_add_request_fn, \
- elv_linus_init, \
- elv_linus_exit, \
- })
-
#endif
*/
int ide_multwrite (ide_drive_t *drive, unsigned int mcount);
+/*
+ * idedisk_input_data() is a wrapper around ide_input_data() which copes
+ * with byte-swapping the input data if required.
+ */
+inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+
/*
* ide_stall_queue() can be used by a drive to give excess bandwidth back
* to the hwgroup by sleeping for timeout jiffies.
* all fields in a single cacheline that are needed for
* the goodness() loop in schedule().
*/
- long dyn_prio;
+ unsigned long dyn_prio;
long nice;
unsigned long policy;
struct mm_struct *mm;
*/
struct list_head run_list;
long time_slice;
- unsigned long sleep_time;
/* recalculation loop checkpoint */
unsigned long rcl_last;
*/
#define _STK_LIM (8*1024*1024)
-#define MAX_DYNPRIO 100
+#define MAX_DYNPRIO 40
#define DEF_TSLICE (6 * HZ / 100)
#define MAX_TSLICE (20 * HZ / 100)
#define DEF_NICE (0)
static inline void del_from_runqueue(struct task_struct * p)
{
nr_running--;
- p->sleep_time = jiffies;
list_del(&p->run_list);
p->run_list.next = NULL;
}
error = -EINVAL;
- if (!num_args) {
- printk("have no arguments\n");
+ if (!num_args)
goto done;
- }
if (!strnicmp(str_command,"suspend",7)) {
-
- printk("%s: we know it's a suspend action\n",__FUNCTION__);
-
if (num_args != 3)
goto done;
if (!strnicmp(str_stage,"notify",6))
error = dev->driver->resume(dev,int_stage);
else
error = 0;
- } else
- printk("%s: couldn't find any thing to do\n",__FUNCTION__);
+ }
done:
put_device(dev);
* NOTE! The unix "nice" value influences how long a process
* gets. The nice value ranges from -20 to +19, where a -20
* is a "high-priority" task, and a "+10" is a low-priority
- * task. The default time slice for zero-nice tasks will be 43ms.
+ * task. The default time slice for zero-nice tasks will be 37ms.
*/
#define NICE_RANGE 40
-#define MIN_NICE_TSLICE 10000
-#define MAX_NICE_TSLICE 80000
+#define MIN_NICE_TSLICE 5000
+#define MAX_NICE_TSLICE 70000
#define TASK_TIMESLICE(p) ((int) ts_table[19 - (p)->nice])
static unsigned char ts_table[NICE_RANGE];
goto need_resched;
if (!--p->time_slice) {
- if (p->dyn_prio > 0) {
+ if (p->dyn_prio) {
p->time_slice--;
p->dyn_prio--;
}
current->need_resched = 1;
current->time_slice = 0;
- current->dyn_prio++;
+ if (++current->dyn_prio > MAX_DYNPRIO)
+ current->dyn_prio = MAX_DYNPRIO;
}
return 0;
}
{
int i;
- for (i = 0; i < NICE_RANGE; i++)
+ for (i = 0; i < NICE_RANGE; i++) {
ts_table[i] = ((MIN_NICE_TSLICE +
- ((MAX_NICE_TSLICE - MIN_NICE_TSLICE) / NICE_RANGE) * i) * HZ) / 1000000;
+ ((MAX_NICE_TSLICE -
+ MIN_NICE_TSLICE) / (NICE_RANGE - 1)) * i) * HZ) / 1000000;
+ if (!ts_table[i]) ts_table[i] = 1;
+ }
}
void __init sched_init(void)
static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
{
struct ircomm_tty_cb *self;
- int line;
+ unsigned int line;
int ret;
IRDA_DEBUG(2, __FUNCTION__ "()\n");
MOD_INC_USE_COUNT;
- line = MINOR(tty->device) - tty->driver.minor_start;
+ line = minor(tty->device) - tty->driver.minor_start;
if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) {
MOD_DEC_USE_COUNT;
return -ENODEV;
static unsigned int netlink_poll(struct file *file, poll_table * wait)
{
- struct socket *sock = netlink_user[MINOR(file->f_dentry->d_inode->i_rdev)];
+ struct socket *sock = netlink_user[minor(file->f_dentry->d_inode->i_rdev)];
if (sock->ops->poll==NULL)
return 0;
size_t count, loff_t *pos)
{
struct inode *inode = file->f_dentry->d_inode;
- struct socket *sock = netlink_user[MINOR(inode->i_rdev)];
+ struct socket *sock = netlink_user[minor(inode->i_rdev)];
struct msghdr msg;
struct iovec iov;
size_t count, loff_t *pos)
{
struct inode *inode = file->f_dentry->d_inode;
- struct socket *sock = netlink_user[MINOR(inode->i_rdev)];
+ struct socket *sock = netlink_user[minor(inode->i_rdev)];
struct msghdr msg;
struct iovec iov;
static int netlink_open(struct inode * inode, struct file * file)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct socket *sock;
struct sockaddr_nl nladdr;
int err;
static int netlink_release(struct inode * inode, struct file * file)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
struct socket *sock;
sock = netlink_user[minor];
static int netlink_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int minor = minor(inode->i_rdev);
int retval = 0;
if (minor >= MAX_LINKS)