Commit 9910fd91 authored by Linus Torvalds's avatar Linus Torvalds

v2.4.0.7 -> v2.4.0.8

  - USB hotplug updates/fixes
  - boots on real i386 machines
  - fix n_tty "canon" mode SMP race
  - FAT fat_cache SMP race fix
parent 3175e85b
...@@ -2625,13 +2625,14 @@ CONFIG_HOTPLUG ...@@ -2625,13 +2625,14 @@ CONFIG_HOTPLUG
One well known example of this is PCMCIA- or PC-cards, credit-card One well known example of this is PCMCIA- or PC-cards, credit-card
size devices such as network cards, modems or hard drives which are size devices such as network cards, modems or hard drives which are
plugged into slots found on all modern laptop computers. plugged into slots found on all modern laptop computers. Another
example, used on modern desktops as well as laptops, is USB.
Another example, used on modern desktops as well as laptops, is USB.
Enable HOTPLUG with USB and KMOD, and your kernel will automatically Enable HOTPLUG and KMOD, and build a modular kernel. Get agent
call out to a user mode "policy agent" to load modules and set up software (at http://linux-hotplug.sourceforge.net) and install it.
software needed to use USB devices you plug in. Get agent software Then your kernel will automatically call out to a user mode "policy
(at http://www.linux-usb.org/policy.html) and install it. agent" (/sbin/hotplug) to load modules and set up software needed
to use devices as you hotplug them.
PCMCIA/Cardbus support PCMCIA/Cardbus support
CONFIG_PCMCIA CONFIG_PCMCIA
......
USB HOTPLUGGING LINUX HOTPLUGGING
In hotpluggable busses like USB (and Cardbus PCI), end-users plug devices In hotpluggable busses like USB (and Cardbus PCI), end-users plug devices
into the bus with power on. In most cases, users expect the devices to become into the bus with power on. In most cases, users expect the devices to become
...@@ -8,7 +8,7 @@ immediately usable. That means the system must do many things, including: ...@@ -8,7 +8,7 @@ immediately usable. That means the system must do many things, including:
loading a kernel module; newer drivers can use modutils to loading a kernel module; newer drivers can use modutils to
publish their device (and class) support to user utilities. publish their device (and class) support to user utilities.
- Bind a driver to that device. That's done using the USB - Bind a driver to that device. Bus frameworks do that using a
device driver's probe() routine. device driver's probe() routine.
- Tell other subsystems to configure the new device. Print - Tell other subsystems to configure the new device. Print
...@@ -26,6 +26,10 @@ Those triggered actions must support a system's administrative policies; ...@@ -26,6 +26,10 @@ Those triggered actions must support a system's administrative policies;
such programs are called "policy agents" here. Typically they involve such programs are called "policy agents" here. Typically they involve
shell scripts that dispatch to more familiar administration tools. shell scripts that dispatch to more familiar administration tools.
Because some of those actions rely on information about drivers (metadata)
that is currently available only when the drivers are dynamically linked,
you get the best hotplugging when you configure a highly modular system.
KERNEL HOTPLUG HELPER (/sbin/hotplug) KERNEL HOTPLUG HELPER (/sbin/hotplug)
...@@ -40,9 +44,14 @@ some kernel event. That name is used as the first key for further event ...@@ -40,9 +44,14 @@ some kernel event. That name is used as the first key for further event
dispatch; any other argument and environment parameters are specified by dispatch; any other argument and environment parameters are specified by
the subsystem making that invocation. the subsystem making that invocation.
A reference implementation of a /sbin/hotplug script is available at the Hotplug software and other resources is available at:
http://www.linux-usb.org website, which works USB for but also knows how to
delegate to any /etc/hotplug/$TYPE.agent policy agent present. http://linux-hotplug.sourceforge.net
Mailing list information is also available at that site.
--------------------------------------------------------------------------
USB POLICY AGENT USB POLICY AGENT
......
...@@ -223,7 +223,7 @@ Generic Serial driver ...@@ -223,7 +223,7 @@ Generic Serial driver
To enable the generic driver to recognize your device, build the driver To enable the generic driver to recognize your device, build the driver
as a module and load it by the following invocation: as a module and load it by the following invocation:
insmod usb-serial vendor=0x#### product=0x#### insmod usbserial vendor=0x#### product=0x####
where the #### is replaced with the hex representation of your device's where the #### is replaced with the hex representation of your device's
vendor id and product id. vendor id and product id.
......
VERSION = 2 VERSION = 2
PATCHLEVEL = 4 PATCHLEVEL = 4
SUBLEVEL = 1 SUBLEVEL = 1
EXTRAVERSION =-pre7 EXTRAVERSION =-pre8
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
......
...@@ -86,6 +86,15 @@ static inline void free_buf(unsigned char *buf) ...@@ -86,6 +86,15 @@ static inline void free_buf(unsigned char *buf)
free_page((unsigned long) buf); free_page((unsigned long) buf);
} }
static inline void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
{
if (tty->read_cnt < N_TTY_BUF_SIZE) {
tty->read_buf[tty->read_head] = c;
tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
tty->read_cnt++;
}
}
static inline void put_tty_queue(unsigned char c, struct tty_struct *tty) static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
{ {
unsigned long flags; unsigned long flags;
...@@ -94,11 +103,7 @@ static inline void put_tty_queue(unsigned char c, struct tty_struct *tty) ...@@ -94,11 +103,7 @@ static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
* Why didn't anyone see this one comming? --AJK * Why didn't anyone see this one comming? --AJK
*/ */
spin_lock_irqsave(&tty->read_lock, flags); spin_lock_irqsave(&tty->read_lock, flags);
if (tty->read_cnt < N_TTY_BUF_SIZE) { put_tty_queue_nolock(c, tty);
tty->read_buf[tty->read_head] = c;
tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
tty->read_cnt++;
}
spin_unlock_irqrestore(&tty->read_lock, flags); spin_unlock_irqrestore(&tty->read_lock, flags);
} }
...@@ -499,6 +504,8 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty, ...@@ -499,6 +504,8 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty,
static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
{ {
unsigned long flags;
if (tty->raw) { if (tty->raw) {
put_tty_queue(c, tty); put_tty_queue(c, tty);
return; return;
...@@ -651,10 +658,12 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) ...@@ -651,10 +658,12 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
put_tty_queue(c, tty); put_tty_queue(c, tty);
handle_newline: handle_newline:
spin_lock_irqsave(&tty->read_lock, flags);
set_bit(tty->read_head, &tty->read_flags); set_bit(tty->read_head, &tty->read_flags);
put_tty_queue(c, tty); put_tty_queue_nolock(c, tty);
tty->canon_head = tty->read_head; tty->canon_head = tty->read_head;
tty->canon_data++; tty->canon_data++;
spin_unlock_irqrestore(&tty->read_lock, flags);
kill_fasync(&tty->fasync, SIGIO, POLL_IN); kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait)) if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->read_wait);
...@@ -1055,12 +1064,6 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file, ...@@ -1055,12 +1064,6 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file,
tty->read_tail = ((tty->read_tail+1) & tty->read_tail = ((tty->read_tail+1) &
(N_TTY_BUF_SIZE-1)); (N_TTY_BUF_SIZE-1));
tty->read_cnt--; tty->read_cnt--;
spin_unlock_irqrestore(&tty->read_lock, flags);
if (!eol || (c != __DISABLED_CHAR)) {
put_user(c, b++);
nr--;
}
if (eol) { if (eol) {
/* this test should be redundant: /* this test should be redundant:
* we shouldn't be reading data if * we shouldn't be reading data if
...@@ -1068,8 +1071,15 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file, ...@@ -1068,8 +1071,15 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file,
*/ */
if (--tty->canon_data < 0) if (--tty->canon_data < 0)
tty->canon_data = 0; tty->canon_data = 0;
break;
} }
spin_unlock_irqrestore(&tty->read_lock, flags);
if (!eol || (c != __DISABLED_CHAR)) {
put_user(c, b++);
nr--;
}
if (eol)
break;
} }
} else { } else {
int uncopied; int uncopied;
......
...@@ -247,6 +247,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -247,6 +247,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
return 0; return 0;
err_out: err_out:
up(&(rio->lock));
return retval; return retval;
} }
...@@ -389,7 +390,7 @@ read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos) ...@@ -389,7 +390,7 @@ read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos)
result, partial, this_read); result, partial, this_read);
return -EIO; return -EIO;
} else { } else {
unlock_kernel(); up(&(rio->lock));
return (0); return (0);
} }
......
...@@ -22,6 +22,7 @@ if [ "$CONFIG_USB_SERIAL" != "n" ]; then ...@@ -22,6 +22,7 @@ if [ "$CONFIG_USB_SERIAL" != "n" ]; then
bool ' USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19 bool ' USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19
bool ' USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X bool ' USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
bool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W bool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
bool ' USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W
fi fi
dep_tristate ' USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
......
...@@ -14,8 +14,14 @@ ...@@ -14,8 +14,14 @@
* based on a driver by Brad Keryan) * based on a driver by Brad Keryan)
* *
* See Documentation/usb/usb-serial.txt for more information on using this driver * See Documentation/usb/usb-serial.txt for more information on using this driver
* *
* (12/29/2000) gkh * (12/12/2000) gkh
* Removed MOD_INC and MOD_DEC from poll and disconnect functions, and
* moved them to the serial_open and serial_close functions.
* Also fixed bug with there not being a MOD_DEC for the generic driver
* (thanks to Gary Brubaker for finding this.)
*
* (11/29/2000) gkh
* Small NULL pointer initialization cleanup which saves a bit of disk image * Small NULL pointer initialization cleanup which saves a bit of disk image
* *
* (11/01/2000) Adam J. Richter * (11/01/2000) Adam J. Richter
...@@ -471,6 +477,8 @@ static int serial_open (struct tty_struct *tty, struct file * filp) ...@@ -471,6 +477,8 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
return -ENODEV; return -ENODEV;
} }
MOD_INC_USE_COUNT;
/* set up our port structure making the tty driver remember our port object, and us it */ /* 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]; port = &serial->port[portNumber];
...@@ -508,6 +516,8 @@ static void serial_close(struct tty_struct *tty, struct file * filp) ...@@ -508,6 +516,8 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
} else { } else {
generic_close(port, filp); generic_close(port, filp);
} }
MOD_DEC_USE_COUNT;
} }
...@@ -721,12 +731,13 @@ static int generic_open (struct usb_serial_port *port, struct file *filp) ...@@ -721,12 +731,13 @@ static int generic_open (struct usb_serial_port *port, struct file *filp)
if (port_paranoia_check (port, __FUNCTION__)) if (port_paranoia_check (port, __FUNCTION__))
return -ENODEV; return -ENODEV;
MOD_INC_USE_COUNT;
dbg(__FUNCTION__ " - port %d", port->number); dbg(__FUNCTION__ " - port %d", port->number);
spin_lock_irqsave (&port->port_lock, flags); spin_lock_irqsave (&port->port_lock, flags);
++port->open_count; ++port->open_count;
MOD_INC_USE_COUNT;
if (!port->active) { if (!port->active) {
port->active = 1; port->active = 1;
...@@ -776,6 +787,7 @@ static void generic_close (struct usb_serial_port *port, struct file * filp) ...@@ -776,6 +787,7 @@ static void generic_close (struct usb_serial_port *port, struct file * filp)
} }
spin_unlock_irqrestore (&port->port_lock, flags); spin_unlock_irqrestore (&port->port_lock, flags);
MOD_DEC_USE_COUNT;
} }
...@@ -1069,7 +1081,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1069,7 +1081,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
} }
/* found all that we need */ /* found all that we need */
MOD_INC_USE_COUNT;
info("%s converter detected", type->name); info("%s converter detected", type->name);
#ifdef CONFIG_USB_SERIAL_GENERIC #ifdef CONFIG_USB_SERIAL_GENERIC
...@@ -1077,7 +1088,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1077,7 +1088,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
num_ports = num_bulk_out; num_ports = num_bulk_out;
if (num_ports == 0) { if (num_ports == 0) {
err("Generic device with no bulk out, not allowed."); err("Generic device with no bulk out, not allowed.");
MOD_DEC_USE_COUNT;
return NULL; return NULL;
} }
} else } else
...@@ -1087,7 +1097,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1087,7 +1097,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
serial = get_free_serial (num_ports, &minor); serial = get_free_serial (num_ports, &minor);
if (serial == NULL) { if (serial == NULL) {
err("No more free serial devices"); err("No more free serial devices");
MOD_DEC_USE_COUNT;
return NULL; return NULL;
} }
...@@ -1233,7 +1242,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1233,7 +1242,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
/* free up any memory that we allocated */ /* free up any memory that we allocated */
kfree (serial); kfree (serial);
MOD_DEC_USE_COUNT;
return NULL; return NULL;
} }
...@@ -1300,7 +1308,6 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr) ...@@ -1300,7 +1308,6 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
info("device disconnected"); info("device disconnected");
} }
MOD_DEC_USE_COUNT;
} }
......
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
* (at your option) any later version. * (at your option) any later version.
* *
* See Documentation/usb/usb-serial.txt for more information on using this driver * See Documentation/usb/usb-serial.txt for more information on using this driver
*
* (12/12/2000) gkh
* Moved MOD_DEC to end of visor_close to be nicer, as the final write
* message can sleep.
* *
* (11/12/2000) gkh * (11/12/2000) gkh
* Fixed bug with data being dropped on the floor by forcing tty->low_latency * Fixed bug with data being dropped on the floor by forcing tty->low_latency
...@@ -214,7 +218,6 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) ...@@ -214,7 +218,6 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
spin_lock_irqsave (&port->port_lock, flags); spin_lock_irqsave (&port->port_lock, flags);
--port->open_count; --port->open_count;
MOD_DEC_USE_COUNT;
if (port->open_count <= 0) { if (port->open_count <= 0) {
transfer_buffer = kmalloc (0x12, GFP_KERNEL); transfer_buffer = kmalloc (0x12, GFP_KERNEL);
...@@ -237,6 +240,8 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) ...@@ -237,6 +240,8 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
/* Uncomment the following line if you want to see some statistics in your syslog */ /* Uncomment the following line if you want to see some statistics in your syslog */
/* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */
MOD_DEC_USE_COUNT;
} }
......
/* Driver for USB Mass Storage compliant devices /* Driver for USB Mass Storage compliant devices
* Debugging Functions Header File * Debugging Functions Header File
* *
* $Id: debug.h,v 1.5 2000/09/04 02:12:47 groovyjava Exp $ * $Id: debug.h,v 1.6 2001/01/12 23:51:04 mdharm Exp $
* *
* Current development and maintenance by: * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
......
...@@ -248,7 +248,7 @@ static int bus_reset( Scsi_Cmnd *srb ) ...@@ -248,7 +248,7 @@ static int bus_reset( Scsi_Cmnd *srb )
for (i = 0; i < us->pusb_dev->actconfig->bNumInterfaces; i++) { for (i = 0; i < us->pusb_dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *intf = struct usb_interface *intf =
&us->pusb_dev->actconfig->interface[i]; &us->pusb_dev->actconfig->interface[i];
const struct usb_device_id *id; struct usb_device_id *id;
/* if this is an unclaimed interface, skip it */ /* if this is an unclaimed interface, skip it */
if (!intf->driver) { if (!intf->driver) {
......
/* Driver for USB Mass Storage compliant devices
* Ununsual Devices File
*
* $Id: unusual_devs.h,v 1.1 2000/12/05 05:38:31 mdharm Exp $
*
* Current development and maintenance by:
* (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Initial work by:
* (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc.
*
* Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
* information about this 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, 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.
*/
/* IMPORTANT NOTE: This file must be included in another file which does
* both of the following things for it to work:
* (1) <include/config.h> _must_ be included before this file
* (2) The macro UNUSUAL_DEV() must be defined before this file is included
*/
/* If you edit this file, please try to keep it sorted first by VendorID,
* then by ProductID.
*/
UNUSUAL_DEV( 0x03ee, 0x0000, 0x0000, 0x0245,
"Mitsumi",
"CD-R/RW Drive",
US_SC_8020, US_PR_CBI, NULL, 0),
UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200,
"HP",
"CD-Writer+",
US_SC_8070, US_PR_CB, NULL, 0),
#ifdef CONFIG_USB_STORAGE_HP8200e
UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001,
"HP",
"CD-Writer+ 8200e",
US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0),
#endif
UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200,
"Matshita",
"LS-120",
US_SC_8020, US_PR_CB, NULL, 0),
UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
#ifdef CONFIG_USB_STORAGE_SDDR09
UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999,
"Sandisk",
"ImageMate SDDR09",
US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP ),
#endif
#ifdef CONFIG_USB_STORAGE_DPCM
UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100,
"Microtech",
"CameraMate (DPCM_USB)",
US_SC_SCSI, US_PR_DPCM_USB, NULL,
US_FL_START_STOP ),
#endif
UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0200,
"Shuttle",
"eUSB MMC Adapter",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN),
UNUSUAL_DEV( 0x04e6, 0x0007, 0x0100, 0x0200,
"Sony",
"Hifd",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN),
UNUSUAL_DEV( 0x04e6, 0x0009, 0x0200, 0x0200,
"Shuttle",
"eUSB ATA/ATAPI Adapter",
US_SC_8020, US_PR_CB, NULL, 0),
UNUSUAL_DEV( 0x04e6, 0x000a, 0x0200, 0x0200,
"Shuttle",
"eUSB CompactFlash Adapter",
US_SC_8020, US_PR_CB, NULL, 0),
UNUSUAL_DEV( 0x04e6, 0x000B, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
UNUSUAL_DEV( 0x04e6, 0x000C, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x0200,
"Shuttle",
"CD-RW Device",
US_SC_8020, US_PR_CB, NULL, 0),
UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0210,
"Sony",
"DSC-S30/S70/505V/F505",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ),
UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100,
"Sony",
"Memorystick MSAC-US1",
US_SC_UFI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP ),
UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299,
"Y-E Data",
"Flashbuster-U",
US_SC_UFI, US_PR_CB, NULL,
US_FL_SINGLE_LUN),
UNUSUAL_DEV( 0x057b, 0x0000, 0x0300, 0x9999,
"Y-E Data",
"Flashbuster-U",
US_SC_UFI, US_PR_CBI, NULL,
US_FL_SINGLE_LUN),
UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200,
"LaCie",
"USB Hard Disk",
US_SC_RBC, US_PR_CB, NULL, 0 ),
UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0100,
"In-System",
"USB/IDE Bridge (ATAPI ONLY!)",
US_SC_8070, US_PR_BULK, NULL, 0 ),
UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100,
"TEAC",
"Floppy Drive",
US_SC_UFI, US_PR_CB, NULL, 0 ),
#ifdef CONFIG_USB_STORAGE_SDDR09
UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100,
"Olympus",
"Camedia MAUSB-2",
US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP ),
#endif
UNUSUAL_DEV( 0x0693, 0x0002, 0x0100, 0x0100,
"Hagiwara",
"FlashGate SmartMedia",
US_SC_SCSI, US_PR_BULK, NULL, 0 ),
UNUSUAL_DEV( 0x0693, 0x0005, 0x0100, 0x0100,
"Hagiwara",
"Flashgate",
US_SC_SCSI, US_PR_BULK, NULL, 0 ),
UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200,
"Sandisk",
"ImageMate SDDR-05a",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP),
UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100,
"Sandisk",
"ImageMate SDDR-12",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN ),
#ifdef CONFIG_USB_STORAGE_SDDR09
UNUSUAL_DEV( 0x0781, 0x0200, 0x0100, 0x0100,
"Sandisk",
"ImageMate SDDR-09",
US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP ),
#endif
UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009,
"Sandisk",
"ImageMate SDDR-31",
US_SC_SCSI, US_PR_BULK, NULL,
US_FL_IGNORE_SER),
UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0100,
"Microtech",
"USB-SCSI-DB25",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
#ifdef CONFIG_USB_STORAGE_FREECOM
UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999,
"Freecom",
"USB-IDE",
US_SC_QIC, US_PR_FREECOM, freecom_init, 0),
#endif
UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100,
"Microtech",
"USB-SCSI-HD50",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
#ifdef CONFIG_USB_STORAGE_DPCM
UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100,
"Microtech",
"CameraMate (DPCM_USB)",
US_SC_SCSI, US_PR_DPCM_USB, NULL,
US_FL_START_STOP ),
#endif
/* Driver for USB Mass Storage compliant devices /* Driver for USB Mass Storage compliant devices
* *
* $Id: usb.c,v 1.57 2000/11/21 02:56:41 mdharm Exp $ * $Id: usb.c,v 1.61 2001/01/13 00:10:59 mdharm Exp $
* *
* Current development and maintenance by: * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
* Initial work by: * Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com) * (c) 1999 Michael Gee (michael@linuxspecific.com)
* *
* usb_device_id support by Adam J. Richter (adam@yggdrasil.com):
* (c) 2000 Yggdrasil Computing, Inc.
*
* This driver is based on the 'USB Mass Storage Class' document. This * This driver is based on the 'USB Mass Storage Class' document. This
* describes in detail the protocol used to communicate with such * describes in detail the protocol used to communicate with such
* devices. Clearly, the designers had SCSI and ATAPI commands in * devices. Clearly, the designers had SCSI and ATAPI commands in
...@@ -95,11 +98,133 @@ struct semaphore us_list_semaphore; ...@@ -95,11 +98,133 @@ struct semaphore us_list_semaphore;
static void * storage_probe(struct usb_device *dev, unsigned int ifnum, static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id); const struct usb_device_id *id);
static void storage_disconnect(struct usb_device *dev, void *ptr); static void storage_disconnect(struct usb_device *dev, void *ptr);
/* The entries in this table, except for final ones here
* (USB_MASS_STORAGE_CLASS and the empty entry), correspond,
* line for line with the entries of us_unsuaul_dev_list[].
* For now, we duplicate idVendor and idProduct in us_unsual_dev_list,
* just to avoid alignment bugs.
*/
#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
vendorName, productName,useProtocol, useTransport, \
initFunction, flags) \
{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax) }
static struct usb_device_id storage_usb_ids [] = {
# include "unusual_devs.h"
#undef UNUSUAL_DEV
/* Control/Bulk transport for all SubClass values */
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CB) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CB) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CB) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CB) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CB) },
/* Control/Bulk/Interrupt transport for all SubClass values */
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CBI) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CBI) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CBI) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CBI) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CBI) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CBI) },
/* Bulk-only transport for all SubClass values */
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
/* Terminating entry */
{ }
};
MODULE_DEVICE_TABLE (usb, storage_usb_ids);
/* This is the list of devices we recognize, along with their flag data */
/* The vendor name should be kept at eight characters or less, and
* the product name should be kept at 16 characters or less. If a device
* has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names
* normally generated by a device thorugh the INQUIRY response will be
* taken from this list, and this is the reason for the above size
* restriction. However, if the flag is not present, then you
* are free to use as many characters as you like.
*/
#undef UNUSUAL_DEV
#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
vendor_name, product_name, use_protocol, use_transport, \
init_function, Flags) \
{ \
vendorName: vendor_name, \
productName: product_name, \
useProtocol: use_protocol, \
useTransport: use_transport, \
initFunction : init_function, \
flags: Flags, \
}
static struct us_unusual_dev us_unusual_dev_list[] = {
# include "unusual_devs.h"
# undef UNUSUAL_DEV
/* Control/Bulk transport for all SubClass values */
{ useProtocol: US_SC_RBC,
useTransport: US_PR_CB},
{ useProtocol: US_SC_8020,
useTransport: US_PR_CB},
{ useProtocol: US_SC_QIC,
useTransport: US_PR_CB},
{ useProtocol: US_SC_UFI,
useTransport: US_PR_CB},
{ useProtocol: US_SC_8070,
useTransport: US_PR_CB},
{ useProtocol: US_SC_SCSI,
useTransport: US_PR_CB},
/* Control/Bulk/Interrupt transport for all SubClass values */
{ useProtocol: US_SC_RBC,
useTransport: US_PR_CBI},
{ useProtocol: US_SC_8020,
useTransport: US_PR_CBI},
{ useProtocol: US_SC_QIC,
useTransport: US_PR_CBI},
{ useProtocol: US_SC_UFI,
useTransport: US_PR_CBI},
{ useProtocol: US_SC_8070,
useTransport: US_PR_CBI},
{ useProtocol: US_SC_SCSI,
useTransport: US_PR_CBI},
/* Bulk-only transport for all SubClass values */
{ useProtocol: US_SC_RBC,
useTransport: US_PR_BULK},
{ useProtocol: US_SC_8020,
useTransport: US_PR_BULK},
{ useProtocol: US_SC_QIC,
useTransport: US_PR_BULK},
{ useProtocol: US_SC_UFI,
useTransport: US_PR_BULK},
{ useProtocol: US_SC_8070,
useTransport: US_PR_BULK},
{ useProtocol: US_SC_SCSI,
useTransport: US_PR_BULK},
/* Terminating entry */
{ 0 }
};
struct usb_driver usb_storage_driver = { struct usb_driver usb_storage_driver = {
name: "usb-storage", name: "usb-storage",
probe: storage_probe, probe: storage_probe,
disconnect: storage_disconnect, disconnect: storage_disconnect,
id_table: storage_usb_ids,
}; };
/* /*
...@@ -325,246 +450,6 @@ static int usb_stor_control_thread(void * __us) ...@@ -325,246 +450,6 @@ static int usb_stor_control_thread(void * __us)
return 0; return 0;
} }
/* This is the list of devices we recognize, along with their flag data */
/* The vendor name should be kept at eight characters or less, and
* the product name should be kept at 16 characters or less. If a device
* has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names
* normally generated by a device thorugh the INQUIRY response will be
* taken from this list, and this is the reason for the above size
* restriction. However, if the flag is not present, then you
* are free to use as many characters as you like.
*/
static struct us_unusual_dev us_unusual_dev_list[] = {
{ 0x03ee, 0x0000, 0x0000, 0x0245,
"Mitsumi",
"CD-R/RW Drive",
US_SC_8020, US_PR_CBI, NULL, 0},
{ 0x03f0, 0x0107, 0x0200, 0x0200,
"HP",
"CD-Writer+",
US_SC_8070, US_PR_CB, NULL, 0},
#ifdef CONFIG_USB_STORAGE_HP8200e
{ 0x03f0, 0x0207, 0x0001, 0x0001,
"HP",
"CD-Writer+ 8200e",
US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0},
#endif
{ 0x04e6, 0x0001, 0x0200, 0x0200,
"Matshita",
"LS-120",
US_SC_8020, US_PR_CB, NULL, 0},
{ 0x04e6, 0x0002, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG },
#ifdef CONFIG_USB_STORAGE_SDDR09
{ 0x04e6, 0x0003, 0x0000, 0x9999,
"Sandisk",
"ImageMate SDDR09",
US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP },
#endif
#ifdef CONFIG_USB_STORAGE_DPCM
{ 0x0436, 0x0005, 0x0100, 0x0100,
"Microtech",
"CameraMate (DPCM_USB)",
US_SC_SCSI, US_PR_DPCM_USB, NULL,
US_FL_START_STOP },
#endif
{ 0x04e6, 0x0006, 0x0100, 0x0200,
"Shuttle",
"eUSB MMC Adapter",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN},
{ 0x04e6, 0x0007, 0x0100, 0x0200,
"Sony",
"Hifd",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN},
{ 0x04e6, 0x0009, 0x0200, 0x0200,
"Shuttle",
"eUSB ATA/ATAPI Adapter",
US_SC_8020, US_PR_CB, NULL, 0},
{ 0x04e6, 0x000a, 0x0200, 0x0200,
"Shuttle",
"eUSB CompactFlash Adapter",
US_SC_8020, US_PR_CB, NULL, 0},
{ 0x04e6, 0x000B, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG },
{ 0x04e6, 0x000C, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG },
{ 0x04e6, 0x0101, 0x0200, 0x0200,
"Shuttle",
"CD-RW Device",
US_SC_8020, US_PR_CB, NULL, 0},
{ 0x054c, 0x0010, 0x0106, 0x0210,
"Sony",
"DSC-S30/S70/505V/F505",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE },
{ 0x054c, 0x002d, 0x0100, 0x0100,
"Sony",
"Memorystick MSAC-US1",
US_SC_UFI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP },
{ 0x057b, 0x0000, 0x0000, 0x0299,
"Y-E Data",
"Flashbuster-U",
US_SC_UFI, US_PR_CB, NULL,
US_FL_SINGLE_LUN},
{ 0x057b, 0x0000, 0x0300, 0x9999,
"Y-E Data",
"Flashbuster-U",
US_SC_UFI, US_PR_CBI, NULL,
US_FL_SINGLE_LUN},
{ 0x059f, 0xa601, 0x0200, 0x0200,
"LaCie",
"USB Hard Disk",
US_SC_RBC, US_PR_CB, NULL, 0 },
{ 0x05ab, 0x0031, 0x0100, 0x0100,
"In-System",
"USB/IDE Bridge (ATAPI ONLY!)",
US_SC_8070, US_PR_BULK, NULL, 0 },
{ 0x0644, 0x0000, 0x0100, 0x0100,
"TEAC",
"Floppy Drive",
US_SC_UFI, US_PR_CB, NULL, 0 },
#ifdef CONFIG_USB_STORAGE_SDDR09
{ 0x066b, 0x0105, 0x0100, 0x0100,
"Olympus",
"Camedia MAUSB-2",
US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP },
#endif
{ 0x0693, 0x0002, 0x0100, 0x0100,
"Hagiwara",
"FlashGate SmartMedia",
US_SC_SCSI, US_PR_BULK, NULL, 0 },
{ 0x0693, 0x0005, 0x0100, 0x0100,
"Hagiwara",
"Flashgate",
US_SC_SCSI, US_PR_BULK, NULL, 0 },
{ 0x0781, 0x0001, 0x0200, 0x0200,
"Sandisk",
"ImageMate SDDR-05a",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP},
{ 0x0781, 0x0100, 0x0100, 0x0100,
"Sandisk",
"ImageMate SDDR-12",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN },
#ifdef CONFIG_USB_STORAGE_SDDR09
{ 0x0781, 0x0200, 0x0100, 0x0208,
"Sandisk",
"ImageMate SDDR-09",
US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP },
#endif
{ 0x0781, 0x0002, 0x0009, 0x0009,
"Sandisk",
"ImageMate SDDR-31",
US_SC_SCSI, US_PR_BULK, NULL,
US_FL_IGNORE_SER},
{ 0x07af, 0x0004, 0x0100, 0x0100,
"Microtech",
"USB-SCSI-DB25",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG },
#ifdef CONFIG_USB_STORAGE_FREECOM
{ 0x07ab, 0xfc01, 0x0000, 0x9999,
"Freecom",
"USB-IDE",
US_SC_QIC, US_PR_FREECOM, freecom_init, 0},
#endif
{ 0x07af, 0x0005, 0x0100, 0x0100,
"Microtech",
"USB-SCSI-HD50",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG },
#ifdef CONFIG_USB_STORAGE_DPCM
{ 0x07af, 0x0006, 0x0100, 0x0100,
"Microtech",
"CameraMate (DPCM_USB)",
US_SC_SCSI, US_PR_DPCM_USB, NULL,
US_FL_START_STOP },
#endif
{ 0 }
};
/* Search our ususual device list, based on vendor/product combinations
* to see if we can support this device. Returns a pointer to a structure
* defining how we should support this device, or NULL if it's not in the
* list
*/
static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct,
u16 bcdDevice)
{
struct us_unusual_dev* ptr;
US_DEBUGP("Searching unusual device list for (0x%x, 0x%x, 0x%x)...\n",
idVendor, idProduct, bcdDevice);
ptr = us_unusual_dev_list;
while ((ptr->idVendor != 0x0000) &&
!((ptr->idVendor == idVendor) &&
(ptr->idProduct == idProduct) &&
(ptr->bcdDeviceMin <= bcdDevice) &&
(ptr->bcdDeviceMax >= bcdDevice)))
ptr++;
/* if the search ended because we hit the end record, we failed */
if (ptr->idVendor == 0x0000) {
US_DEBUGP("-- did not find a matching device\n");
return NULL;
}
/* otherwise, we found one! */
US_DEBUGP("-- found matching device: %s %s\n", ptr->vendorName,
ptr->productName);
return ptr;
}
/* Set up the IRQ pipe and handler /* Set up the IRQ pipe and handler
* Note that this function assumes that all the data in the us_data * Note that this function assumes that all the data in the us_data
* strucuture is current. This includes the ep_int field, which gives us * strucuture is current. This includes the ep_int field, which gives us
...@@ -620,6 +505,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -620,6 +505,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
int i; int i;
const int id_index = id - storage_usb_ids;
char mf[USB_STOR_STRING_LEN]; /* manufacturer */ char mf[USB_STOR_STRING_LEN]; /* manufacturer */
char prod[USB_STOR_STRING_LEN]; /* product */ char prod[USB_STOR_STRING_LEN]; /* product */
char serial[USB_STOR_STRING_LEN]; /* serial number */ char serial[USB_STOR_STRING_LEN]; /* serial number */
...@@ -640,47 +526,48 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -640,47 +526,48 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
u8 subclass = 0; u8 subclass = 0;
u8 protocol = 0; u8 protocol = 0;
/* the altsettting 0 on the interface we're probing */ /* the altsettting on the interface we're probing that matched our
struct usb_interface_descriptor *altsetting = * usb_match_id table
&(dev->actconfig->interface[ifnum].altsetting[0]); */
struct usb_interface *intf = dev->actconfig->interface;
struct usb_interface_descriptor *altsetting =
intf[ifnum].altsetting + intf[ifnum].act_altsetting;
US_DEBUGP("act_altsettting is %d\n", intf[ifnum].act_altsetting);
/* clear the temporary strings */ /* clear the temporary strings */
memset(mf, 0, sizeof(mf)); memset(mf, 0, sizeof(mf));
memset(prod, 0, sizeof(prod)); memset(prod, 0, sizeof(prod));
memset(serial, 0, sizeof(serial)); memset(serial, 0, sizeof(serial));
/* search for this device in our unusual device list */
unusual_dev = us_find_dev(dev->descriptor.idVendor,
dev->descriptor.idProduct,
dev->descriptor.bcdDevice);
/* /*
* Can we support this device, either because we know about it * Can we support this device, either because we know about it
* from our unusual device list, or because it advertises that it's * from our unusual device list, or because it advertises that it's
* compliant to the specification? * compliant to the specification?
*
* id_index is calculated in the declaration to be the index number
* of the match from the usb_device_id table, so we can find the
* corresponding entry in the private table.
*/ */
if (!unusual_dev && US_DEBUGP("id_index calculated to be: %d\n", id_index);
!(dev->descriptor.bDeviceClass == 0 && US_DEBUGP("Array length appears to be: %d\n", sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0]));
altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE && if (id_index <
altsetting->bInterfaceSubClass >= US_SC_MIN && sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0])) {
altsetting->bInterfaceSubClass <= US_SC_MAX)) { unusual_dev = &us_unusual_dev_list[id_index];
/* if it's not a mass storage, we go no further */ if (unusual_dev->vendorName)
US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName);
if (unusual_dev->productName)
US_DEBUGP("Product: %s\n", unusual_dev->productName);
} else
/* no, we can't support it */
return NULL; return NULL;
}
/* At this point, we know we've got a live one */ /* At this point, we know we've got a live one */
US_DEBUGP("USB Mass Storage device detected\n"); US_DEBUGP("USB Mass Storage device detected\n");
/* Determine subclass and protocol, or copy from the interface */ /* Determine subclass and protocol, or copy from the interface */
if (unusual_dev) { subclass = unusual_dev->useProtocol;
subclass = unusual_dev->useProtocol; protocol = unusual_dev->useTransport;
protocol = unusual_dev->useTransport; flags = unusual_dev->flags;
flags = unusual_dev->flags;
} else {
subclass = altsetting->bInterfaceSubClass;
protocol = altsetting->bInterfaceProtocol;
flags = 0;
}
/* /*
* Find the endpoints we need * Find the endpoints we need
...@@ -728,7 +615,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -728,7 +615,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
/* Do some basic sanity checks, and bail if we find a problem */ /* Do some basic sanity checks, and bail if we find a problem */
if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) { if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
US_DEBUGP("Sanity check failed. Rejecting device.\n"); US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n");
return NULL; return NULL;
} }
...@@ -861,7 +748,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -861,7 +748,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
strncpy(ss->product, prod, USB_STOR_STRING_LEN); strncpy(ss->product, prod, USB_STOR_STRING_LEN);
strncpy(ss->serial, serial, USB_STOR_STRING_LEN); strncpy(ss->serial, serial, USB_STOR_STRING_LEN);
if (strlen(ss->vendor) == 0) { if (strlen(ss->vendor) == 0) {
if (unusual_dev) if (unusual_dev->vendorName)
strncpy(ss->vendor, unusual_dev->vendorName, strncpy(ss->vendor, unusual_dev->vendorName,
USB_STOR_STRING_LEN); USB_STOR_STRING_LEN);
else else
...@@ -869,7 +756,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -869,7 +756,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
USB_STOR_STRING_LEN); USB_STOR_STRING_LEN);
} }
if (strlen(ss->product) == 0) { if (strlen(ss->product) == 0) {
if (unusual_dev) if (unusual_dev->productName)
strncpy(ss->product, unusual_dev->productName, strncpy(ss->product, unusual_dev->productName,
USB_STOR_STRING_LEN); USB_STOR_STRING_LEN);
else else
...@@ -1118,6 +1005,8 @@ static void storage_disconnect(struct usb_device *dev, void *ptr) ...@@ -1118,6 +1005,8 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
int __init usb_stor_init(void) int __init usb_stor_init(void)
{ {
printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
/* initialize internal global data elements */ /* initialize internal global data elements */
us_list = NULL; us_list = NULL;
init_MUTEX(&us_list_semaphore); init_MUTEX(&us_list_semaphore);
......
/* Driver for USB Mass Storage compliant devices /* Driver for USB Mass Storage compliant devices
* Main Header File * Main Header File
* *
* $Id: usb.h,v 1.11 2000/11/13 22:38:55 mdharm Exp $ * $Id: usb.h,v 1.12 2000/12/05 03:33:49 mdharm Exp $
* *
* Current development and maintenance by: * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
...@@ -84,13 +84,6 @@ struct us_data; ...@@ -84,13 +84,6 @@ struct us_data;
*/ */
struct us_unusual_dev { struct us_unusual_dev {
/* we search the list based on these parameters */
__u16 idVendor;
__u16 idProduct;
__u16 bcdDeviceMin;
__u16 bcdDeviceMax;
/* the list specifies these parameters */
const char* vendorName; const char* vendorName;
const char* productName; const char* productName;
__u8 useProtocol; __u8 useProtocol;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#endif #endif
static struct fat_cache *fat_cache,cache[FAT_CACHE]; static struct fat_cache *fat_cache,cache[FAT_CACHE];
static spinlock_t fat_cache_lock = SPIN_LOCK_UNLOCKED;
/* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If /* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If
new_value is != -1, that FAT entry is replaced by it. */ new_value is != -1, that FAT entry is replaced by it. */
...@@ -133,13 +134,16 @@ int default_fat_access(struct super_block *sb,int nr,int new_value) ...@@ -133,13 +134,16 @@ int default_fat_access(struct super_block *sb,int nr,int new_value)
return next; return next;
} }
void fat_cache_init(void) void fat_cache_init(void)
{ {
static int initialized = 0; static int initialized = 0;
int count; int count;
if (initialized) return; spin_lock(&fat_cache_lock);
if (initialized) {
spin_unlock(&fat_cache_lock);
return;
}
fat_cache = &cache[0]; fat_cache = &cache[0];
for (count = 0; count < FAT_CACHE; count++) { for (count = 0; count < FAT_CACHE; count++) {
cache[count].device = 0; cache[count].device = 0;
...@@ -147,6 +151,7 @@ void fat_cache_init(void) ...@@ -147,6 +151,7 @@ void fat_cache_init(void)
&cache[count+1]; &cache[count+1];
} }
initialized = 1; initialized = 1;
spin_unlock(&fat_cache_lock);
} }
...@@ -157,6 +162,7 @@ void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu) ...@@ -157,6 +162,7 @@ void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu)
if (!first) if (!first)
return; return;
spin_lock(&fat_cache_lock);
for (walk = fat_cache; walk; walk = walk->next) for (walk = fat_cache; walk; walk = walk->next)
if (inode->i_dev == walk->device if (inode->i_dev == walk->device
&& walk->start_cluster == first && walk->start_cluster == first
...@@ -166,8 +172,12 @@ void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu) ...@@ -166,8 +172,12 @@ void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu)
#ifdef DEBUG #ifdef DEBUG
printk("cache hit: %d (%d)\n",walk->file_cluster,*d_clu); printk("cache hit: %d (%d)\n",walk->file_cluster,*d_clu);
#endif #endif
if ((*f_clu = walk->file_cluster) == cluster) return; if ((*f_clu = walk->file_cluster) == cluster) {
spin_unlock(&fat_cache_lock);
return;
}
} }
spin_unlock(&fat_cache_lock);
#ifdef DEBUG #ifdef DEBUG
printk("cache miss\n"); printk("cache miss\n");
#endif #endif
...@@ -197,6 +207,7 @@ void fat_cache_add(struct inode *inode,int f_clu,int d_clu) ...@@ -197,6 +207,7 @@ void fat_cache_add(struct inode *inode,int f_clu,int d_clu)
int first = MSDOS_I(inode)->i_start; int first = MSDOS_I(inode)->i_start;
last = NULL; last = NULL;
spin_lock(&fat_cache_lock);
for (walk = fat_cache; walk->next; walk = (last = walk)->next) for (walk = fat_cache; walk->next; walk = (last = walk)->next)
if (inode->i_dev == walk->device if (inode->i_dev == walk->device
&& walk->start_cluster == first && walk->start_cluster == first
...@@ -204,17 +215,22 @@ void fat_cache_add(struct inode *inode,int f_clu,int d_clu) ...@@ -204,17 +215,22 @@ void fat_cache_add(struct inode *inode,int f_clu,int d_clu)
if (walk->disk_cluster != d_clu) { if (walk->disk_cluster != d_clu) {
printk("FAT cache corruption inode=%ld\n", printk("FAT cache corruption inode=%ld\n",
inode->i_ino); inode->i_ino);
spin_unlock(&fat_cache_lock);
fat_cache_inval_inode(inode); fat_cache_inval_inode(inode);
return; return;
} }
/* update LRU */ /* update LRU */
if (last == NULL) return; if (last == NULL) {
spin_unlock(&fat_cache_lock);
return;
}
last->next = walk->next; last->next = walk->next;
walk->next = fat_cache; walk->next = fat_cache;
fat_cache = walk; fat_cache = walk;
#ifdef DEBUG #ifdef DEBUG
list_cache(); list_cache();
#endif #endif
spin_unlock(&fat_cache_lock);
return; return;
} }
walk->device = inode->i_dev; walk->device = inode->i_dev;
...@@ -224,6 +240,7 @@ list_cache(); ...@@ -224,6 +240,7 @@ list_cache();
last->next = NULL; last->next = NULL;
walk->next = fat_cache; walk->next = fat_cache;
fat_cache = walk; fat_cache = walk;
spin_unlock(&fat_cache_lock);
#ifdef DEBUG #ifdef DEBUG
list_cache(); list_cache();
#endif #endif
...@@ -238,10 +255,12 @@ void fat_cache_inval_inode(struct inode *inode) ...@@ -238,10 +255,12 @@ void fat_cache_inval_inode(struct inode *inode)
struct fat_cache *walk; struct fat_cache *walk;
int first = MSDOS_I(inode)->i_start; int first = MSDOS_I(inode)->i_start;
spin_lock(&fat_cache_lock);
for (walk = fat_cache; walk; walk = walk->next) for (walk = fat_cache; walk; walk = walk->next)
if (walk->device == inode->i_dev if (walk->device == inode->i_dev
&& walk->start_cluster == first) && walk->start_cluster == first)
walk->device = 0; walk->device = 0;
spin_unlock(&fat_cache_lock);
} }
...@@ -249,9 +268,11 @@ void fat_cache_inval_dev(kdev_t device) ...@@ -249,9 +268,11 @@ void fat_cache_inval_dev(kdev_t device)
{ {
struct fat_cache *walk; struct fat_cache *walk;
spin_lock(&fat_cache_lock);
for (walk = fat_cache; walk; walk = walk->next) for (walk = fat_cache; walk; walk = walk->next)
if (walk->device == device) if (walk->device == device)
walk->device = 0; walk->device = 0;
spin_unlock(&fat_cache_lock);
} }
......
...@@ -1853,6 +1853,7 @@ static int reiserfs_commit_write(struct file *f, struct page *page, ...@@ -1853,6 +1853,7 @@ static int reiserfs_commit_write(struct file *f, struct page *page,
struct reiserfs_transaction_handle th ; struct reiserfs_transaction_handle th ;
reiserfs_wait_on_write_block(inode->i_sb) ; reiserfs_wait_on_write_block(inode->i_sb) ;
lock_kernel();
prevent_flush_page_lock(page, inode) ; prevent_flush_page_lock(page, inode) ;
ret = generic_commit_write(f, page, from, to) ; ret = generic_commit_write(f, page, from, to) ;
/* we test for O_SYNC here so we can commit the transaction /* we test for O_SYNC here so we can commit the transaction
...@@ -1866,6 +1867,7 @@ static int reiserfs_commit_write(struct file *f, struct page *page, ...@@ -1866,6 +1867,7 @@ static int reiserfs_commit_write(struct file *f, struct page *page,
journal_end_sync(&th, inode->i_sb, 1) ; journal_end_sync(&th, inode->i_sb, 1) ;
} }
allow_flush_page_lock(page, inode) ; allow_flush_page_lock(page, inode) ;
unlock_kernel();
return ret ; return ret ;
} }
......
...@@ -54,6 +54,7 @@ extern void wait_for_keypress(void); ...@@ -54,6 +54,7 @@ extern void wait_for_keypress(void);
extern int root_mountflags; extern int root_mountflags;
static int do_remount_sb(struct super_block *sb, int flags, char * data); static int do_remount_sb(struct super_block *sb, int flags, char * data);
static int do_remount(const char *dir, int flags, char * data);
/* this is initialized in init/main.c */ /* this is initialized in init/main.c */
kdev_t ROOT_DEV; kdev_t ROOT_DEV;
...@@ -1025,15 +1026,12 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags) ...@@ -1025,15 +1026,12 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags)
* call reboot(9). Then init(8) could umount root and exec /reboot. * call reboot(9). Then init(8) could umount root and exec /reboot.
*/ */
if (mnt == current->fs->rootmnt && !umount_root) { if (mnt == current->fs->rootmnt && !umount_root) {
int retval = 0;
/* /*
* Special case for "unmounting" root ... * Special case for "unmounting" root ...
* we just try to remount it readonly. * we just try to remount it readonly.
*/ */
mntput(mnt); mntput(mnt);
if (!(sb->s_flags & MS_RDONLY)) return do_remount("/", MS_RDONLY, NULL);
retval = do_remount_sb(sb, MS_RDONLY, 0);
return retval;
} }
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
......
...@@ -386,6 +386,7 @@ extern void clear_page_tables(struct mm_struct *, unsigned long, int); ...@@ -386,6 +386,7 @@ extern void clear_page_tables(struct mm_struct *, unsigned long, int);
struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share); struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share);
struct file *shmem_file_setup(char * name, loff_t size); struct file *shmem_file_setup(char * name, loff_t size);
extern void shmem_lock(struct file * file, int lock);
extern int shmem_zero_setup(struct vm_area_struct *); extern int shmem_zero_setup(struct vm_area_struct *);
extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size); extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size);
......
...@@ -117,11 +117,43 @@ shmem_truncate_part (swp_entry_t * dir, unsigned long size, ...@@ -117,11 +117,43 @@ shmem_truncate_part (swp_entry_t * dir, unsigned long size,
return 0; return 0;
} }
/*
* shmem_recalc_inode - recalculate the size of an inode
*
* @inode: inode to recalc
*
* We have to calculate the free blocks since the mm can drop pages
* behind our back
*
* But we know that normally
* inodes->i_blocks == inode->i_mapping->nrpages + info->swapped
*
* So the mm freed
* inodes->i_blocks - (inode->i_mapping->nrpages + info->swapped)
*
* It has to be called with the spinlock held.
*/
static void shmem_recalc_inode(struct inode * inode)
{
unsigned long freed;
freed = inode->i_blocks -
(inode->i_mapping->nrpages + inode->u.shmem_i.swapped);
if (freed){
struct shmem_sb_info * info = &inode->i_sb->u.shmem_sb;
inode->i_blocks -= freed;
spin_lock (&info->stat_lock);
info->free_blocks += freed;
spin_unlock (&info->stat_lock);
}
}
static void shmem_truncate (struct inode * inode) static void shmem_truncate (struct inode * inode)
{ {
int clear_base; int clear_base;
unsigned long start; unsigned long start;
unsigned long mmfreed, freed = 0; unsigned long freed = 0;
swp_entry_t **base, **ptr; swp_entry_t **base, **ptr;
struct shmem_inode_info * info = &inode->u.shmem_i; struct shmem_inode_info * info = &inode->u.shmem_i;
...@@ -154,26 +186,9 @@ static void shmem_truncate (struct inode * inode) ...@@ -154,26 +186,9 @@ static void shmem_truncate (struct inode * inode)
info->i_indirect = 0; info->i_indirect = 0;
out: out:
/*
* We have to calculate the free blocks since we do not know
* how many pages the mm discarded
*
* But we know that normally
* inodes->i_blocks == inode->i_mapping->nrpages + info->swapped
*
* So the mm freed
* inodes->i_blocks - (inode->i_mapping->nrpages + info->swapped)
*/
mmfreed = inode->i_blocks - (inode->i_mapping->nrpages + info->swapped);
info->swapped -= freed; info->swapped -= freed;
inode->i_blocks -= freed + mmfreed; shmem_recalc_inode(inode);
spin_unlock (&info->lock); spin_unlock (&info->lock);
spin_lock (&inode->i_sb->u.shmem_sb.stat_lock);
inode->i_sb->u.shmem_sb.free_blocks += freed + mmfreed;
spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
} }
static void shmem_delete_inode(struct inode * inode) static void shmem_delete_inode(struct inode * inode)
...@@ -208,6 +223,7 @@ static int shmem_writepage(struct page * page) ...@@ -208,6 +223,7 @@ static int shmem_writepage(struct page * page)
return 1; return 1;
spin_lock(&info->lock); spin_lock(&info->lock);
shmem_recalc_inode(page->mapping->host);
entry = shmem_swp_entry (info, page->index); entry = shmem_swp_entry (info, page->index);
if (!entry) /* this had been allocted on page allocation */ if (!entry) /* this had been allocted on page allocation */
BUG(); BUG();
...@@ -269,6 +285,9 @@ struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, i ...@@ -269,6 +285,9 @@ struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, i
entry = shmem_swp_entry (info, idx); entry = shmem_swp_entry (info, idx);
if (!entry) if (!entry)
goto oom; goto oom;
spin_lock (&info->lock);
shmem_recalc_inode(inode);
spin_unlock (&info->lock);
if (entry->val) { if (entry->val) {
unsigned long flags; unsigned long flags;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment