summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <greg@kroah.com>2004-09-12 20:02:40 -0700
committerGreg Kroah-Hartman <greg@kroah.com>2004-09-12 20:02:40 -0700
commit2a69c9cd33412d9a7f393dcd9382ab9ed034d3fa (patch)
tree26e60a470b9eb566c327aa64a4d7453423549a23
parent8a690d16e64e76f884d74128dc10ac6b28c135d2 (diff)
parent26d61c640c05c6cf04987437fad260908faaddf7 (diff)
Merge kroah.com:/home/greg/linux/BK/bleed-2.6
into kroah.com:/home/greg/linux/BK/usb-2.6
-rw-r--r--CREDITS2
-rw-r--r--Documentation/kernel-parameters.txt2
-rw-r--r--Documentation/usb/sn9c102.txt100
-rw-r--r--MAINTAINERS12
-rw-r--r--drivers/block/ub.c59
-rw-r--r--drivers/pci/quirks.c230
-rw-r--r--drivers/usb/class/Kconfig3
-rw-r--r--drivers/usb/class/audio.c21
-rw-r--r--drivers/usb/class/usb-midi.c11
-rw-r--r--drivers/usb/class/usblp.c4
-rw-r--r--drivers/usb/core/devices.c12
-rw-r--r--drivers/usb/core/devio.c17
-rw-r--r--drivers/usb/core/hcd-pci.c4
-rw-r--r--drivers/usb/core/hcd.c29
-rw-r--r--drivers/usb/core/hcd.h4
-rw-r--r--drivers/usb/core/hub.c123
-rw-r--r--drivers/usb/core/inode.c121
-rw-r--r--drivers/usb/core/urb.c5
-rw-r--r--drivers/usb/core/usb.h8
-rw-r--r--drivers/usb/gadget/ether.c6
-rw-r--r--drivers/usb/gadget/file_storage.c30
-rw-r--r--drivers/usb/gadget/gadget_chips.h6
-rw-r--r--drivers/usb/gadget/omap_udc.c144
-rw-r--r--drivers/usb/gadget/omap_udc.h11
-rw-r--r--drivers/usb/gadget/zero.c2
-rw-r--r--drivers/usb/host/ehci-hcd.c9
-rw-r--r--drivers/usb/host/ehci.h1
-rw-r--r--drivers/usb/host/hc_sl811.c8
-rw-r--r--drivers/usb/host/ohci-dbg.c4
-rw-r--r--drivers/usb/host/ohci-hcd.c104
-rw-r--r--drivers/usb/host/ohci-hub.c9
-rw-r--r--drivers/usb/host/ohci-pci.c18
-rw-r--r--drivers/usb/host/ohci.h6
-rw-r--r--drivers/usb/host/uhci-hcd.c2
-rw-r--r--drivers/usb/host/uhci-hcd.h6
-rw-r--r--drivers/usb/host/uhci-hub.c140
-rw-r--r--drivers/usb/image/Kconfig7
-rw-r--r--drivers/usb/image/microtek.c6
-rw-r--r--drivers/usb/input/hid-core.c11
-rw-r--r--drivers/usb/media/Kconfig6
-rw-r--r--drivers/usb/media/dabusb.c6
-rw-r--r--drivers/usb/media/konicawc.c2
-rw-r--r--drivers/usb/media/sn9c102.h15
-rw-r--r--drivers/usb/media/sn9c102_core.c124
-rw-r--r--drivers/usb/media/sn9c102_pas106b.c14
-rw-r--r--drivers/usb/media/sn9c102_pas202bcb.c12
-rw-r--r--drivers/usb/media/sn9c102_sensor.h58
-rw-r--r--drivers/usb/media/sn9c102_tas5110c1b.c45
-rw-r--r--drivers/usb/media/sn9c102_tas5130d1b.c60
-rw-r--r--drivers/usb/misc/tiglusb.c1
-rw-r--r--drivers/usb/net/kaweth.c2
-rw-r--r--drivers/usb/net/rtl8150.c4
-rw-r--r--drivers/usb/serial/belkin_sa.c8
-rw-r--r--drivers/usb/serial/cyberjack.c6
-rw-r--r--drivers/usb/serial/digi_acceleport.c13
-rw-r--r--drivers/usb/serial/empeg.c8
-rw-r--r--drivers/usb/serial/ftdi_sio.c21
-rw-r--r--drivers/usb/serial/ftdi_sio.h8
-rw-r--r--drivers/usb/serial/generic.c4
-rw-r--r--drivers/usb/serial/io_edgeport.c6
-rw-r--r--drivers/usb/serial/io_ti.c6
-rw-r--r--drivers/usb/serial/ipaq.c23
-rw-r--r--drivers/usb/serial/ir-usb.c2
-rw-r--r--drivers/usb/serial/keyspan_pda.c6
-rw-r--r--drivers/usb/serial/kl5kusb105.c12
-rw-r--r--drivers/usb/serial/kobil_sct.c14
-rw-r--r--drivers/usb/serial/mct_u232.c6
-rw-r--r--drivers/usb/serial/omninet.c4
-rw-r--r--drivers/usb/serial/pl2303.c430
-rw-r--r--drivers/usb/serial/usb-serial.c14
-rw-r--r--drivers/usb/serial/visor.c6
-rw-r--r--drivers/usb/serial/whiteheat.c8
-rw-r--r--drivers/usb/storage/isd200.c6
-rw-r--r--drivers/usb/storage/protocol.c49
-rw-r--r--drivers/usb/storage/scsiglue.c17
-rw-r--r--drivers/usb/storage/unusual_devs.h33
-rw-r--r--include/asm-i386/mach-summit/mach_mpparse.h3
-rw-r--r--include/linux/usb.h2
-rw-r--r--include/linux/usbdevice_fs.h10
79 files changed, 1605 insertions, 766 deletions
diff --git a/CREDITS b/CREDITS
index bb348015fb77..644ee6b2dffb 100644
--- a/CREDITS
+++ b/CREDITS
@@ -2763,7 +2763,7 @@ N: Luca Risolia
E: luca.risolia@studio.unibo.it
P: 1024D/FCE635A4 88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4
D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chips
-D: V4L2 driver for SN9C10[12] PC Camera Controllers
+D: V4L2 driver for SN9C10x PC Camera Controllers
S: Via Liberta' 41/A
S: Osio Sotto, 24046, Bergamo
S: Italy
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index ae0eb1a3d4e4..393986feb77e 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1270,6 +1270,8 @@ running once the system is up.
uart6850= [HW,OSS]
Format: <io>,<irq>
+
+ usb-handoff [HW] Enable early USB BIOS -> OS handoff
video= [FB] Frame buffer configuration
See Documentation/fb/modedb.txt.
diff --git a/Documentation/usb/sn9c102.txt b/Documentation/usb/sn9c102.txt
index 3999069b94bc..ea4f4274b371 100644
--- a/Documentation/usb/sn9c102.txt
+++ b/Documentation/usb/sn9c102.txt
@@ -1,7 +1,7 @@
- SN9C10[12] PC Camera Controllers
+ SN9C10x PC Camera Controllers
Driver for Linux
- ================================
+ =============================
- Documentation -
@@ -49,22 +49,23 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
3. Overview
===========
-This driver attempts to support the video streaming capabilities of the devices
-mounting the SONiX SN9C101 or SONiX SN9C102 PC Camera Controllers.
+This driver attempts to support the video and audio streaming capabilities of
+the devices mounting the SONiX SN9C101, SN9C102 and SN9C103 (or SUI-102) PC
+Camera Controllers.
- It's worth to note that SONiX has never collaborated with me during the
-development of this project, despite of several requests for enough detailed
+development of this project, despite several requests for enough detailed
specifications of the register tables, compression engine and video data format
of the above chips -
Up to 64 cameras can be handled at the same time. They can be connected and
disconnected from the host many times without turning off the computer, if
-your system supports the hotplug facility.
+your system supports hotplugging.
The driver relies on the Video4Linux2 and USB core modules. It has been
designed to run properly on SMP systems as well.
-The latest version of the SN9C10[12] driver can be found at the following URL:
+The latest version of the SN9C10x driver can be found at the following URL:
http://go.lamarinapunto.com/
@@ -150,17 +151,20 @@ Default: 2
7. Optional device control through "sysfs"
==========================================
-It is possible to read and write both the SN9C10[12] and the image sensor
+It is possible to read and write both the SN9C10x and the image sensor
registers by using the "sysfs" filesystem interface.
-Every time a supported device is recognized, a read-only file named "green" is
+Every time a supported device is recognized, a write-only file named "green" is
created in the /sys/class/video4linux/videoX directory. You can set the green
channel's gain by writing the desired value to it. The value may range from 0
-to 15.
+to 15 for SN9C101 or SN9C102 bridges, from 0 to 127 for SN9C103 bridges.
+Similarly, only for SN9C103 controllers, blue and red gain control files are
+available in the same directory, for which accepted values may range from 0 to
+127.
There are other four entries in the directory above for each registered camera:
"reg", "val", "i2c_reg" and "i2c_val". The first two files control the
-SN9C10[12] bridge, while the other two control the sensor chip. "reg" and
+SN9C10x bridge, while the other two control the sensor chip. "reg" and
"i2c_reg" hold the values of the current register index where the following
reading/writing operations are addressed at through "val" and "i2c_val". Their
use is not intended for end-users, unless you know what you are doing. Note
@@ -169,19 +173,19 @@ support the standard I2C protocol. Also, remember that you must be logged in as
root before writing to them.
As an example, suppose we were to want to read the value contained in the
-register number 1 of the sensor register table - which usually is the product
+register number 1 of the sensor register table - which is usually the product
identifier - of the camera registered as "/dev/video0":
[root@localhost #] cd /sys/class/video4linux/video0
[root@localhost #] echo 1 > i2c_reg
[root@localhost #] cat i2c_val
-Now let's set the green gain's register of the SN9C10[12] chip to 2:
+Now let's set the green gain's register of the SN9C10x chip to 2:
[root@localhost #] echo 0x11 > reg
[root@localhost #] echo 2 > val
-Note that the SN9C10[12] always returns 0 when some of its registers are read.
+Note that the SN9C10x always returns 0 when some of its registers are read.
To avoid race conditions, all the I/O accesses to the files are serialized.
@@ -192,25 +196,52 @@ here. They have never collaborated with me, so no advertising -
From the point of view of a driver, what unambiguously identify a device are
its vendor and product USB identifiers. Below is a list of known identifiers of
-devices mounting the SN9C10[12] PC camera controllers:
+devices mounting the SN9C10x PC camera controllers:
Vendor ID Product ID
--------- ----------
-0xc45 0x6001
-0xc45 0x6005
-0xc45 0x6009
-0xc45 0x600d
-0xc45 0x6024
-0xc45 0x6025
-0xc45 0x6028
-0xc45 0x6029
-0xc45 0x602a
-0xc45 0x602c
-0xc45 0x6030
+0x0c45 0x6001
+0x0c45 0x6005
+0x0c45 0x6009
+0x0c45 0x600d
+0x0c45 0x6024
+0x0c45 0x6025
+0x0c45 0x6028
+0x0c45 0x6029
+0x0c45 0x602a
+0x0c45 0x602b
+0x0c45 0x602c
+0x0c45 0x6030
+0x0c45 0x6080
+0x0c45 0x6082
+0x0c45 0x6083
+0x0c45 0x6088
+0x0c45 0x608a
+0x0c45 0x608b
+0x0c45 0x608c
+0x0c45 0x608e
+0x0c45 0x608f
+0x0c45 0x60a0
+0x0c45 0x60a2
+0x0c45 0x60a3
+0x0c45 0x60a8
+0x0c45 0x60aa
+0x0c45 0x60ab
+0x0c45 0x60ac
+0x0c45 0x60ae
+0x0c45 0x60af
+0x0c45 0x60b0
+0x0c45 0x60b2
+0x0c45 0x60b3
+0x0c45 0x60b8
+0x0c45 0x60ba
+0x0c45 0x60bb
+0x0c45 0x60bc
+0x0c45 0x60be
The list above does NOT imply that all those devices work with this driver: up
-until now only the ones that mount the following image sensors are supported.
-Kernel messages will always tell you whether this is the case:
+until now only the ones that mount the following image sensors are supported;
+kernel messages will always tell you whether this is the case:
Model Manufacturer
----- ------------
@@ -224,7 +255,7 @@ listed in the above table, you may try to add the specific USB VendorID and
ProductID identifiers to the sn9c102_id_table[] in the file "sn9c102_sensor.h";
then compile, load the module again and look at the kernel output.
If this works, please send an email to me reporting the kernel messages, so
-that I will add a new entry in the list of supported devices.
+that I can add a new entry in the list of supported devices.
Donations of new models for further testing and support would be much
appreciated. I won't add official support for hardware that I don't actually
@@ -238,8 +269,8 @@ have created for this purpose, which is present in "sn9c102_sensor.h"
(documentation is included there). As an example, have a look at the code in
"sn9c102_pas106b.c", which uses the mentioned interface.
-At the moment, not yet supported image sensors are: HV7131[D|E1] (VGA),
-MI03 (VGA), OV7620 (VGA).
+At the moment, possible unsupported image sensors are: HV7131x series (VGA),
+MI03x series (VGA), OV7620 (VGA), OV7630 (VGA), CIS-VF10 (VGA).
10. Notes for V4L2 application developers
@@ -254,12 +285,13 @@ device to switch to the other I/O method;
- previously mapped buffer memory must always be unmapped before calling any
of the "VIDIOC_S_CROP", "VIDIOC_TRY_FMT" and "VIDIOC_S_FMT" ioctl's. The same
number of buffers as before will be allocated again to match the size of the
-new video frames, so you have to map them again before any I/O attempts.
+new video frames, so you have to map the buffers again before any I/O attempts
+on them.
Consistently with the hardware limits, this driver also supports image
downscaling with arbitrary scaling factors from 1, 2 and 4 in both directions.
-However the V4L2 API specifications don't correctly define how the scaling
-factor can be choosen arbitrarily by the "negotiation" of the "source" and
+However, the V4L2 API specifications don't correctly define how the scaling
+factor can be chosen arbitrarily by the "negotiation" of the "source" and
"target" rectangles. To work around this flaw, we have added the convention
that, during the negotiation, whenever the "VIDIOC_S_CROP" ioctl is issued, the
scaling factor is restored to 1.
diff --git a/MAINTAINERS b/MAINTAINERS
index c1a5296a74c7..bc43c45c6a7c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -947,7 +947,7 @@ S: Maintained
HPUSBSCSI
P: Oliver Neukum
-M: drivers@neukum.org
+M: oliver@neukum.name
S: Maintained
I2C AND SENSORS DRIVERS
@@ -1428,7 +1428,7 @@ S: Maintained
MICROTEK X6 SCANNER
P: Oliver Neukum
-M: drivers@neukum.org
+M: oliver@neukum.name
S: Maintained
MIPS
@@ -2192,8 +2192,8 @@ W: http://www.kernel.dk
S: Maintained
USB ACM DRIVER
-P: Vojtech Pavlik
-M: vojtech@suse.cz
+P: Oliver Neukum
+M: oliver@neukum.name
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
S: Maintained
@@ -2237,7 +2237,7 @@ S: Maintained
USB KAWASAKI LSI DRIVER
P: Oliver Neukum
-M: drivers@neukum.org
+M: oliver@neukum.name
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
S: Maintained
@@ -2354,7 +2354,7 @@ L: linux-usb-devel@lists.sourceforge.net
W: http://www.connecttech.com
S: Supported
-USB SN9C10[12] DRIVER
+USB SN9C10x DRIVER
P: Luca Risolia
M: luca.risolia@studio.unibo.it
L: linux-usb-devel@lists.sourceforge.net
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index f605535d3f56..6379b9043631 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -786,17 +786,16 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
- sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
- add_timer(&sc->work_timer);
-
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
/* XXX Clear stalls */
printk("ub: cmd #%d start failed (%d)\n", cmd->tag, rc); /* P3 */
- del_timer(&sc->work_timer);
ub_complete(&sc->work_done);
return rc;
}
+ sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
+ add_timer(&sc->work_timer);
+
cmd->state = UB_CMDST_CMD;
ub_cmdtr_state(sc, cmd);
return 0;
@@ -968,18 +967,17 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
- sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
- add_timer(&sc->work_timer);
-
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
/* XXX Clear stalls */
printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */
- del_timer(&sc->work_timer);
ub_complete(&sc->work_done);
ub_state_done(sc, cmd, rc);
return;
}
+ sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
+ add_timer(&sc->work_timer);
+
cmd->state = UB_CMDST_DATA;
ub_cmdtr_state(sc, cmd);
@@ -1063,19 +1061,18 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
- sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
- add_timer(&sc->work_timer);
-
rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC);
if (rc != 0) {
/* XXX Clear stalls */
printk("%s: CSW #%d submit failed (%d)\n",
sc->name, cmd->tag, rc); /* P3 */
- del_timer(&sc->work_timer);
ub_complete(&sc->work_done);
ub_state_done(sc, cmd, rc);
return;
}
+
+ sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
+ add_timer(&sc->work_timer);
return;
}
@@ -1186,18 +1183,17 @@ static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
- sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
- add_timer(&sc->work_timer);
-
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
/* XXX Clear stalls */
printk("ub: CSW #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */
- del_timer(&sc->work_timer);
ub_complete(&sc->work_done);
ub_state_done(sc, cmd, rc);
return;
}
+ sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
+ add_timer(&sc->work_timer);
+
cmd->stat_count = 0;
cmd->state = UB_CMDST_STAT;
ub_cmdtr_state(sc, cmd);
@@ -1217,9 +1213,17 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
goto error;
}
+ /*
+ * ``If the allocation length is eighteen or greater, and a device
+ * server returns less than eithteen bytes of data, the application
+ * client should assume that the bytes not transferred would have been
+ * zeroes had the device server returned those bytes.''
+ */
memset(&sc->top_sense, 0, UB_SENSE_SIZE);
+
scmd = &sc->top_rqs_cmd;
scmd->cdb[0] = REQUEST_SENSE;
+ scmd->cdb[4] = UB_SENSE_SIZE;
scmd->cdb_len = 6;
scmd->dir = UB_DIR_READ;
scmd->state = UB_CMDST_INIT;
@@ -1271,14 +1275,13 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
- sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT;
- add_timer(&sc->work_timer);
-
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
- del_timer(&sc->work_timer);
ub_complete(&sc->work_done);
return rc;
}
+
+ sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT;
+ add_timer(&sc->work_timer);
return 0;
}
@@ -1289,6 +1292,9 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
unsigned char *sense = scmd->data;
struct ub_scsi_cmd *cmd;
+ /*
+ * Ignoring scmd->act_len, because the buffer was pre-zeroed.
+ */
ub_cmdtr_sense(sc, scmd, sense);
if ((cmd = ub_cmdq_peek(sc)) == NULL) {
@@ -1725,19 +1731,18 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
- init_timer(&timer);
- timer.function = ub_probe_timeout;
- timer.data = (unsigned long) &compl;
- timer.expires = jiffies + UB_CTRL_TIMEOUT;
- add_timer(&timer);
-
if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
printk(KERN_WARNING
"%s: Unable to submit a probe clear (%d)\n", sc->name, rc);
- del_timer_sync(&timer);
return rc;
}
+ init_timer(&timer);
+ timer.function = ub_probe_timeout;
+ timer.data = (unsigned long) &compl;
+ timer.expires = jiffies + UB_CTRL_TIMEOUT;
+ add_timer(&timer);
+
wait_for_completion(&compl);
del_timer_sync(&timer);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 164f738df6a7..34f072c9823e 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -826,6 +826,236 @@ static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
pci_read_config_byte(dev, 0x77, &val);
}
+
+#define UHCI_USBLEGSUP 0xc0 /* legacy support */
+#define UHCI_USBCMD 0 /* command register */
+#define UHCI_USBSTS 2 /* status register */
+#define UHCI_USBINTR 4 /* interrupt register */
+#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
+#define UHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */
+#define UHCI_USBCMD_GRESET (1 << 2) /* Global reset */
+#define UHCI_USBCMD_CONFIGURE (1 << 6) /* config semaphore */
+#define UHCI_USBSTS_HALTED (1 << 5) /* HCHalted bit */
+
+#define OHCI_CONTROL 0x04
+#define OHCI_CMDSTATUS 0x08
+#define OHCI_INTRSTATUS 0x0c
+#define OHCI_INTRENABLE 0x10
+#define OHCI_INTRDISABLE 0x14
+#define OHCI_OCR (1 << 3) /* ownership change request */
+#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
+#define OHCI_INTR_OC (1 << 30) /* ownership change */
+
+#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */
+#define EHCI_USBCMD 0 /* command register */
+#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */
+#define EHCI_USBSTS 4 /* status register */
+#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */
+#define EHCI_USBINTR 8 /* interrupt register */
+#define EHCI_USBLEGSUP 0 /* legacy support register */
+#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */
+#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */
+#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */
+#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */
+
+int usb_early_handoff __initdata = 0;
+static int __init usb_handoff_early(char *str)
+{
+ usb_early_handoff = 1;
+ return 0;
+}
+__setup("usb-handoff", usb_handoff_early);
+
+static void __init quirk_usb_handoff_uhci(struct pci_dev *pdev)
+{
+ unsigned long base = 0;
+ int wait_time, delta;
+ u16 val, sts;
+ int i;
+
+ for (i = 0; i < PCI_ROM_RESOURCE; i++)
+ if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
+ base = pci_resource_start(pdev, i);
+ break;
+ }
+
+ if (!base)
+ return;
+
+ /*
+ * stop controller
+ */
+ sts = inw(base + UHCI_USBSTS);
+ val = inw(base + UHCI_USBCMD);
+ val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE);
+ outw(val, base + UHCI_USBCMD);
+
+ /*
+ * wait while it stops if it was running
+ */
+ if ((sts & UHCI_USBSTS_HALTED) == 0)
+ {
+ wait_time = 1000;
+ delta = 100;
+
+ do {
+ outw(0x1f, base + UHCI_USBSTS);
+ udelay(delta);
+ wait_time -= delta;
+ val = inw(base + UHCI_USBSTS);
+ if (val & UHCI_USBSTS_HALTED)
+ break;
+ } while (wait_time > 0);
+ }
+
+ /*
+ * disable interrupts & legacy support
+ */
+ outw(0, base + UHCI_USBINTR);
+ outw(0x1f, base + UHCI_USBSTS);
+ pci_read_config_word(pdev, UHCI_USBLEGSUP, &val);
+ if (val & 0xbf)
+ pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT);
+
+}
+
+static void __init quirk_usb_handoff_ohci(struct pci_dev *pdev)
+{
+ char *base;
+ int wait_time;
+
+ base = ioremap_nocache(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (base == NULL) return;
+
+ if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
+ wait_time = 500; /* 0.5 seconds */
+ writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
+ writel(OHCI_OCR, base + OHCI_CMDSTATUS);
+ while (wait_time > 0 &&
+ readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
+ wait_time -= 10;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((HZ*10 + 999) / 1000);
+ }
+ }
+
+ /*
+ * disable interrupts
+ */
+ writel(~(u32)0, base + OHCI_INTRDISABLE);
+ writel(~(u32)0, base + OHCI_INTRSTATUS);
+
+ iounmap(base);
+}
+
+static void __init quirk_usb_disable_ehci(struct pci_dev *pdev)
+{
+ int wait_time, delta;
+ char *base, *op_reg_base;
+ u32 hcc_params, val, temp;
+ u8 cap_length;
+
+ base = ioremap_nocache(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (base == NULL) return;
+
+ cap_length = readb(base);
+ op_reg_base = base + cap_length;
+ hcc_params = readl(base + EHCI_HCC_PARAMS);
+ hcc_params = (hcc_params >> 8) & 0xff;
+ if (hcc_params) {
+ pci_read_config_dword(pdev,
+ hcc_params + EHCI_USBLEGSUP,
+ &val);
+ if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) {
+ /*
+ * Ok, BIOS is in smm mode, try to hand off...
+ */
+ pci_read_config_dword(pdev,
+ hcc_params + EHCI_USBLEGCTLSTS,
+ &temp);
+ pci_write_config_dword(pdev,
+ hcc_params + EHCI_USBLEGCTLSTS,
+ temp | EHCI_USBLEGCTLSTS_SOOE);
+ val |= EHCI_USBLEGSUP_OS;
+ pci_write_config_dword(pdev,
+ hcc_params + EHCI_USBLEGSUP,
+ val);
+
+ wait_time = 500;
+ do {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((HZ*10+999)/1000);
+ wait_time -= 10;
+ pci_read_config_dword(pdev,
+ hcc_params + EHCI_USBLEGSUP,
+ &val);
+ } while (wait_time && (val & EHCI_USBLEGSUP_BIOS));
+ if (!wait_time) {
+ /*
+ * well, possibly buggy BIOS...
+ */
+ printk(KERN_WARNING "EHCI early BIOS handoff "
+ "failed (BIOS bug ?)\n");
+ pci_write_config_dword(pdev,
+ hcc_params + EHCI_USBLEGSUP,
+ EHCI_USBLEGSUP_OS);
+ pci_write_config_dword(pdev,
+ hcc_params + EHCI_USBLEGCTLSTS,
+ 0);
+ }
+ }
+ }
+
+ /*
+ * halt EHCI & disable its interrupts in any case
+ */
+ val = readl(op_reg_base + EHCI_USBSTS);
+ if ((val & EHCI_USBSTS_HALTED) == 0) {
+ val = readl(op_reg_base + EHCI_USBCMD);
+ val &= ~EHCI_USBCMD_RUN;
+ writel(val, op_reg_base + EHCI_USBCMD);
+
+ wait_time = 2000;
+ delta = 100;
+ do {
+ writel(0x3f, op_reg_base + EHCI_USBSTS);
+ udelay(delta);
+ wait_time -= delta;
+ val = readl(op_reg_base + EHCI_USBSTS);
+ if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
+ break;
+ }
+ } while (wait_time > 0);
+ }
+ writel(0, op_reg_base + EHCI_USBINTR);
+ writel(0x3f, op_reg_base + EHCI_USBSTS);
+
+ iounmap(base);
+
+ return;
+}
+
+
+
+static void __init quirk_usb_early_handoff(struct pci_dev *pdev)
+{
+ if (!usb_early_handoff)
+ return;
+
+ if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */
+ quirk_usb_handoff_uhci(pdev);
+ } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */
+ quirk_usb_handoff_ohci(pdev);
+ } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */
+ quirk_usb_disable_ehci(pdev);
+ }
+
+ return;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
+
/*
* ... This is further complicated by the fact that some SiS96x south
* bridges pretend to be 85C503/5513 instead. In that case see if we
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
index 3d49e9d8cb67..0561d0234f23 100644
--- a/drivers/usb/class/Kconfig
+++ b/drivers/usb/class/Kconfig
@@ -9,7 +9,8 @@ config USB_AUDIO
depends on USB && SOUND
help
Say Y here if you want to connect USB audio equipment such as
- speakers to your computer's USB port.
+ speakers to your computer's USB port. You only need this if you use
+ the OSS sound driver; ALSA has its own option for usb audio support.
To compile this driver as a module, choose M here: the
module will be called audio.
diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c
index 17a6dd74713f..36b3f3663e62 100644
--- a/drivers/usb/class/audio.c
+++ b/drivers/usb/class/audio.c
@@ -1949,15 +1949,12 @@ static inline int prog_dmabuf_out(struct usb_audiodev *as)
static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
- struct list_head *devs, *mdevs;
struct usb_mixerdev *ms;
struct usb_audio_state *s;
down(&open_sem);
- list_for_each(devs, &audiodevs) {
- s = list_entry(devs, struct usb_audio_state, audiodev);
- list_for_each(mdevs, &s->mixerlist) {
- ms = list_entry(mdevs, struct usb_mixerdev, list);
+ list_for_each_entry(s, &audiodevs, audiodev) {
+ list_for_each_entry(ms, &s->mixerlist, list) {
if (ms->dev_mixer == minor)
goto mixer_found;
}
@@ -2634,16 +2631,13 @@ static int usb_audio_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
DECLARE_WAITQUEUE(wait, current);
- struct list_head *devs, *adevs;
struct usb_audiodev *as;
struct usb_audio_state *s;
for (;;) {
down(&open_sem);
- list_for_each(devs, &audiodevs) {
- s = list_entry(devs, struct usb_audio_state, audiodev);
- list_for_each(adevs, &s->audiolist) {
- as = list_entry(adevs, struct usb_audiodev, list);
+ list_for_each_entry(s, &audiodevs, audiodev) {
+ list_for_each_entry(as, &s->audiolist, list) {
if (!((as->dev_audio ^ minor) & ~0xf))
goto device_found;
}
@@ -3809,7 +3803,6 @@ static int usb_audio_probe(struct usb_interface *intf,
static void usb_audio_disconnect(struct usb_interface *intf)
{
struct usb_audio_state *s = usb_get_intfdata (intf);
- struct list_head *list;
struct usb_audiodev *as;
struct usb_mixerdev *ms;
@@ -3831,8 +3824,7 @@ static void usb_audio_disconnect(struct usb_interface *intf)
usb_set_intfdata (intf, NULL);
/* deregister all audio and mixer devices, so no new processes can open this device */
- list_for_each(list, &s->audiolist) {
- as = list_entry(list, struct usb_audiodev, list);
+ list_for_each_entry(as, &s->audiolist, list) {
usbin_disc(as);
usbout_disc(as);
wake_up(&as->usbin.dma.wait);
@@ -3843,8 +3835,7 @@ static void usb_audio_disconnect(struct usb_interface *intf)
}
as->dev_audio = -1;
}
- list_for_each(list, &s->mixerlist) {
- ms = list_entry(list, struct usb_mixerdev, list);
+ list_for_each_entry(ms, &s->mixerlist, list) {
if (ms->dev_mixer >= 0) {
unregister_sound_mixer(ms->dev_mixer);
printk(KERN_INFO "usbaudio: unregister mixer 14,%d\n", ms->dev_mixer);
diff --git a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c
index a9dc047a04a7..c4192ea52269 100644
--- a/drivers/usb/class/usb-midi.c
+++ b/drivers/usb/class/usb-midi.c
@@ -805,7 +805,6 @@ static int usb_midi_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
DECLARE_WAITQUEUE(wait, current);
- struct list_head *devs, *mdevs;
struct usb_midi_state *s;
struct usb_mididev *m;
unsigned long flags;
@@ -817,10 +816,8 @@ static int usb_midi_open(struct inode *inode, struct file *file)
for(;;) {
down(&open_sem);
- list_for_each(devs, &mididevs) {
- s = list_entry(devs, struct usb_midi_state, mididev);
- list_for_each(mdevs, &s->midiDevList) {
- m = list_entry(mdevs, struct usb_mididev, list);
+ list_for_each_entry(s, &mididevs, mididev) {
+ list_for_each_entry(m, &s->midiDevList, list) {
if ( !((m->dev_midi ^ minor) & ~0xf) )
goto device_found;
}
@@ -1994,7 +1991,6 @@ static int usb_midi_probe(struct usb_interface *intf,
static void usb_midi_disconnect(struct usb_interface *intf)
{
struct usb_midi_state *s = usb_get_intfdata (intf);
- struct list_head *list;
struct usb_mididev *m;
if ( !s )
@@ -2012,8 +2008,7 @@ static void usb_midi_disconnect(struct usb_interface *intf)
s->usbdev = NULL;
usb_set_intfdata (intf, NULL);
- list_for_each(list, &s->midiDevList) {
- m = list_entry(list, struct usb_mididev, list);
+ list_for_each_entry(m, &s->midiDevList, list) {
wake_up(&(m->min.ep->wait));
wake_up(&(m->mout.ep->wait));
if ( m->dev_midi >= 0 ) {
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index dd6950e674f4..3174bf78fefc 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -410,9 +410,9 @@ static void usblp_cleanup (struct usblp *usblp)
static void usblp_unlink_urbs(struct usblp *usblp)
{
- usb_unlink_urb(usblp->writeurb);
+ usb_kill_urb(usblp->writeurb);
if (usblp->bidir)
- usb_unlink_urb(usblp->readurb);
+ usb_kill_urb(usblp->readurb);
}
static int usblp_release(struct inode *inode, struct file *file)
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 8e535789fce7..195e365675af 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -149,7 +149,7 @@ static const struct class_info clas_info[] =
/*****************************************************************/
-void usbdevfs_conn_disc_event(void)
+void usbfs_conn_disc_event(void)
{
conndiscevcnt++;
wake_up(&deviceconndiscwq);
@@ -569,7 +569,6 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
- struct list_head *buslist;
struct usb_bus *bus;
ssize_t ret, total_written = 0;
loff_t skip_bytes = *ppos;
@@ -581,12 +580,9 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
if (!access_ok(VERIFY_WRITE, buf, nbytes))
return -EFAULT;
- /* enumerate busses */
down (&usb_bus_list_lock);
- list_for_each(buslist, &usb_bus_list) {
- /* print devices for this bus */
- bus = list_entry(buslist, struct usb_bus, bus_list);
-
+ /* print devices for all busses */
+ list_for_each_entry(bus, &usb_bus_list, bus_list) {
/* recurse through all children of the root hub */
if (!bus->root_hub)
continue;
@@ -682,7 +678,7 @@ static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
return ret;
}
-struct file_operations usbdevfs_devices_fops = {
+struct file_operations usbfs_devices_fops = {
.llseek = usb_device_lseek,
.read = usb_device_read,
.poll = usb_device_poll,
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 776c1bf0df9b..0b3bf6634ee4 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -21,7 +21,7 @@
*
* $Id: devio.c,v 1.7 2000/02/01 17:28:48 fliegl Exp $
*
- * This file implements the usbdevfs/x/y files, where
+ * This file implements the usbfs/x/y files, where
* x is the bus number and y the device number.
*
* It allows user space programs/"drivers" to communicate directly
@@ -286,9 +286,10 @@ static void destroy_async (struct dev_state *ps, struct list_head *list)
while (!list_empty(list)) {
as = list_entry(list->next, struct async, asynclist);
list_del_init(&as->asynclist);
+
+ /* drop the spinlock so the completion handler can run */
spin_unlock_irqrestore(&ps->lock, flags);
- /* usb_unlink_urb calls the completion handler with status == -ENOENT */
- usb_unlink_urb(as->urb);
+ usb_kill_urb(as->urb);
spin_lock_irqsave(&ps->lock, flags);
}
spin_unlock_irqrestore(&ps->lock, flags);
@@ -353,7 +354,7 @@ static void driver_disconnect(struct usb_interface *intf)
destroy_async_on_interface(ps, ifnum);
}
-struct usb_driver usbdevfs_driver = {
+struct usb_driver usbfs_driver = {
.owner = THIS_MODULE,
.name = "usbfs",
.probe = driver_probe,
@@ -378,7 +379,7 @@ static int claimintf(struct dev_state *ps, unsigned int ifnum)
if (!intf)
err = -ENOENT;
else
- err = usb_driver_claim_interface(&usbdevfs_driver, intf, ps);
+ err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
up_write(&usb_bus_type.subsys.rwsem);
if (err == 0)
set_bit(ifnum, &ps->ifclaimed);
@@ -401,7 +402,7 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum)
if (!intf)
err = -ENOENT;
else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) {
- usb_driver_release_interface(&usbdevfs_driver, intf);
+ usb_driver_release_interface(&usbfs_driver, intf);
err = 0;
}
up_write(&usb_bus_type.subsys.rwsem);
@@ -976,7 +977,7 @@ static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
as = async_getpending(ps, arg);
if (!as)
return -EINVAL;
- usb_unlink_urb(as->urb);
+ usb_kill_urb(as->urb);
return 0;
}
@@ -1314,7 +1315,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai
return mask;
}
-struct file_operations usbdevfs_device_file_operations = {
+struct file_operations usbfs_device_file_operations = {
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index e7a7ba51371f..f6f9c3b2325c 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -188,9 +188,9 @@ clean_3:
}
hcd->irq = dev->irq;
- dev_info (hcd->self.controller, "irq %s, %s %p\n", bufp,
+ dev_info (hcd->self.controller, "irq %s, %s 0x%lx\n", bufp,
(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
- base);
+ resource);
usb_bus_init (&hcd->self);
hcd->self.op = &usb_hcd_operations;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 08a3378bc875..c1de465a10d1 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1263,7 +1263,7 @@ static int hcd_unlink_urb (struct urb *urb, int status)
* never get completion IRQs ... maybe even the ones we need to
* finish unlinking the initial failed usb_set_address().
*/
- if (!hcd->saw_irq) {
+ if (!hcd->saw_irq && hcd->rh_timer.data != (unsigned long) urb) {
dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
"Different ACPI or APIC settings may help."
"\n");
@@ -1572,13 +1572,12 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
struct usb_hcd *hcd = __hcd;
int start = hcd->state;
- if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
+ if (start == USB_STATE_HALT)
return IRQ_NONE;
-
- hcd->saw_irq = 1;
if (hcd->driver->irq (hcd, r) == IRQ_NONE)
return IRQ_NONE;
+ hcd->saw_irq = 1;
if (hcd->state != start && hcd->state == USB_STATE_HALT)
usb_hc_died (hcd);
return IRQ_HANDLED;
@@ -1587,22 +1586,6 @@ EXPORT_SYMBOL (usb_hcd_irq);
/*-------------------------------------------------------------------------*/
-static void hcd_panic (void *_hcd)
-{
- struct usb_hcd *hcd = _hcd;
- struct usb_device *hub = hcd->self.root_hub;
- unsigned i;
-
- /* hc's root hub is removed later removed in hcd->stop() */
- down (&hub->serialize);
- usb_set_device_state(hub, USB_STATE_NOTATTACHED);
- for (i = 0; i < hub->maxchild; i++) {
- if (hub->children [i])
- usb_disconnect (&hub->children [i]);
- }
- up (&hub->serialize);
-}
-
/**
* usb_hc_died - report abnormal shutdown of a host controller (bus glue)
* @hcd: pointer to the HCD representing the controller
@@ -1615,9 +1598,9 @@ void usb_hc_died (struct usb_hcd *hcd)
{
dev_err (hcd->self.controller, "HC died; cleaning up\n");
- /* clean up old urbs and devices; needs a task context */
- INIT_WORK (&hcd->work, hcd_panic, hcd);
- (void) schedule_work (&hcd->work);
+ /* make khubd clean up old urbs and devices */
+ usb_set_device_state(hcd->self.root_hub, USB_STATE_NOTATTACHED);
+ mod_timer(&hcd->rh_timer, jiffies);
}
EXPORT_SYMBOL (usb_hc_died);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 90e7d081b484..5e0337dfbcc9 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -67,7 +67,6 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
struct timer_list rh_timer; /* drives root hub */
struct list_head dev_list; /* devices on this bus */
- struct work_struct work;
/*
* hardware info/state
@@ -363,6 +362,9 @@ static inline int hcd_register_root (struct usb_device *usb_dev,
return usb_register_root_hub (usb_dev, hcd->self.controller);
}
+extern void usb_set_device_state(struct usb_device *udev,
+ enum usb_device_state new_state);
+
/*-------------------------------------------------------------------------*/
/* exported only within usbcore */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 7f72ee96c7fe..29bba5e78da3 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -39,12 +39,13 @@
/* Protect struct usb_device state and children members */
static spinlock_t device_state_lock = SPIN_LOCK_UNLOCKED;
-/* Wakes up khubd */
+/* khubd's worklist and its lock */
static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
-
static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */
+/* Wakes up khubd */
static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
+
static pid_t khubd_pid = 0; /* PID of khubd */
static DECLARE_COMPLETION(khubd_exited);
@@ -226,6 +227,19 @@ static int get_port_status(struct usb_device *hdev, int port,
data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
}
+static void kick_khubd(struct usb_hub *hub)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hub_event_lock, flags);
+ if (list_empty(&hub->event_list)) {
+ list_add_tail(&hub->event_list, &hub_event_list);
+ wake_up(&khubd_wait);
+ }
+ spin_unlock_irqrestore(&hub_event_lock, flags);
+}
+
+
/* completion function, fires on port status changes and various faults */
static void hub_irq(struct urb *urb, struct pt_regs *regs)
{
@@ -261,12 +275,7 @@ static void hub_irq(struct urb *urb, struct pt_regs *regs)
hub->nerrors = 0;
/* Something happened, let khubd figure it out */
- spin_lock(&hub_event_lock);
- if (list_empty(&hub->event_list)) {
- list_add_tail(&hub->event_list, &hub_event_list);
- wake_up(&khubd_wait);
- }
- spin_unlock(&hub_event_lock);
+ kick_khubd(hub);
resubmit:
if (hub->quiescing)
@@ -579,6 +588,9 @@ static int hub_configure(struct usb_hub *hub,
dev_dbg(hub_dev, "%sover-current condition exists\n",
(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
+ /* scan all ports ASAP on new hubs */
+ hub->change_bits[0] = ~0;
+
/* Start the interrupt endpoint */
pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
@@ -604,7 +616,7 @@ static int hub_configure(struct usb_hub *hub,
}
/* Wake up khubd */
- wake_up(&khubd_wait);
+ kick_khubd(hub);
/* maybe start cycling the hub leds */
if (hub->has_indicators && blinkenlights) {
@@ -910,7 +922,7 @@ static int locktree(struct usb_device *udev)
}
/**
- * usb_set_device_state - change a device's current state (usbcore-internal)
+ * usb_set_device_state - change a device's current state (usbcore, hcds)
* @udev: pointer to device whose state should be changed
* @new_state: new state value to be stored
*
@@ -941,6 +953,7 @@ void usb_set_device_state(struct usb_device *udev,
recursively_mark_NOTATTACHED(udev);
spin_unlock_irqrestore(&device_state_lock, flags);
}
+EXPORT_SYMBOL(usb_set_device_state);
static void choose_address(struct usb_device *udev)
@@ -1384,7 +1397,6 @@ static int hub_port_disable(struct usb_device *hdev, int port)
int ret;
if (hdev->children[port]) {
- /* FIXME need disconnect() for NOTATTACHED device */
usb_set_device_state(hdev->children[port],
USB_STATE_NOTATTACHED);
}
@@ -1396,6 +1408,33 @@ static int hub_port_disable(struct usb_device *hdev, int port)
return ret;
}
+/*
+ * Disable a port and mark a logical connnect-change event, so that some
+ * time later khubd will disconnect() any existing usb_device on the port
+ * and will re-enumerate if there actually is a device attached.
+ */
+static void hub_port_logical_disconnect(struct usb_device *hdev, int port)
+{
+ struct usb_hub *hub;
+
+ dev_dbg(hubdev(hdev), "logical disconnect on port %d\n", port + 1);
+ hub_port_disable(hdev, port);
+
+ /* FIXME let caller ask to power down the port:
+ * - some devices won't enumerate without a VBUS power cycle
+ * - SRP saves power that way
+ * - usb_suspend_device(dev,PM_SUSPEND_DISK)
+ * That's easy if this hub can switch power per-port, and
+ * khubd reactivates the port later (timer, SRP, etc).
+ * Powerdown must be optional, because of reset/DFU.
+ */
+
+ hub = usb_get_intfdata(hdev->actconfig->interface[0]);
+ set_bit(port, hub->change_bits);
+ kick_khubd(hub);
+}
+
+
#ifdef CONFIG_USB_SUSPEND
/*
@@ -1413,8 +1452,8 @@ static int hub_port_suspend(struct usb_device *hdev, int port)
int status;
struct usb_device *udev;
- udev = hdev->children[port - 1];
- // dev_dbg(hubdev(hdev), "suspend port %d\n", port);
+ udev = hdev->children[port];
+ // dev_dbg(hubdev(hdev), "suspend port %d\n", port + 1);
/* enable remote wakeup when appropriate; this lets the device
* wake up the upstream hub (including maybe the root hub).
@@ -1439,11 +1478,11 @@ static int hub_port_suspend(struct usb_device *hdev, int port)
}
/* see 7.1.7.6 */
- status = set_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND);
+ status = set_port_feature(hdev, port + 1, USB_PORT_FEAT_SUSPEND);
if (status) {
dev_dbg(hubdev(hdev),
"can't suspend port %d, status %d\n",
- port, status);
+ port + 1, status);
/* paranoia: "should not happen" */
(void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
@@ -1562,7 +1601,7 @@ static int __usb_suspend_device (struct usb_device *udev, int port, u32 state)
else
status = -EOPNOTSUPP;
} else
- status = hub_port_suspend(udev->parent, port + 1);
+ status = hub_port_suspend(udev->parent, port);
if (status == 0)
udev->dev.power.power_state = state;
@@ -1687,15 +1726,15 @@ hub_port_resume(struct usb_device *hdev, int port)
int status;
struct usb_device *udev;
- udev = hdev->children[port - 1];
- // dev_dbg(hubdev(hdev), "resume port %d\n", port);
+ udev = hdev->children[port];
+ // dev_dbg(hubdev(hdev), "resume port %d\n", port + 1);
/* see 7.1.7.7; affects power usage, but not budgeting */
- status = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND);
+ status = clear_port_feature(hdev, port + 1, USB_PORT_FEAT_SUSPEND);
if (status) {
dev_dbg(&hdev->actconfig->interface[0]->dev,
"can't resume port %d, status %d\n",
- port, status);
+ port + 1, status);
} else {
u16 devstatus;
u16 portchange;
@@ -1713,7 +1752,7 @@ hub_port_resume(struct usb_device *hdev, int port)
* sequence.
*/
devstatus = portchange = 0;
- status = hub_port_status(hdev, port - 1,
+ status = hub_port_status(hdev, port,
&devstatus, &portchange);
if (status < 0
|| (devstatus & LIVE_FLAGS) != LIVE_FLAGS
@@ -1721,7 +1760,7 @@ hub_port_resume(struct usb_device *hdev, int port)
) {
dev_dbg(&hdev->actconfig->interface[0]->dev,
"port %d status %04x.%04x after resume, %d\n",
- port, portchange, devstatus, status);
+ port + 1, portchange, devstatus, status);
} else {
/* TRSMRCY = 10 msec */
msleep(10);
@@ -1729,7 +1768,7 @@ hub_port_resume(struct usb_device *hdev, int port)
}
}
if (status < 0)
- status = hub_port_disable(hdev, port);
+ hub_port_logical_disconnect(hdev, port);
return status;
}
@@ -1773,7 +1812,7 @@ int usb_resume_device(struct usb_device *udev)
->actconfig->interface[0]);
}
} else if (udev->state == USB_STATE_SUSPENDED) {
- status = hub_port_resume(udev->parent, port + 1);
+ status = hub_port_resume(udev->parent, port);
} else {
status = 0;
udev->dev.power.power_state = PM_SUSPEND_ON;
@@ -1866,14 +1905,14 @@ static int hub_resume(struct usb_interface *intf)
continue;
down (&udev->serialize);
if (portstat & USB_PORT_STAT_SUSPEND)
- status = hub_port_resume(hdev, port + 1);
+ status = hub_port_resume(hdev, port);
else {
status = finish_port_resume(udev);
- if (status < 0)
- status = hub_port_disable(hdev, port);
- if (status < 0)
+ if (status < 0) {
dev_dbg(&intf->dev, "resume port %d --> %d\n",
- port, status);
+ port + 1, status);
+ hub_port_logical_disconnect(hdev, port);
+ }
}
up(&udev->serialize);
}
@@ -2011,7 +2050,7 @@ hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port)
hdev->bus->b_hnp_enable = 0;
}
- retval = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND);
+ retval = clear_port_feature(hdev, port + 1, USB_PORT_FEAT_SUSPEND);
if (retval < 0 && retval != -EPIPE)
dev_dbg(&udev->dev, "can't clear suspend; %d\n", retval);
@@ -2502,15 +2541,17 @@ static void hub_events(void)
if (portchange & USB_PORT_STAT_C_SUSPEND) {
clear_port_feature(hdev, i + 1,
USB_PORT_FEAT_C_SUSPEND);
- if (hdev->children[i])
+ if (hdev->children[i]) {
ret = remote_wakeup(hdev->children[i]);
- else
+ if (ret < 0)
+ connect_change = 1;
+ } else {
ret = -ENODEV;
+ hub_port_disable(hdev, i);
+ }
dev_dbg (hub_dev,
"resume on port %d, status %d\n",
i + 1, ret);
- if (ret < 0)
- ret = hub_port_disable(hdev, i);
}
if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
@@ -2713,7 +2754,6 @@ int __usb_reset_device(struct usb_device *udev)
struct usb_device *parent = udev->parent;
struct usb_device_descriptor descriptor = udev->descriptor;
int i, ret, port = -1;
- struct usb_hub *hub;
if (udev->state == USB_STATE_NOTATTACHED ||
udev->state == USB_STATE_SUSPENDED) {
@@ -2794,18 +2834,7 @@ int __usb_reset_device(struct usb_device *udev)
return 0;
re_enumerate:
- hub_port_disable(parent, port);
-
- hub = usb_get_intfdata(parent->actconfig->interface[0]);
- set_bit(port, hub->change_bits);
-
- spin_lock_irq(&hub_event_lock);
- if (list_empty(&hub->event_list)) {
- list_add_tail(&hub->event_list, &hub_event_list);
- wake_up(&khubd_wait);
- }
- spin_unlock_irq(&hub_event_lock);
-
+ hub_port_logical_disconnect(parent, port);
return -ENODEV;
}
EXPORT_SYMBOL(__usb_reset_device);
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index c9f57e334a4f..24452d66d576 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -4,7 +4,7 @@
* inode.c -- Inode/Dentry functions for the USB device file system.
*
* Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
- * Copyright (C) 2001,2002 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.com)
*
* 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
@@ -40,17 +40,15 @@
#include <linux/smp_lock.h>
#include <linux/parser.h>
#include <asm/byteorder.h>
+#include "usb.h"
static struct super_operations usbfs_ops;
static struct file_operations default_file_operations;
static struct inode_operations usbfs_dir_inode_operations;
-static struct vfsmount *usbdevfs_mount;
static struct vfsmount *usbfs_mount;
-static int usbdevfs_mount_count; /* = 0 */
static int usbfs_mount_count; /* = 0 */
static int ignore_mount = 0;
-static struct dentry *devices_usbdevfs_dentry;
static struct dentry *devices_usbfs_dentry;
static int num_buses; /* = 0 */
@@ -240,9 +238,6 @@ static int remount(struct super_block *sb, int *flags, char *data)
if (usbfs_mount && usbfs_mount->mnt_sb)
update_sb(usbfs_mount->mnt_sb);
- if (usbdevfs_mount && usbdevfs_mount->mnt_sb)
- update_sb(usbdevfs_mount->mnt_sb);
-
return 0;
}
@@ -561,28 +556,12 @@ static void fs_remove_file (struct dentry *dentry)
/* --------------------------------------------------------------------- */
-
-
-/*
- * The usbdevfs name is now deprecated (as of 2.5.1).
- * It will be removed when the 2.7.x development cycle is started.
- * You have been warned :)
- */
-static struct file_system_type usbdevice_fs_type;
-
static struct super_block *usb_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, usbfs_fill_super);
}
-static struct file_system_type usbdevice_fs_type = {
- .owner = THIS_MODULE,
- .name = "usbdevfs",
- .get_sb = usb_get_sb,
- .kill_sb = kill_litter_super,
-};
-
static struct file_system_type usb_fs_type = {
.owner = THIS_MODULE,
.name = "usbfs",
@@ -603,16 +582,10 @@ static int create_special_files (void)
ignore_mount = 1;
/* create the devices special file */
- retval = simple_pin_fs("usbdevfs", &usbdevfs_mount, &usbdevfs_mount_count);
- if (retval) {
- err ("Unable to get usbdevfs mount");
- goto exit;
- }
-
retval = simple_pin_fs("usbfs", &usbfs_mount, &usbfs_mount_count);
if (retval) {
err ("Unable to get usbfs mount");
- goto error_clean_usbdevfs_mount;
+ goto exit;
}
ignore_mount = 0;
@@ -620,7 +593,7 @@ static int create_special_files (void)
parent = usbfs_mount->mnt_sb->s_root;
devices_usbfs_dentry = fs_create_file ("devices",
listmode | S_IFREG, parent,
- NULL, &usbdevfs_devices_fops,
+ NULL, &usbfs_devices_fops,
listuid, listgid);
if (devices_usbfs_dentry == NULL) {
err ("Unable to create devices usbfs file");
@@ -628,42 +601,19 @@ static int create_special_files (void)
goto error_clean_mounts;
}
- parent = usbdevfs_mount->mnt_sb->s_root;
- devices_usbdevfs_dentry = fs_create_file ("devices",
- listmode | S_IFREG, parent,
- NULL, &usbdevfs_devices_fops,
- listuid, listgid);
- if (devices_usbdevfs_dentry == NULL) {
- err ("Unable to create devices usbfs file");
- retval = -ENODEV;
- goto error_remove_file;
- }
-
goto exit;
-error_remove_file:
- fs_remove_file (devices_usbfs_dentry);
- devices_usbfs_dentry = NULL;
-
error_clean_mounts:
simple_release_fs(&usbfs_mount, &usbfs_mount_count);
-
-error_clean_usbdevfs_mount:
- simple_release_fs(&usbdevfs_mount, &usbdevfs_mount_count);
-
exit:
return retval;
}
static void remove_special_files (void)
{
- if (devices_usbdevfs_dentry)
- fs_remove_file (devices_usbdevfs_dentry);
if (devices_usbfs_dentry)
fs_remove_file (devices_usbfs_dentry);
- devices_usbdevfs_dentry = NULL;
devices_usbfs_dentry = NULL;
- simple_release_fs(&usbdevfs_mount, &usbdevfs_mount_count);
simple_release_fs(&usbfs_mount, &usbfs_mount_count);
}
@@ -671,11 +621,6 @@ void usbfs_update_special (void)
{
struct inode *inode;
- if (devices_usbdevfs_dentry) {
- inode = devices_usbdevfs_dentry->d_inode;
- if (inode)
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- }
if (devices_usbfs_dentry) {
inode = devices_usbfs_dentry->d_inode;
if (inode)
@@ -707,29 +652,16 @@ void usbfs_add_bus(struct usb_bus *bus)
return;
}
- parent = usbdevfs_mount->mnt_sb->s_root;
- bus->usbdevfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent,
- bus, NULL, busuid, busgid);
- if (bus->usbdevfs_dentry == NULL) {
- err ("error creating usbdevfs bus entry");
- return;
- }
-
usbfs_update_special();
- usbdevfs_conn_disc_event();
+ usbfs_conn_disc_event();
}
-
void usbfs_remove_bus(struct usb_bus *bus)
{
if (bus->usbfs_dentry) {
fs_remove_file (bus->usbfs_dentry);
bus->usbfs_dentry = NULL;
}
- if (bus->usbdevfs_dentry) {
- fs_remove_file (bus->usbdevfs_dentry);
- bus->usbdevfs_dentry = NULL;
- }
--num_buses;
if (num_buses <= 0) {
@@ -738,7 +670,7 @@ void usbfs_remove_bus(struct usb_bus *bus)
}
usbfs_update_special();
- usbdevfs_conn_disc_event();
+ usbfs_conn_disc_event();
}
void usbfs_add_device(struct usb_device *dev)
@@ -750,20 +682,12 @@ void usbfs_add_device(struct usb_device *dev)
sprintf (name, "%03d", dev->devnum);
dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
dev->bus->usbfs_dentry, dev,
- &usbdevfs_device_file_operations,
+ &usbfs_device_file_operations,
devuid, devgid);
if (dev->usbfs_dentry == NULL) {
err ("error creating usbfs device entry");
return;
}
- dev->usbdevfs_dentry = fs_create_file (name, devmode | S_IFREG,
- dev->bus->usbdevfs_dentry, dev,
- &usbdevfs_device_file_operations,
- devuid, devgid);
- if (dev->usbdevfs_dentry == NULL) {
- err ("error creating usbdevfs device entry");
- return;
- }
/* Set the size of the device's file to be
* equal to the size of the device descriptors. */
@@ -775,11 +699,9 @@ void usbfs_add_device(struct usb_device *dev)
}
if (dev->usbfs_dentry->d_inode)
dev->usbfs_dentry->d_inode->i_size = i_size;
- if (dev->usbdevfs_dentry->d_inode)
- dev->usbdevfs_dentry->d_inode->i_size = i_size;
usbfs_update_special();
- usbdevfs_conn_disc_event();
+ usbfs_conn_disc_event();
}
void usbfs_remove_device(struct usb_device *dev)
@@ -791,10 +713,6 @@ void usbfs_remove_device(struct usb_device *dev)
fs_remove_file (dev->usbfs_dentry);
dev->usbfs_dentry = NULL;
}
- if (dev->usbdevfs_dentry) {
- fs_remove_file (dev->usbdevfs_dentry);
- dev->usbdevfs_dentry = NULL;
- }
while (!list_empty(&dev->filelist)) {
ds = list_entry(dev->filelist.next, struct dev_state, list);
list_del_init(&ds->list);
@@ -807,51 +725,38 @@ void usbfs_remove_device(struct usb_device *dev)
}
}
usbfs_update_special();
- usbdevfs_conn_disc_event();
+ usbfs_conn_disc_event();
}
/* --------------------------------------------------------------------- */
-#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *usbdir = NULL;
-#endif
int __init usbfs_init(void)
{
int retval;
- retval = usb_register(&usbdevfs_driver);
+ retval = usb_register(&usbfs_driver);
if (retval)
return retval;
retval = register_filesystem(&usb_fs_type);
if (retval) {
- usb_deregister(&usbdevfs_driver);
- return retval;
- }
- retval = register_filesystem(&usbdevice_fs_type);
- if (retval) {
- unregister_filesystem(&usb_fs_type);
- usb_deregister(&usbdevfs_driver);
+ usb_deregister(&usbfs_driver);
return retval;
}
-#ifdef CONFIG_PROC_FS
- /* create mount point for usbdevfs */
+ /* create mount point for usbfs */
usbdir = proc_mkdir("usb", proc_bus);
-#endif
return 0;
}
void usbfs_cleanup(void)
{
- usb_deregister(&usbdevfs_driver);
+ usb_deregister(&usbfs_driver);
unregister_filesystem(&usb_fs_type);
- unregister_filesystem(&usbdevice_fs_type);
-#ifdef CONFIG_PROC_FS
if (usbdir)
remove_proc_entry("usb", proc_bus);
-#endif
}
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 3c14361bbeb3..f57de4dca2bf 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -451,6 +451,11 @@ int usb_unlink_urb(struct urb *urb)
if (!urb)
return -EINVAL;
if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
+#ifdef CONFIG_DEBUG_KERNEL
+ printk(KERN_NOTICE "usb_unlink_urb() is deprecated for "
+ "synchronous unlinks. Use usb_kill_urb() instead.\n");
+ WARN_ON(1);
+#endif
usb_kill_urb(urb);
return 0;
}
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index f1dff4f4d5d6..8e9c923bff0b 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -22,8 +22,12 @@ extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
-extern void usb_set_device_state(struct usb_device *udev,
- enum usb_device_state new_state);
/* for labeling diagnostics */
extern const char *usbcore_name;
+
+/* usbfs stuff */
+extern struct usb_driver usbfs_driver;
+extern struct file_operations usbfs_devices_fops;
+extern struct file_operations usbfs_device_file_operations;
+extern void usbfs_conn_disc_event(void);
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 763d0552146a..0c5f37c2ba0a 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -231,6 +231,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
+#ifdef CONFIG_USB_GADGET_N9604
+#define DEV_CONFIG_CDC
+#endif
+
/* For CDC-incapable hardware, choose the simple cdc subset.
* Anything that talks bulk (without notable bugs) can do this.
@@ -2334,6 +2338,8 @@ eth_bind (struct usb_gadget *gadget)
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
} else if (gadget_is_lh7a40x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
+ } else if (gadget_is_n9604(gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x020a);
} else {
/* can't assume CDC works. don't want to default to
* anything less functional on CDC-capable hardware,
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 6e8008fa43cb..2d2b2c032f19 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -248,7 +248,7 @@
#define DRIVER_DESC "File-backed Storage Gadget"
#define DRIVER_NAME "g_file_storage"
-#define DRIVER_VERSION "28 July 2004"
+#define DRIVER_VERSION "31 August 2004"
static const char longname[] = DRIVER_DESC;
static const char shortname[] = DRIVER_NAME;
@@ -866,6 +866,14 @@ config_desc = {
.bMaxPower = 1, // self-powered
};
+static struct usb_otg_descriptor
+otg_desc = {
+ .bLength = sizeof(otg_desc),
+ .bDescriptorType = USB_DT_OTG,
+
+ .bmAttributes = USB_OTG_SRP,
+};
+
/* There is only one interface. */
static struct usb_interface_descriptor
@@ -914,6 +922,7 @@ fs_intr_in_desc = {
};
static const struct usb_descriptor_header *fs_function[] = {
+ (struct usb_descriptor_header *) &otg_desc,
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &fs_bulk_in_desc,
(struct usb_descriptor_header *) &fs_bulk_out_desc,
@@ -976,6 +985,7 @@ hs_intr_in_desc = {
};
static const struct usb_descriptor_header *hs_function[] = {
+ (struct usb_descriptor_header *) &otg_desc,
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &hs_bulk_in_desc,
(struct usb_descriptor_header *) &hs_bulk_out_desc,
@@ -1018,9 +1028,10 @@ static struct usb_gadget_strings stringtab = {
* and with code managing interfaces and their altsettings. They must
* also handle different speeds and other-speed requests.
*/
-static int populate_config_buf(enum usb_device_speed speed,
+static int populate_config_buf(struct usb_gadget *gadget,
u8 *buf, u8 type, unsigned index)
{
+ enum usb_device_speed speed = gadget->speed;
int len;
const struct usb_descriptor_header **function;
@@ -1036,6 +1047,10 @@ static int populate_config_buf(enum usb_device_speed speed,
#endif
function = fs_function;
+ /* for now, don't advertise srp-only devices */
+ if (!gadget->is_otg)
+ function++;
+
len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
((struct usb_config_descriptor *) buf)->bDescriptorType = type;
return len;
@@ -1366,7 +1381,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
#ifdef CONFIG_USB_GADGET_DUALSPEED
get_config:
#endif
- value = populate_config_buf(fsg->gadget->speed,
+ value = populate_config_buf(fsg->gadget,
req->buf,
ctrl->wValue >> 8,
ctrl->wValue & 0xff);
@@ -3713,8 +3728,10 @@ static int __init check_parameters(struct fsg_dev *fsg)
mod_data.release = __constant_cpu_to_le16(0x0307);
else if (gadget_is_omap(fsg->gadget))
mod_data.release = __constant_cpu_to_le16(0x0308);
- else if (gadget_is_lh7a40x(gadget))
+ else if (gadget_is_lh7a40x(fsg->gadget))
mod_data.release = __constant_cpu_to_le16 (0x0309);
+ else if (gadget_is_n9604(fsg->gadget))
+ mod_data.release = __constant_cpu_to_le16 (0x030a);
else {
WARN(fsg, "controller '%s' not recognized\n",
fsg->gadget->name);
@@ -3896,6 +3913,11 @@ static int __init fsg_bind(struct usb_gadget *gadget)
hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;
#endif
+ if (gadget->is_otg) {
+ otg_desc.bmAttributes |= USB_OTG_HNP,
+ config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
rc = -ENOMEM;
/* Allocate the request and buffer for endpoint 0 */
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e24e2f9ad28e..f6273701fec6 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -62,6 +62,12 @@
#define gadget_is_omap(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_N9604
+#define gadget_is_n9604(g) !strcmp("n9604_udc", (g)->name)
+#else
+#define gadget_is_n9604(g) 0
+#endif
+
// CONFIG_USB_GADGET_AT91RM9200
// CONFIG_USB_GADGET_SX2
// CONFIG_USB_GADGET_AU1X00
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index e40089d79365..84de1faeab64 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -1200,7 +1200,8 @@ static void pullup_enable(struct omap_udc *udc)
{
UDC_SYSCON1_REG |= UDC_PULLUP_EN;
#ifndef CONFIG_USB_OTG
- OTG_CTRL_REG |= OTG_BSESSVLD;
+ if (!cpu_is_omap15xx())
+ OTG_CTRL_REG |= OTG_BSESSVLD;
#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
}
@@ -1208,7 +1209,8 @@ static void pullup_enable(struct omap_udc *udc)
static void pullup_disable(struct omap_udc *udc)
{
#ifndef CONFIG_USB_OTG
- OTG_CTRL_REG &= ~OTG_BSESSVLD;
+ if (!cpu_is_omap15xx())
+ OTG_CTRL_REG &= ~OTG_BSESSVLD;
#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
@@ -1688,7 +1690,7 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
}
change &= ~UDC_SUS;
}
- if (change & OTG_FLAGS) {
+ if (!cpu_is_omap15xx() && (change & OTG_FLAGS)) {
update_otg(udc);
change &= ~OTG_FLAGS;
}
@@ -2036,34 +2038,14 @@ static char *trx_mode(unsigned m)
}
}
-static int proc_udc_show(struct seq_file *s, void *_)
+static int proc_otg_show(struct seq_file *s)
{
u32 tmp;
- struct omap_ep *ep;
- unsigned long flags;
-
- spin_lock_irqsave(&udc->lock, flags);
- seq_printf(s, "%s, version: " DRIVER_VERSION
-#ifdef USE_ISO
- " (iso)"
-#endif
- "%s\n",
- driver_desc,
- use_dma ? " (dma)" : "");
-
- tmp = UDC_REV_REG & 0xff;
- seq_printf(s,
- "UDC rev %d.%d, OTG rev %d.%d, fifo mode %d, gadget %s\n"
- "hmc %d, transceiver %08x %s\n",
+ tmp = OTG_REV_REG;
+ seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %08x\n",
tmp >> 4, tmp & 0xf,
- OTG_REV_REG >> 4, OTG_REV_REG & 0xf,
- fifo_mode,
- udc->driver ? udc->driver->driver.name : "(none)",
- HMC, USB_TRANSCEIVER_CTRL_REG,
- udc->transceiver ? udc->transceiver->label : "");
-
- /* OTG controller registers */
+ USB_TRANSCEIVER_CTRL_REG);
tmp = OTG_SYSCON_1_REG;
seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s,"
FOURBITS "\n", tmp,
@@ -2117,6 +2099,37 @@ static int proc_udc_show(struct seq_file *s, void *_)
seq_printf(s, "otg_outctrl %04x" "\n", tmp);
tmp = OTG_TEST_REG;
seq_printf(s, "otg_test %04x" "\n", tmp);
+}
+
+static int proc_udc_show(struct seq_file *s, void *_)
+{
+ u32 tmp;
+ struct omap_ep *ep;
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ seq_printf(s, "%s, version: " DRIVER_VERSION
+#ifdef USE_ISO
+ " (iso)"
+#endif
+ "%s\n",
+ driver_desc,
+ use_dma ? " (dma)" : "");
+
+ tmp = UDC_REV_REG & 0xff;
+ seq_printf(s,
+ "UDC rev %d.%d, fifo mode %d, gadget %s\n"
+ "hmc %d, transceiver %s\n",
+ tmp >> 4, tmp & 0xf,
+ fifo_mode,
+ udc->driver ? udc->driver->driver.name : "(none)",
+ HMC,
+ udc->transceiver ? udc->transceiver->label : "");
+
+ /* OTG controller registers */
+ if (!cpu_is_omap15xx())
+ proc_otg_show(s);
tmp = UDC_SYSCON1_REG;
seq_printf(s, "\nsyscon1 %04x" EIGHTBITS "\n", tmp,
@@ -2496,41 +2509,51 @@ static int __init omap_udc_probe(struct device *dev)
return -EBUSY;
}
- INFO("OMAP UDC rev %d.%d, OTG rev %d.%d, %s receptacle\n",
+ INFO("OMAP UDC rev %d.%d, %s receptacle\n",
UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
- OTG_REV_REG >> 4, OTG_REV_REG & 0xf,
config->otg ? "Mini-AB" : "B/Mini-B");
/* use the mode given to us by board init code */
- hmc = HMC;
- switch (hmc) {
- case 3:
- case 11:
- case 19:
- case 25:
- xceiv = otg_get_transceiver();
- if (!xceiv) {
- DBG("external transceiver not registered!\n");
- goto cleanup0;
- }
- type = xceiv->label;
- break;
- case 0: /* POWERUP DEFAULT == 0 */
- case 4:
- case 12:
- case 20:
- type = "INTEGRATED";
- break;
- case 21: /* internal loopback */
- type = "(loopback)";
- break;
- case 14: /* transceiverless */
- type = "(none)";
- break;
+ if (cpu_is_omap15xx()) {
+ hmc = HMC_1510;
+ type = "(unknown)";
- default:
- ERR("unrecognized UDC HMC mode %d\n", hmc);
- return -ENODEV;
+ /* FIXME may need a GPIO-0 handler to call
+ * usb_gadget_vbus_{dis,}connect() on us...
+ */
+ } else {
+ hmc = HMC_1610;
+ switch (hmc) {
+ case 3:
+ case 11:
+ case 19:
+ case 25:
+ xceiv = otg_get_transceiver();
+ if (!xceiv) {
+ DBG("external transceiver not registered!\n");
+ if (config->otg)
+ goto cleanup0;
+ type = "(unknown external)";
+ } else
+ type = xceiv->label;
+ break;
+ case 0: /* POWERUP DEFAULT == 0 */
+ case 4:
+ case 12:
+ case 20:
+ type = "INTEGRATED";
+ break;
+ case 21: /* internal loopback */
+ type = "(loopback)";
+ break;
+ case 14: /* transceiverless */
+ type = "(none)";
+ break;
+
+ default:
+ ERR("unrecognized UDC HMC mode %d\n", hmc);
+ return -ENODEV;
+ }
}
INFO("hmc mode %d, transceiver %s\n", hmc, type);
@@ -2671,13 +2694,6 @@ static struct device_driver udc_driver = {
static int __init udc_init(void)
{
- /* should work on many OMAP systems with at most minor changes,
- * but the 1510 doesn't have an OTG controller.
- */
- if (cpu_is_omap1510()) {
- DBG("no OMAP1510 support yet\n");
- return -ENODEV;
- }
INFO("%s, version: " DRIVER_VERSION "%s\n", driver_desc,
use_dma ? " (dma)" : "");
return driver_register(&udc_driver);
diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
index bd5420cd0b05..ca8572314f95 100644
--- a/drivers/usb/gadget/omap_udc.h
+++ b/drivers/usb/gadget/omap_udc.h
@@ -193,7 +193,14 @@ struct omap_udc {
/*-------------------------------------------------------------------------*/
-// #define HMC_1510 ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f)
+#define MOD_CONF_CTRL_0_REG __REG32(MOD_CONF_CTRL_0)
+#define VBUS_W2FC_1510 (1 << 17) /* 0 gpio0, 1 dvdd2 pin */
+
+#define FUNC_MUX_CTRL_0_REG __REG32(FUNC_MUX_CTRL_0)
+#define VBUS_CTRL_1510 (1 << 19) /* 1 connected (software) */
+#define VBUS_MODE_1510 (1 << 18) /* 0 hardware, 1 software */
+
+#define HMC_1510 ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f)
#define HMC_1610 (OTG_SYSCON_2_REG & 0x3f)
-#define HMC HMC_1610
+#define HMC (cpu_is_omap15xx() ? HMC_1510 : HMC_1610)
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index a415a33ed117..69962c30a3a9 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1188,6 +1188,8 @@ autoconf_fail:
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
} else if (gadget_is_lh7a40x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
+ } else if (gadget_is_n9604(gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x020a);
} else {
/* gadget zero is so simple (for now, no altsettings) that
* it SHOULD NOT have problems with bulk-capable hardware.
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 554af349d5e2..2f204b864a90 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -695,9 +695,18 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
timer_action_done (ehci, TIMER_IO_WATCHDOG);
if (ehci->reclaim_ready)
end_unlink_async (ehci, regs);
+
+ /* another CPU may drop ehci->lock during a schedule scan while
+ * it reports urb completions. this flag guards against bogus
+ * attempts at re-entrant schedule scanning.
+ */
+ if (ehci->scanning)
+ return;
+ ehci->scanning = 1;
scan_async (ehci, regs);
if (ehci->next_uframe != -1)
scan_periodic (ehci, regs);
+ ehci->scanning = 0;
/* the IO watchdog guards against hardware or driver bugs that
* misplace IRQs, and should let us run completely without IRQs.
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 14e001d98f57..de666f6b3314 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -53,6 +53,7 @@ struct ehci_hcd { /* one per controller */
struct ehci_qh *async;
struct ehci_qh *reclaim;
unsigned reclaim_ready : 1;
+ unsigned scanning : 1;
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
diff --git a/drivers/usb/host/hc_sl811.c b/drivers/usb/host/hc_sl811.c
index b57f1fe8258d..baf0e8086352 100644
--- a/drivers/usb/host/hc_sl811.c
+++ b/drivers/usb/host/hc_sl811.c
@@ -1343,15 +1343,11 @@ static int __init hci_hcd_init (void)
*****************************************************************/
static void __exit hci_hcd_cleanup (void)
{
- struct list_head *hci_l;
- hci_t *hci;
+ hci_t *hci, *tmp;
DBGFUNC ("Enter hci_hcd_cleanup\n");
- for (hci_l = hci_hcd_list.next; hci_l != &hci_hcd_list;) {
- hci = list_entry (hci_l, hci_t, hci_hcd_list);
- hci_l = hci_l->next;
+ list_for_each_entry_safe(hci, tmp, &hci_hcd_list, hci_hcd_list)
hc_release_hci (hci);
- }
}
module_init (hci_hcd_init);
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 54daaacdc8c9..532164079cfa 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -640,14 +640,14 @@ show_registers (struct class_device *class_dev, char *buf)
rdata = ohci_readl (&regs->fminterval);
temp = scnprintf (next, size,
"fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n",
- rdata, (rdata >> 31) ? " FIT" : "",
+ rdata, (rdata >> 31) ? "FIT " : "",
(rdata >> 16) & 0xefff, rdata & 0xffff);
size -= temp;
next += temp;
rdata = ohci_readl (&regs->fmremaining);
temp = scnprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n",
- rdata, (rdata >> 31) ? " FRT" : "",
+ rdata, (rdata >> 31) ? "FRT " : "",
rdata & 0x3fff);
size -= temp;
next += temp;
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index a087e72b94ae..d96a4edbd022 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -2,7 +2,7 @@
* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
*
* [ Initialisation is based on Linus' ]
* [ uhci code and gregs ohci fragments ]
@@ -122,6 +122,16 @@
#define OHCI_INTR_INIT \
(OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH)
+#ifdef __hppa__
+/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
+#define IR_DISABLE
+#endif
+
+#ifdef CONFIG_ARCH_OMAP
+/* OMAP doesn't support IR (no SMM; not needed) */
+#define IR_DISABLE
+#endif
+
/*-------------------------------------------------------------------------*/
static const char hcd_name [] = "ohci_hcd";
@@ -399,18 +409,24 @@ static int hc_reset (struct ohci_hcd *ohci)
/* boot firmware should have set this up (5.1.1.3.1) */
if (!ohci->fminterval) {
+ u32 t2;
+
temp = ohci_readl (&ohci->regs->fminterval);
- if (temp & 0x3fff0000)
- ohci->fminterval = temp;
- else
- ohci->fminterval = DEFAULT_FMINTERVAL;
+ ohci->fminterval = temp & 0x3fff;
+ if (ohci->fminterval != FI)
+ ohci_dbg (ohci, "fminterval delta %d\n",
+ ohci->fminterval - FI);
+
+ t2 = FSMP (ohci->fminterval);
+ temp >>= 16;
+ if ((t2/2) < temp || temp > t2)
+ temp = t2;
+ ohci->fminterval |= temp << 16;
/* also: power/overcurrent flags in roothub.a */
}
- /* SMM owns the HC? not for long!
- * On PA-RISC, PDC can leave IR set incorrectly; ignore it there.
- */
-#ifndef __hppa__
+#ifndef IR_DISABLE
+ /* SMM owns the HC? not for long! */
if (ohci_readl (&ohci->regs->control) & OHCI_CTRL_IR) {
ohci_dbg (ohci, "USB HC TakeOver from BIOS/SMM\n");
@@ -435,18 +451,40 @@ static int hc_reset (struct ohci_hcd *ohci)
/* Disable HC interrupts */
writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
- ohci_dbg (ohci, "reset, control = 0x%x\n",
- ohci_readl (&ohci->regs->control));
-
- /* Reset USB (needed by some controllers); RemoteWakeupConnected
+ /* Reset USB nearly "by the book". RemoteWakeupConnected
* saved if boot firmware (BIOS/SMM/...) told us it's connected
* (for OHCI integrated on mainboard, it normally is)
*/
ohci->hc_control = ohci_readl (&ohci->regs->control);
- ohci->hc_control &= OHCI_CTRL_RWC; /* hcfs 0 = RESET */
- if (ohci->hc_control)
+ ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n",
+ hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
+ ohci->hc_control);
+
+ if (ohci->hc_control & OHCI_CTRL_RWC
+ && !(ohci->flags & OHCI_QUIRK_AMD756))
ohci->hcd.can_wakeup = 1;
+
+ switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+ case OHCI_USB_OPER:
+ temp = 0;
+ break;
+ case OHCI_USB_SUSPEND:
+ case OHCI_USB_RESUME:
+ ohci->hc_control &= OHCI_CTRL_RWC;
+ ohci->hc_control |= OHCI_USB_RESUME;
+ temp = 10 /* msec wait */;
+ break;
+ // case OHCI_USB_RESET:
+ default:
+ ohci->hc_control &= OHCI_CTRL_RWC;
+ ohci->hc_control |= OHCI_USB_RESET;
+ temp = 50 /* msec wait */;
+ break;
+ }
writel (ohci->hc_control, &ohci->regs->control);
+ // flush the writes
+ (void) ohci_readl (&ohci->regs->control);
+ msleep(temp);
if (power_switching) {
unsigned ports = roothub_a (ohci) & RH_A_NDP;
@@ -455,9 +493,8 @@ static int hc_reset (struct ohci_hcd *ohci)
writel (RH_PS_LSDA,
&ohci->regs->roothub.portstatus [temp]);
}
- // flush those pci writes
+ // flush those writes
(void) ohci_readl (&ohci->regs->control);
- msleep (50);
/* HC Reset requires max 10 us delay */
writel (OHCI_HCR, &ohci->regs->cmdstatus);
@@ -469,6 +506,7 @@ static int hc_reset (struct ohci_hcd *ohci)
}
udelay (1);
}
+ periodic_reinit (ohci);
/* now we're in the SUSPEND state ... must go OPERATIONAL
* within 2msec else HC enters RESUME
@@ -477,10 +515,11 @@ static int hc_reset (struct ohci_hcd *ohci)
* (SiS, OPTi ...), so reset again instead. SiS doesn't need
* this if we write fmInterval after we're OPERATIONAL.
*/
- writel (ohci->hc_control, &ohci->regs->control);
- // flush those pci writes
- (void) ohci_readl (&ohci->regs->control);
-
+ if (ohci->flags & OHCI_QUIRK_INITRESET) {
+ writel (ohci->hc_control, &ohci->regs->control);
+ // flush those writes
+ (void) ohci_readl (&ohci->regs->control);
+ }
return 0;
}
@@ -506,8 +545,6 @@ static int hc_start (struct ohci_hcd *ohci)
/* a reset clears this */
writel ((u32) ohci->hcca_dma, &ohci->regs->hcca);
- periodic_reinit (ohci);
-
/* some OHCI implementations are finicky about how they init.
* bogus values here mean not even enumeration could work.
*/
@@ -553,7 +590,7 @@ static int hc_start (struct ohci_hcd *ohci)
writel (tmp, &ohci->regs->roothub.a);
writel (RH_HS_LPSC, &ohci->regs->roothub.status);
writel (power_switching ? RH_B_PPCM : 0, &ohci->regs->roothub.b);
- // flush those pci writes
+ // flush those writes
(void) ohci_readl (&ohci->regs->control);
// POTPGT delay is bits 24-31, in 2 ms units.
@@ -620,7 +657,8 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
// e.g. due to PCI Master/Target Abort
ohci_dump (ohci, 1);
- hc_reset (ohci);
+ ohci->hc_control &= OHCI_CTRL_RWC; /* hcfs 0 = RESET */
+ writel (ohci->hc_control, &ohci->regs->control);
}
if (ints & OHCI_INTR_RD) {
@@ -655,7 +693,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
if (HCD_IS_RUNNING(ohci->hcd.state)) {
writel (ints, &regs->intrstatus);
writel (OHCI_INTR_MIE, &regs->intrenable);
- // flush those pci writes
+ // flush those writes
(void) ohci_readl (&ohci->regs->control);
}
@@ -696,18 +734,6 @@ static void ohci_stop (struct usb_hcd *hcd)
#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
-static void mark_children_gone (struct usb_device *dev)
-{
- unsigned i;
-
- for (i = 0; i < dev->maxchild; i++) {
- if (dev->children [i] == 0)
- continue;
- dev->children [i]->state = USB_STATE_NOTATTACHED;
- mark_children_gone (dev->children [i]);
- }
-}
-
static int hc_restart (struct ohci_hcd *ohci)
{
int temp;
@@ -721,7 +747,7 @@ static int hc_restart (struct ohci_hcd *ohci)
*/
spin_lock_irq(&ohci->lock);
disable (ohci);
- mark_children_gone (ohci->hcd.self.root_hub);
+ usb_set_device_state (ohci->hcd.self.root_hub, USB_STATE_NOTATTACHED);
if (!list_empty (&ohci->pending))
ohci_dbg(ohci, "abort schedule...\n");
list_for_each_entry (priv, &ohci->pending, pending) {
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 344b1cab16e1..11093ed39cb1 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -146,10 +146,11 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
ohci->next_statechange = jiffies + msecs_to_jiffies (5);
succeed:
- /* it's not USB_STATE_SUSPENDED unless access to this
+ /* it's not HCD_STATE_SUSPENDED unless access to this
* hub from the non-usb side (PCI, SOC, etc) stopped
*/
root->dev.power.power_state = 3;
+ root->state = USB_STATE_SUSPENDED;
done:
spin_unlock_irq (&ohci->lock);
return status;
@@ -289,7 +290,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
ohci->hc_control |= enables;
writel (ohci->hc_control, &ohci->regs->control);
if (temp)
- writel (status, &ohci->regs->cmdstatus);
+ writel (temp, &ohci->regs->cmdstatus);
(void) ohci_readl (&ohci->regs->control);
}
@@ -481,8 +482,8 @@ static void start_hnp(struct ohci_hcd *ohci);
/* this timer value might be vendor-specific ... */
#define PORT_RESET_HW_MSEC 10
-/* wrap-aware logic stolen from <linux/jiffies.h> */
-#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0)
+/* wrap-aware logic morphed from <linux/jiffies.h> */
+#define tick_before(t1,t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
/* called from some task, normally khubd */
static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port)
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 73d9aee657d5..bf0c5d8ec231 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -61,6 +61,7 @@ ohci_pci_start (struct usb_hcd *hcd)
&& pdev->device == 0x740c) {
ohci->flags = OHCI_QUIRK_AMD756;
ohci_info (ohci, "AMD756 erratum 4 workaround\n");
+ // also somewhat erratum 10 (suspend/resume issues)
}
/* FIXME for some of the early AMD 760 southbridges, OHCI
@@ -75,6 +76,8 @@ ohci_pci_start (struct usb_hcd *hcd)
&& pdev->device == 0xc861) {
ohci_info (ohci,
"WARNING: OPTi workarounds unavailable\n");
+ /* OPTi sometimes acts wierd during init */
+ ohci->flags = OHCI_QUIRK_INITRESET;
}
/* Check for NSC87560. We have to look at the bridge (fn1) to
@@ -92,6 +95,12 @@ ohci_pci_start (struct usb_hcd *hcd)
ohci_info (ohci, "Using NSC SuperIO setup\n");
}
}
+
+ /* SiS sometimes acts wierd during init */
+ else if (pdev->vendor == PCI_VENDOR_ID_SI) {
+ ohci->flags = OHCI_QUIRK_INITRESET;
+ ohci_info(ohci, "SiS init quirk\n");
+ }
}
@@ -101,6 +110,15 @@ ohci_pci_start (struct usb_hcd *hcd)
return ret;
}
+ /* NOTE: this is a second reset. the first one helps
+ * keep bios/smm irqs from making trouble, but it was
+ * probably more than 1msec ago...
+ */
+ if (hc_reset (ohci) < 0) {
+ ohci_stop (hcd);
+ return -ENODEV;
+ }
+
if (hc_start (ohci) < 0) {
ohci_err (ohci, "can't start\n");
ohci_stop (hcd);
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index dcc511662c2c..079bbc1b00c9 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -387,6 +387,7 @@ struct ohci_hcd {
unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */
+#define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */
// there are also chip quirks/bugs in init logic
/*
@@ -405,13 +406,14 @@ static inline void disable (struct ohci_hcd *ohci)
}
#define FI 0x2edf /* 12000 bits per frame (-1) */
-#define DEFAULT_FMINTERVAL ((((6 * (FI - 210)) / 7) << 16) | FI)
+#define FSMP(fi) ((6 * ((fi) - 210)) / 7)
#define LSTHRESH 0x628 /* lowspeed bit threshold */
static inline void periodic_reinit (struct ohci_hcd *ohci)
{
+ u32 fi = ohci->fminterval & 0x0ffff;
writel (ohci->fminterval, &ohci->regs->fminterval);
- writel (((9 * FI) / 10) & 0x3fff, &ohci->regs->periodicstart);
+ writel (((9 * fi) / 10) & 0x3fff, &ohci->regs->periodicstart);
writel (LSTHRESH, &ohci->regs->lsthresh);
}
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 00e6eb15a6ce..fe924e65ba35 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -1661,6 +1661,8 @@ static void stall_callback(unsigned long ptr)
/* Poll for and perform state transitions */
hc_state_transitions(uhci);
+ if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED))
+ uhci_check_resume(uhci);
init_stall_timer(hcd);
}
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index b4bf3b6cac38..3a6735740364 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -352,6 +352,12 @@ struct uhci_hcd {
int resume_detect; /* Need a Global Resume */
unsigned int saved_framenumber; /* Save during PM suspend */
+ /* Support for port suspend/resume */
+ unsigned long port_c_suspend; /* Bit-arrays of ports */
+ unsigned long suspended_ports;
+ unsigned long resuming_ports;
+ unsigned long resume_timeout; /* Time to stop signalling */
+
/* Main list of URB's currently controlled by this HC */
struct list_head urb_list; /* P: uhci->schedule_lock */
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index 2dde381632e9..538be7c5a409 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -36,13 +36,13 @@ static __u8 root_hub_hub_des[] =
static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- unsigned long io_addr = uhci->io_addr;
- int i;
+ int port;
*buf = 0;
- for (i = 0; i < uhci->rh_numports; i++) {
- if (inw(io_addr + USBPORTSC1 + i * 2) & RWC_BITS)
- *buf |= (1 << (i + 1));
+ for (port = 0; port < uhci->rh_numports; ++port) {
+ if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) ||
+ test_bit(port, &uhci->port_c_suspend))
+ *buf |= (1 << (port + 1));
}
return !!*buf;
}
@@ -62,31 +62,67 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
status &= ~(RWC_BITS|WZ_BITS); \
outw(status, port_addr)
+/* UHCI controllers don't automatically stop resume signalling after 20 msec,
+ * so we have to poll and check timeouts in order to take care of it.
+ * FIXME: Synchronize access to these fields by a spinlock.
+ */
+static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
+ unsigned int port_addr)
+{
+ int status;
+
+ if (test_bit(port, &uhci->suspended_ports)) {
+ CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD);
+ clear_bit(port, &uhci->suspended_ports);
+ clear_bit(port, &uhci->resuming_ports);
+ set_bit(port, &uhci->port_c_suspend);
+ }
+}
+
+static void uhci_check_resume(struct uhci_hcd *uhci)
+{
+ unsigned int port;
+ unsigned int port_addr;
+
+ for (port = 0; port < uhci->rh_numports; ++port) {
+ port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
+ if (unlikely(inw(port_addr) & USBPORTSC_RD)) {
+ if (!test_bit(port, &uhci->resuming_ports)) {
+
+ /* Port received a wakeup request */
+ set_bit(port, &uhci->resuming_ports);
+ uhci->resume_timeout = jiffies +
+ msecs_to_jiffies(20);
+ } else if (time_after_eq(jiffies,
+ uhci->resume_timeout)) {
+ uhci_finish_suspend(uhci, port, port_addr);
+ }
+ }
+ }
+}
/* size of returned buffer is part of USB spec */
static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- int status, retval = 0, len = 0;
- unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * (wIndex-1);
- __u16 wPortChange, wPortStatus;
+ int status, lstatus, retval = 0, len = 0;
+ unsigned int port = wIndex - 1;
+ unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
+ u16 wPortChange, wPortStatus;
switch (typeReq) {
- /* Request Destination:
- without flags: Device,
- RH_INTERFACE: interface,
- RH_ENDPOINT: endpoint,
- RH_CLASS means HUB here,
- RH_OTHER | RH_CLASS almost ever means HUB_PORT here
- */
case GetHubStatus:
- *(__u32 *)buf = cpu_to_le32(0);
+ *(u32 *) buf = cpu_to_le32(0);
OK(4); /* hub power */
case GetPortStatus:
- if (!wIndex || wIndex > uhci->rh_numports)
+ if (port >= uhci->rh_numports)
goto err;
+
+ if (uhci->resuming_ports)
+ uhci_check_resume(uhci);
+
status = inw(port_addr);
/* Intel controllers report the OverCurrent bit active on.
@@ -97,37 +133,46 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
PCI_VENDOR_ID_VIA)
status ^= USBPORTSC_OC;
- /* UHCI doesn't support C_SUSPEND and C_RESET (always false) */
- wPortChange = 0;
+ /* UHCI doesn't support C_RESET (always false) */
+ wPortChange = lstatus = 0;
if (status & USBPORTSC_CSC)
- wPortChange |= 1 << (USB_PORT_FEAT_C_CONNECTION - 16);
+ wPortChange |= USB_PORT_STAT_C_CONNECTION;
if (status & USBPORTSC_PEC)
- wPortChange |= 1 << (USB_PORT_FEAT_C_ENABLE - 16);
+ wPortChange |= USB_PORT_STAT_C_ENABLE;
if (status & USBPORTSC_OCC)
- wPortChange |= 1 << (USB_PORT_FEAT_C_OVER_CURRENT - 16);
+ wPortChange |= USB_PORT_STAT_C_OVERCURRENT;
+
+ if (test_bit(port, &uhci->port_c_suspend)) {
+ wPortChange |= USB_PORT_STAT_C_SUSPEND;
+ lstatus |= 1;
+ }
+ if (test_bit(port, &uhci->suspended_ports))
+ lstatus |= 2;
+ if (test_bit(port, &uhci->resuming_ports))
+ lstatus |= 4;
/* UHCI has no power switching (always on) */
- wPortStatus = 1 << USB_PORT_FEAT_POWER;
+ wPortStatus = USB_PORT_STAT_POWER;
if (status & USBPORTSC_CCS)
- wPortStatus |= 1 << USB_PORT_FEAT_CONNECTION;
+ wPortStatus |= USB_PORT_STAT_CONNECTION;
if (status & USBPORTSC_PE) {
- wPortStatus |= 1 << USB_PORT_FEAT_ENABLE;
+ wPortStatus |= USB_PORT_STAT_ENABLE;
if (status & (USBPORTSC_SUSP | USBPORTSC_RD))
- wPortStatus |= 1 << USB_PORT_FEAT_SUSPEND;
+ wPortStatus |= USB_PORT_STAT_SUSPEND;
}
if (status & USBPORTSC_OC)
- wPortStatus |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+ wPortStatus |= USB_PORT_STAT_OVERCURRENT;
if (status & USBPORTSC_PR)
- wPortStatus |= 1 << USB_PORT_FEAT_RESET;
+ wPortStatus |= USB_PORT_STAT_RESET;
if (status & USBPORTSC_LSDA)
- wPortStatus |= 1 << USB_PORT_FEAT_LOWSPEED;
+ wPortStatus |= USB_PORT_STAT_LOW_SPEED;
if (wPortChange)
- dev_dbg(uhci_dev(uhci), "port %d portsc %04x\n",
- wIndex, status);
+ dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x\n",
+ wIndex, status, lstatus);
- *(__u16 *)buf = cpu_to_le16(wPortStatus);
- *(__u16 *)(buf + 2) = cpu_to_le16(wPortChange);
+ *(u16 *) buf = cpu_to_le16(wPortStatus);
+ *(u16 *) (buf + 2) = cpu_to_le16(wPortChange);
OK(4);
case SetHubFeature: /* We don't implement these */
case ClearHubFeature:
@@ -140,11 +185,12 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
break;
case SetPortFeature:
- if (!wIndex || wIndex > uhci->rh_numports)
+ if (port >= uhci->rh_numports)
goto err;
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
+ set_bit(port, &uhci->suspended_ports);
SET_RH_PORTSTAT(USBPORTSC_SUSP);
OK(0);
case USB_PORT_FEAT_RESET:
@@ -152,6 +198,9 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
mdelay(50); /* USB v1.1 7.1.7.3 */
CLR_RH_PORTSTAT(USBPORTSC_PR);
udelay(10);
+
+ /* Reset terminates Resume signalling */
+ uhci_finish_suspend(uhci, port, port_addr);
SET_RH_PORTSTAT(USBPORTSC_PE);
mdelay(10);
CLR_RH_PORTSTAT(USBPORTSC_PEC|USBPORTSC_CSC);
@@ -164,21 +213,38 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
break;
case ClearPortFeature:
- if (!wIndex || wIndex > uhci->rh_numports)
+ if (port >= uhci->rh_numports)
goto err;
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
CLR_RH_PORTSTAT(USBPORTSC_PE);
+
+ /* Disable terminates Resume signalling */
+ uhci_finish_suspend(uhci, port, port_addr);
OK(0);
case USB_PORT_FEAT_C_ENABLE:
CLR_RH_PORTSTAT(USBPORTSC_PEC);
OK(0);
case USB_PORT_FEAT_SUSPEND:
- CLR_RH_PORTSTAT(USBPORTSC_SUSP);
+ if (test_bit(port, &uhci->suspended_ports) &&
+ !test_and_set_bit(port,
+ &uhci->resuming_ports)) {
+ uhci->resume_timeout = jiffies +
+ msecs_to_jiffies(20);
+ SET_RH_PORTSTAT(USBPORTSC_RD);
+
+ /* The controller won't allow RD to be set
+ * if the port is disabled. When this happens
+ * just skip the Resume signalling.
+ */
+ if (!(inw(port_addr) & USBPORTSC_RD))
+ uhci_finish_suspend(uhci, port,
+ port_addr);
+ }
OK(0);
case USB_PORT_FEAT_C_SUSPEND:
- /* this driver won't report these */
+ clear_bit(port, &uhci->port_c_suspend);
OK(0);
case USB_PORT_FEAT_POWER:
/* UHCI has no power switching */
diff --git a/drivers/usb/image/Kconfig b/drivers/usb/image/Kconfig
index 0b0f80e4f9a7..b541b67d2eb6 100644
--- a/drivers/usb/image/Kconfig
+++ b/drivers/usb/image/Kconfig
@@ -30,11 +30,12 @@ config USB_MICROTEK
This driver can be compiled as a module, called microtek.
config USB_HPUSBSCSI
- tristate "HP53xx USB scanner support (EXPERIMENTAL)"
- depends on USB && SCSI && EXPERIMENTAL
+ tristate "HP53xx USB scanner support"
+ depends on USB && SCSI
help
Say Y here if you want support for the HP 53xx series of scanners
- and the Minolta Scan Dual. This driver is experimental.
+ and the Minolta Scan Dual.
The scanner will be accessible as a SCSI device.
+ Please note that recent versions of SANE use usbfs, not this driver.
This can be compiled as a module, called hpusbscsi.
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 9d3aa3075086..14b218239a8c 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -324,7 +324,7 @@ static inline void mts_urb_abort(struct mts_desc* desc) {
MTS_DEBUG_GOT_HERE();
mts_debug_dump(desc);
- usb_unlink_urb( desc->urb );
+ usb_kill_urb( desc->urb );
}
static int mts_scsi_abort (Scsi_Cmnd *srb)
@@ -822,10 +822,10 @@ static void mts_usb_disconnect (struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
+ usb_kill_urb(desc->urb);
scsi_remove_host(desc->host);
- usb_unlink_urb(desc->urb);
- scsi_host_put(desc->host);
+ scsi_host_put(desc->host);
usb_free_urb(desc->urb);
kfree(desc);
}
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 1b94a27f2eb4..34b0e91aeb1b 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -1439,6 +1439,12 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
+#define USB_VENDOR_ID_CODEMERCS 0x07c0
+#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500
+#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501
+#define USB_DEVICE_ID_CODEMERCS_IOW48 0x1502
+#define USB_DEVICE_ID_CODEMERCS_IOW28 0x1503
+
static struct hid_blacklist {
__u16 idVendor;
__u16 idProduct;
@@ -1521,6 +1527,11 @@ static struct hid_blacklist {
{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
+ { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE },
+
{ 0, 0 }
};
diff --git a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig
index 4ac7ac4f3b1d..678e5fcbe29a 100644
--- a/drivers/usb/media/Kconfig
+++ b/drivers/usb/media/Kconfig
@@ -123,11 +123,11 @@ config USB_SE401
module will be called se401.
config USB_SN9C102
- tristate "USB SN9C10[12] PC Camera Controller support"
+ tristate "USB SN9C10x PC Camera Controller support"
depends on USB && VIDEO_DEV
---help---
- Say Y here if you want support for cameras based on SONiX SN9C101
- or SN9C102 PC Camera Controllers.
+ Say Y here if you want support for cameras based on SONiX SN9C101,
+ SN9C102 or SN9C103 PC Camera Controllers.
See <file:Documentation/usb/sn9c102.txt> for more informations.
diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c
index 0e5425f328d0..0aae6ecc7ad6 100644
--- a/drivers/usb/media/dabusb.c
+++ b/drivers/usb/media/dabusb.c
@@ -109,16 +109,13 @@ static void dump_urb (struct urb *urb)
static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q)
{
unsigned long flags;
- struct list_head *p;
pbuff_t b;
dbg("dabusb_cancel_queue");
spin_lock_irqsave (&s->lock, flags);
- for (p = q->next; p != q; p = p->next) {
- b = list_entry (p, buff_t, buff_list);
-
+ list_for_each_entry(b, q, buff_list) {
#ifdef DEBUG
dump_urb(b->purb);
#endif
@@ -598,6 +595,7 @@ static int dabusb_open (struct inode *inode, struct file *file)
if (file->f_flags & O_NONBLOCK) {
return -EBUSY;
}
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout (HZ / 2);
if (signal_pending (current)) {
diff --git a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c
index 3c741a8f5b73..3376654ca051 100644
--- a/drivers/usb/media/konicawc.c
+++ b/drivers/usb/media/konicawc.c
@@ -362,8 +362,8 @@ static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs)
else if (!urb->status && !cam->last_data_urb->status)
len = konicawc_compress_iso(uvd, cam->last_data_urb, urb);
- resubmit_urb(uvd, urb);
resubmit_urb(uvd, cam->last_data_urb);
+ resubmit_urb(uvd, urb);
cam->last_data_urb = NULL;
uvd->stats.urb_length = len;
uvd->stats.data_count += len;
diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h
index 62ff2144392c..050a25d6f6aa 100644
--- a/drivers/usb/media/sn9c102.h
+++ b/drivers/usb/media/sn9c102.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * V4L2 driver for SN9C10[12] PC Camera Controllers *
+ * V4L2 driver for SN9C10x PC Camera Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
@@ -49,12 +49,18 @@
/*****************************************************************************/
-#define SN9C102_MODULE_NAME "V4L2 driver for SN9C10[12] PC Camera Controllers"
+#define SN9C102_MODULE_NAME "V4L2 driver for SN9C10x PC Camera Controllers"
#define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL"
-#define SN9C102_MODULE_VERSION "1:1.08"
-#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 8)
+#define SN9C102_MODULE_VERSION "1:1.10"
+#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 10)
+
+enum sn9c102_bridge {
+ BRIDGE_SN9C101 = 0x01,
+ BRIDGE_SN9C102 = 0x02,
+ BRIDGE_SN9C103 = 0x04,
+};
SN9C102_ID_TABLE;
SN9C102_SENSOR_TABLE;
@@ -105,6 +111,7 @@ struct sn9c102_device {
struct video_device* v4ldev;
+ enum sn9c102_bridge bridge;
struct sn9c102_sensor* sensor;
struct usb_device* usbdev;
diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c
index 9f775f74002c..3881ae5ea08f 100644
--- a/drivers/usb/media/sn9c102_core.c
+++ b/drivers/usb/media/sn9c102_core.c
@@ -1,5 +1,5 @@
/***************************************************************************
- * V4L2 driver for SN9C10[12] PC Camera Controllers *
+ * V4L2 driver for SN9C10x PC Camera Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
@@ -169,15 +169,15 @@ static u32 sn9c102_request_buffers(struct sn9c102_device* cam, u32 count)
cam->nbuffers = count;
while (cam->nbuffers > 0) {
- if ((buff = rvmalloc(cam->nbuffers * imagesize)))
+ if ((buff = rvmalloc(cam->nbuffers * PAGE_ALIGN(imagesize))))
break;
cam->nbuffers--;
}
for (i = 0; i < cam->nbuffers; i++) {
- cam->frame[i].bufmem = buff + i*imagesize;
+ cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
cam->frame[i].buf.index = i;
- cam->frame[i].buf.m.offset = i*imagesize;
+ cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
cam->frame[i].buf.length = imagesize;
cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
cam->frame[i].buf.sequence = 0;
@@ -388,7 +388,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
data[4] = data3;
data[5] = data4;
data[6] = data5;
- data[7] = 0x10;
+ data[7] = 0x14;
res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
if (res < 0)
@@ -1022,15 +1022,79 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
static ssize_t
sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
{
+ struct sn9c102_device* cam;
+ enum sn9c102_bridge bridge;
ssize_t res = 0;
u8 value;
ssize_t count;
+ if (down_interruptible(&sn9c102_sysfs_lock))
+ return -ERESTARTSYS;
+
+ cam = video_get_drvdata(to_video_device(cd));
+ if (!cam) {
+ up(&sn9c102_sysfs_lock);
+ return -ENODEV;
+ }
+
+ bridge = cam->bridge;
+
+ up(&sn9c102_sysfs_lock);
+
value = sn9c102_strtou8(buf, len, &count);
- if (!count || value > 0x0f)
+ if (!count)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
+ switch (bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ if (value > 0x0f)
+ return -EINVAL;
+ if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
+ res = sn9c102_store_val(cd, buf, len);
+ break;
+ case BRIDGE_SN9C103:
+ if (value > 0x7f)
+ return -EINVAL;
+ if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0)
+ res = sn9c102_store_val(cd, buf, len);
+ break;
+ }
+
+ return res;
+}
+
+
+static ssize_t
+sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
+{
+ ssize_t res = 0;
+ u8 value;
+ ssize_t count;
+
+ value = sn9c102_strtou8(buf, len, &count);
+ if (!count || value > 0x7f)
+ return -EINVAL;
+
+ if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0)
+ res = sn9c102_store_val(cd, buf, len);
+
+ return res;
+}
+
+
+static ssize_t
+sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
+{
+ ssize_t res = 0;
+ u8 value;
+ ssize_t count;
+
+ value = sn9c102_strtou8(buf, len, &count);
+ if (!count || value > 0x7f)
+ return -EINVAL;
+
+ if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0)
res = sn9c102_store_val(cd, buf, len);
return res;
@@ -1046,6 +1110,8 @@ static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
sn9c102_show_i2c_val, sn9c102_store_i2c_val);
static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
+static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
+static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
static void sn9c102_create_sysfs(struct sn9c102_device* cam)
@@ -1054,7 +1120,12 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam)
video_device_create_file(v4ldev, &class_device_attr_reg);
video_device_create_file(v4ldev, &class_device_attr_val);
- video_device_create_file(v4ldev, &class_device_attr_green);
+ if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+ video_device_create_file(v4ldev, &class_device_attr_green);
+ else if (cam->bridge == BRIDGE_SN9C103) {
+ video_device_create_file(v4ldev, &class_device_attr_blue);
+ video_device_create_file(v4ldev, &class_device_attr_red);
+ }
if (cam->sensor->slave_write_id && cam->sensor->slave_read_id) {
video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
video_device_create_file(v4ldev, &class_device_attr_i2c_val);
@@ -1092,21 +1163,13 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
v_start = (u8)(rect->top - s->cropcap.bounds.top),
h_size = (u8)(rect->width / 16),
- v_size = (u8)(rect->height / 16),
- ae_strx = 0x00,
- ae_stry = 0x00,
- ae_endx = h_size / 2,
- ae_endy = v_size / 2;
+ v_size = (u8)(rect->height / 16);
int err = 0;
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
err += sn9c102_write_reg(cam, h_size, 0x15);
err += sn9c102_write_reg(cam, v_size, 0x16);
- err += sn9c102_write_reg(cam, ae_strx, 0x1c);
- err += sn9c102_write_reg(cam, ae_stry, 0x1d);
- err += sn9c102_write_reg(cam, ae_endx, 0x1e);
- err += sn9c102_write_reg(cam, ae_endy, 0x1f);
if (err)
return -EIO;
@@ -1636,16 +1699,21 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
return -EFAULT;
- if ((err = s->set_ctrl(cam, &ctrl)))
- return err;
-
n = sizeof(s->qctrl) / sizeof(s->qctrl[0]);
for (i = 0; i < n; i++)
if (ctrl.id == s->qctrl[i].id) {
- s->_qctrl[i].default_value = ctrl.value;
+ if (ctrl.value < s->qctrl[i].minimum ||
+ ctrl.value > s->qctrl[i].maximum)
+ return -ERANGE;
+ ctrl.value -= ctrl.value % s->qctrl[i].step;
break;
}
+ if ((err = s->set_ctrl(cam, &ctrl)))
+ return err;
+
+ s->_qctrl[i].default_value = ctrl.value;
+
return 0;
}
@@ -1776,7 +1844,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
DBG(1, "VIDIOC_S_CROP failed because of hardware "
"problems. To use the camera, close and open "
"/dev/video%d again.", cam->v4ldev->minor)
- return err;
+ return -EIO;
}
s->pix_format.width = rect->width/scale;
@@ -1951,7 +2019,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
DBG(1, "VIDIOC_S_FMT failed because of hardware "
"problems. To use the camera, close and open "
"/dev/video%d again.", cam->v4ldev->minor)
- return err;
+ return -EIO;
}
memcpy(pfmt, pix, sizeof(*pix));
@@ -2286,15 +2354,17 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
r = sn9c102_read_reg(cam, 0x00);
if (r < 0 || r != 0x10) {
- DBG(1, "Sorry, this is not a SN9C10[12] based camera "
+ DBG(1, "Sorry, this is not a SN9C10x based camera "
"(vid/pid 0x%04X/0x%04X)",
sn9c102_id_table[i].idVendor,sn9c102_id_table[i].idProduct)
err = -ENODEV;
goto fail;
}
- DBG(2, "SN9C10[12] PC Camera Controller detected "
- "(vid/pid 0x%04X/0x%04X)",
+ cam->bridge = (sn9c102_id_table[i].idProduct & 0xffc0) == 0x6080 ?
+ BRIDGE_SN9C102 : BRIDGE_SN9C103;
+
+ DBG(2, "SN9C10x PC Camera Controller detected (vid/pid 0x%04X/0x%04X)",
sn9c102_id_table[i].idVendor, sn9c102_id_table[i].idProduct)
for (i = 0; sn9c102_sensor_table[i]; i++) {
@@ -2318,7 +2388,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->state |= DEV_MISCONFIGURED;
}
- strcpy(cam->v4ldev->name, "SN9C10[12] PC Camera");
+ strcpy(cam->v4ldev->name, "SN9C10x PC Camera");
cam->v4ldev->owner = THIS_MODULE;
cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
cam->v4ldev->hardware = VID_HARDWARE_SN9C102;
diff --git a/drivers/usb/media/sn9c102_pas106b.c b/drivers/usb/media/sn9c102_pas106b.c
index a302a4845893..8453409ea125 100644
--- a/drivers/usb/media/sn9c102_pas106b.c
+++ b/drivers/usb/media/sn9c102_pas106b.c
@@ -1,5 +1,5 @@
/***************************************************************************
- * Driver for PAS106B image sensor connected to the SN9C10[12] PC Camera *
+ * Driver for PAS106B image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
@@ -100,26 +100,26 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
switch (ctrl->id) {
case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_write(cam, 0x0c, ctrl->value & 0x1f);
+ err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
break;
case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x1f);
+ err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
break;
case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x0e, ctrl->value & 0x1f);
+ err += sn9c102_i2c_write(cam, 0x0e, ctrl->value);
break;
case V4L2_CID_BRIGHTNESS:
- err += sn9c102_i2c_write(cam, 0x0d, 0x1f-(ctrl->value & 0x1f));
+ err += sn9c102_i2c_write(cam, 0x0d, 0x1f - ctrl->value);
break;
case V4L2_CID_CONTRAST:
- err += sn9c102_i2c_write(cam, 0x0f, ctrl->value & 0x03);
+ err += sn9c102_i2c_write(cam, 0x0f, ctrl->value);
break;
default:
return -EINVAL;
}
err += sn9c102_i2c_write(cam, 0x13, 0x01);
- return err;
+ return err ? -EIO : 0;
}
diff --git a/drivers/usb/media/sn9c102_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c
index 26944eaf85d0..ffd12ed14e34 100644
--- a/drivers/usb/media/sn9c102_pas202bcb.c
+++ b/drivers/usb/media/sn9c102_pas202bcb.c
@@ -1,5 +1,5 @@
/***************************************************************************
- * Driver for PAS202BCB image sensor connected to the SN9C10[12] PC Camera *
+ * Driver for PAS202BCB image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
@@ -95,23 +95,23 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
switch (ctrl->id) {
case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x0f);
+ err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
break;
case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x07, ctrl->value & 0x0f);
+ err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
break;
case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x10, ctrl->value & 0x1f);
+ err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
break;
case V4L2_CID_BRIGHTNESS:
- err += sn9c102_i2c_write(cam, 0x06, 0x0f-(ctrl->value & 0x0f));
+ err += sn9c102_i2c_write(cam, 0x06, 0x0f - ctrl->value);
break;
default:
return -EINVAL;
}
err += sn9c102_i2c_write(cam, 0x11, 0x01);
- return err;
+ return err ? -EIO : 0;
}
diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h
index 3e7e4a2578bc..9632a5a63ccc 100644
--- a/drivers/usb/media/sn9c102_sensor.h
+++ b/drivers/usb/media/sn9c102_sensor.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * API for image sensors connected to the SN9C10[12] PC Camera Controllers *
+ * API for image sensors connected to the SN9C10x PC Camera Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
@@ -89,17 +89,44 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
/* Each SN9C10X camera has proper PID/VID identifiers. Add them here in case.*/
#define SN9C102_ID_TABLE \
static const struct usb_device_id sn9c102_id_table[] = { \
- { USB_DEVICE(0xc45, 0x6001), }, /* TAS5110C1B */ \
- { USB_DEVICE(0xc45, 0x6005), }, /* TAS5110C1B */ \
- { USB_DEVICE(0xc45, 0x6009), }, /* PAS106B */ \
- { USB_DEVICE(0xc45, 0x600d), }, /* PAS106B */ \
- { USB_DEVICE(0xc45, 0x6024), }, \
- { USB_DEVICE(0xc45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \
- { USB_DEVICE(0xc45, 0x6028), }, /* PAS202BCB */ \
- { USB_DEVICE(0xc45, 0x6029), }, /* PAS106B */ \
- { USB_DEVICE(0xc45, 0x602a), }, /* HV7131[D|E1] */ \
- { USB_DEVICE(0xc45, 0x602c), }, /* OV7620 */ \
- { USB_DEVICE(0xc45, 0x6030), }, /* MI03 */ \
+ { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \
+ { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \
+ { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \
+ { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \
+ { USB_DEVICE(0x0c45, 0x6024), }, \
+ { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \
+ { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */ \
+ { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \
+ { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131[D|E1] */ \
+ { USB_DEVICE(0x0c45, 0x602b), }, \
+ { USB_DEVICE(0x0c45, 0x602c), }, /* OV7620 */ \
+ { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \
+ { USB_DEVICE(0x0c45, 0x6080), }, \
+ { USB_DEVICE(0x0c45, 0x6082), }, /* MI0343 and MI0360 */ \
+ { USB_DEVICE(0x0c45, 0x6083), }, /* HV7131[D|E1] */ \
+ { USB_DEVICE(0x0c45, 0x6088), }, \
+ { USB_DEVICE(0x0c45, 0x608a), }, \
+ { USB_DEVICE(0x0c45, 0x608b), }, \
+ { USB_DEVICE(0x0c45, 0x608c), }, /* HV7131x */ \
+ { USB_DEVICE(0x0c45, 0x608e), }, /* CIS-VF10 */ \
+ { USB_DEVICE(0x0c45, 0x608f), }, /* OV7630 */ \
+ { USB_DEVICE(0x0c45, 0x60a0), }, \
+ { USB_DEVICE(0x0c45, 0x60a2), }, \
+ { USB_DEVICE(0x0c45, 0x60a3), }, \
+ { USB_DEVICE(0x0c45, 0x60a8), }, /* PAS106B */ \
+ { USB_DEVICE(0x0c45, 0x60aa), }, /* TAS5130D1B */ \
+ { USB_DEVICE(0x0c45, 0x60ab), }, /* TAS5110C1B */ \
+ { USB_DEVICE(0x0c45, 0x60ac), }, \
+ { USB_DEVICE(0x0c45, 0x60ae), }, \
+ { USB_DEVICE(0x0c45, 0x60af), }, /* PAS202BCB */ \
+ { USB_DEVICE(0x0c45, 0x60b0), }, \
+ { USB_DEVICE(0x0c45, 0x60b2), }, \
+ { USB_DEVICE(0x0c45, 0x60b3), }, \
+ { USB_DEVICE(0x0c45, 0x60b8), }, \
+ { USB_DEVICE(0x0c45, 0x60ba), }, \
+ { USB_DEVICE(0x0c45, 0x60bb), }, \
+ { USB_DEVICE(0x0c45, 0x60bc), }, \
+ { USB_DEVICE(0x0c45, 0x60be), }, \
{ } \
};
@@ -173,9 +200,7 @@ struct sn9c102_sensor {
/*
These identifiers must be provided if the image sensor implements
- the standard I2C protocol. TASC sensors don't, although they have a
- serial interface: so this is a case where the "raw" I2C version
- could be helpful.
+ the standard I2C protocol.
*/
u8 slave_read_id, slave_write_id; /* reg. 0x09 */
@@ -214,7 +239,8 @@ struct sn9c102_sensor {
the list above. The returned value must follow the V4L2
specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER
are not supported by this driver, so do not implement them. Also,
- passed values are NOT checked to see if they are out of bounds.
+ you don't have to check whether the passed values are out of bounds,
+ given that this is done by the core module.
*/
struct v4l2_cropcap cropcap;
diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c
index 68e1b2e0ce18..006a6b569f4a 100644
--- a/drivers/usb/media/sn9c102_tas5110c1b.c
+++ b/drivers/usb/media/sn9c102_tas5110c1b.c
@@ -1,6 +1,6 @@
/***************************************************************************
- * Driver for TAS5110C1B image sensor connected to the SN9C10[12] PC *
- * Camera Controllers *
+ * Driver for TAS5110C1B image sensor connected to the SN9C10x PC Camera *
+ * Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
@@ -24,6 +24,8 @@
static struct sn9c102_sensor tas5110c1b;
+static struct v4l2_control tas5110c1b_gain;
+
static int tas5110c1b_init(struct sn9c102_device* cam)
{
@@ -38,25 +40,42 @@ static int tas5110c1b_init(struct sn9c102_device* cam)
err += sn9c102_write_reg(cam, 0x06, 0x18);
err += sn9c102_write_reg(cam, 0xfb, 0x19);
- err += sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, 0x00, 0xc0,
- 0x80, 0, 0);
+ err += sn9c102_i2c_write(cam, 0xc0, 0x80);
return err;
}
+static int tas5110c1b_get_ctrl(struct sn9c102_device* cam,
+ struct v4l2_control* ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ ctrl->value = tas5110c1b_gain.value;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
const struct v4l2_control* ctrl)
{
+ int err = 0;
+
switch (ctrl->id) {
case V4L2_CID_GAIN:
- return sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11,
- 0x02, 0x20,
- 0xff - (ctrl->value & 0xff),
- 0, 0);
+ if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value)))
+ tas5110c1b_gain.value = ctrl->value;
+ break;
default:
return -EINVAL;
}
+
+ return err ? -EIO : 0;
}
@@ -85,6 +104,8 @@ static struct sn9c102_sensor tas5110c1b = {
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_3WIRES,
+ .slave_read_id = 0xff, /* fictitious */
+ .slave_write_id = 0xff, /* fictitious */
.init = &tas5110c1b_init,
.qctrl = {
{
@@ -92,9 +113,9 @@ static struct sn9c102_sensor tas5110c1b = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "global gain",
.minimum = 0x00,
- .maximum = 0xff,
+ .maximum = 0xf6,
.step = 0x01,
- .default_value = 0x48,
+ .default_value = 0x40,
.flags = 0,
},
},
@@ -113,6 +134,7 @@ static struct sn9c102_sensor tas5110c1b = {
.height = 288,
},
},
+ .get_ctrl = &tas5110c1b_get_ctrl,
.set_crop = &tas5110c1b_set_crop,
.pix_format = {
.width = 352,
@@ -130,7 +152,8 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
/* At the moment, sensor detection is based on USB pid/vid */
if (tas5110c1b.usbdev->descriptor.idProduct != 0x6001 &&
- tas5110c1b.usbdev->descriptor.idProduct != 0x6005)
+ tas5110c1b.usbdev->descriptor.idProduct != 0x6005 &&
+ tas5110c1b.usbdev->descriptor.idProduct != 0x60ab)
return -ENODEV;
return 0;
diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c
index 0bab19435399..7af73acd2c37 100644
--- a/drivers/usb/media/sn9c102_tas5130d1b.c
+++ b/drivers/usb/media/sn9c102_tas5130d1b.c
@@ -1,6 +1,6 @@
/***************************************************************************
- * Driver for TAS5130D1B image sensor connected to the SN9C10[12] PC *
- * Camera Controllers *
+ * Driver for TAS5130D1B image sensor connected to the SN9C10x PC Camera *
+ * Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
@@ -24,6 +24,8 @@
static struct sn9c102_sensor tas5130d1b;
+static struct v4l2_control tas5130d1b_gain, tas5130d1b_exposure;
+
static int tas5130d1b_init(struct sn9c102_device* cam)
{
@@ -38,25 +40,47 @@ static int tas5130d1b_init(struct sn9c102_device* cam)
err += sn9c102_write_reg(cam, 0x60, 0x17);
err += sn9c102_write_reg(cam, 0x07, 0x18);
- err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40,
- 0x47, 0, 0);
-
return err;
}
+static int tas5130d1b_get_ctrl(struct sn9c102_device* cam,
+ struct v4l2_control* ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ ctrl->value = tas5130d1b_gain.value;
+ break;
+ case V4L2_CID_EXPOSURE:
+ ctrl->value = tas5130d1b_exposure.value;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
const struct v4l2_control* ctrl)
{
+ int err = 0;
+
switch (ctrl->id) {
case V4L2_CID_GAIN:
- return sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11,
- 0x02, 0x20,
- 0xff - (ctrl->value & 0xff),
- 0, 0);
+ if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value)))
+ tas5130d1b_gain.value = ctrl->value;
+ break;
+ case V4L2_CID_EXPOSURE:
+ if (!(err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value)))
+ tas5130d1b_exposure.value = ctrl->value;
+ break;
default:
return -EINVAL;
}
+
+ return err ? -EIO : 0;
}
@@ -85,6 +109,8 @@ static struct sn9c102_sensor tas5130d1b = {
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_3WIRES,
+ .slave_read_id = 0xff, /* fictitious */
+ .slave_write_id = 0xff, /* fictitious */
.init = &tas5130d1b_init,
.qctrl = {
{
@@ -92,12 +118,23 @@ static struct sn9c102_sensor tas5130d1b = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "global gain",
.minimum = 0x00,
- .maximum = 0xff,
+ .maximum = 0xf6,
+ .step = 0x02,
+ .default_value = 0x00,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x00,
+ .maximum = 0x47,
.step = 0x01,
.default_value = 0x00,
.flags = 0,
},
},
+ .get_ctrl = &tas5130d1b_get_ctrl,
.set_ctrl = &tas5130d1b_set_ctrl,
.cropcap = {
.bounds = {
@@ -129,7 +166,8 @@ int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
sn9c102_attach_sensor(cam, &tas5130d1b);
/* At the moment, sensor detection is based on USB pid/vid */
- if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025)
+ if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025 &&
+ tas5130d1b.usbdev->descriptor.idProduct != 0x60aa)
return -ENODEV;
return 0;
diff --git a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c
index 0f9c5753772d..f902884a7bbb 100644
--- a/drivers/usb/misc/tiglusb.c
+++ b/drivers/usb/misc/tiglusb.c
@@ -115,6 +115,7 @@ tiglusb_open (struct inode *inode, struct file *filp)
return -EBUSY;
}
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout (HZ / 2);
if (signal_pending (current)) {
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index c366fe957060..a84569a43c39 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -668,7 +668,7 @@ static int kaweth_open(struct net_device *net)
INTBUFFERSIZE,
int_callback,
kaweth,
- 8);
+ 250); /* overriding the descriptor */
kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle;
kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index 6724399513f3..c7daf82e3a34 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -20,7 +20,7 @@
#include <asm/uaccess.h>
/* Version Information */
-#define DRIVER_VERSION "v0.6.1 (2004/03/13)"
+#define DRIVER_VERSION "v0.6.2 (2004/08/27)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "rtl8150 based usb-ethernet driver"
@@ -344,7 +344,7 @@ static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
static int rtl8150_reset(rtl8150_t * dev)
{
- u8 data = 0x10;
+ u8 data = 0x11;
int i = HZ;
set_registers(dev, CR, 1, &data);
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index bcf56011ec22..a44cb9d96113 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -228,7 +228,7 @@ static int belkin_sa_open (struct usb_serial_port *port, struct file *filp)
port->interrupt_in_urb->dev = port->serial->dev;
retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (retval) {
- usb_unlink_urb(port->read_urb);
+ usb_kill_urb(port->read_urb);
err(" usb_submit_urb(read int) failed");
}
@@ -242,9 +242,9 @@ static void belkin_sa_close (struct usb_serial_port *port, struct file *filp)
dbg("%s port %d", __FUNCTION__, port->number);
/* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- usb_unlink_urb (port->interrupt_in_urb);
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
+ usb_kill_urb(port->interrupt_in_urb);
} /* belkin_sa_close */
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 33613b008557..6b5ec2af32ad 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -149,7 +149,7 @@ static void cyberjack_shutdown (struct usb_serial *serial)
dbg("%s", __FUNCTION__);
for (i=0; i < serial->num_ports; ++i) {
- usb_unlink_urb (serial->port[i]->interrupt_in_urb);
+ usb_kill_urb(serial->port[i]->interrupt_in_urb);
/* My special items, the standard routines free my urbs */
kfree(usb_get_serial_port_data(serial->port[i]));
usb_set_serial_port_data(serial->port[i], NULL);
@@ -189,8 +189,8 @@ static void cyberjack_close (struct usb_serial_port *port, struct file *filp)
if (port->serial->dev) {
/* shutdown any bulk reads that might be going on */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
}
}
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index f187b3165d57..5c4669db9b86 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -1553,13 +1553,17 @@ static void digi_close( struct usb_serial_port *port, struct file *filp )
dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count );
+ /* if disconnected, just clear flags */
+ if (!usb_get_intfdata(port->serial->interface))
+ goto exit;
+
/* do cleanup only after final close on this port */
spin_lock_irqsave( &priv->dp_port_lock, flags );
priv->dp_in_close = 1;
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
/* tell line discipline to process only XON/XOFF */
- tty->closing = 1;
+ tty->closing = 1;
/* wait for output to drain */
if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
@@ -1619,11 +1623,12 @@ dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_co
DIGI_CLOSE_TIMEOUT );
/* shutdown any outstanding bulk writes */
- usb_unlink_urb (port->write_urb);
+ usb_kill_urb(port->write_urb);
}
tty->closing = 0;
+exit:
spin_lock_irqsave( &priv->dp_port_lock, flags );
priv->dp_write_urb_in_use = 0;
priv->dp_in_close = 0;
@@ -1757,8 +1762,8 @@ dbg( "digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt() );
/* stop reads and writes on all ports */
for( i=0; i<serial->type->num_ports+1; i++ ) {
- usb_unlink_urb( serial->port[i]->read_urb );
- usb_unlink_urb( serial->port[i]->write_urb );
+ usb_kill_urb(serial->port[i]->read_urb);
+ usb_kill_urb(serial->port[i]->write_urb);
}
/* free the private data structures for all ports */
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 972f3b91d41c..edb3559d546a 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -185,7 +185,7 @@ static void empeg_close (struct usb_serial_port *port, struct file * filp)
dbg("%s - port %d", __FUNCTION__, port->number);
/* shutdown our bulk read */
- usb_unlink_urb (port->read_urb);
+ usb_kill_urb(port->read_urb);
/* Uncomment the following line if you want to see some statistics in your syslog */
/* dev_info (&port->dev, "Bytes In = %d Bytes Out = %d\n", bytes_in, bytes_out); */
}
@@ -406,7 +406,7 @@ static void empeg_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
static void empeg_throttle (struct usb_serial_port *port)
{
dbg("%s - port %d", __FUNCTION__, port->number);
- usb_unlink_urb (port->read_urb);
+ usb_kill_urb(port->read_urb);
}
@@ -583,10 +583,10 @@ static void __exit empeg_exit (void)
for (i = 0; i < NUM_URBS; ++i) {
if (write_urb_pool[i]) {
- /* FIXME - uncomment the following usb_unlink_urb call when
+ /* FIXME - uncomment the following usb_kill_urb call when
* the host controllers get fixed to set urb->dev = NULL after
* the urb is finished. Otherwise this call oopses. */
- /* usb_unlink_urb(write_urb_pool[i]); */
+ /* usb_kill_urb(write_urb_pool[i]); */
if (write_urb_pool[i]->transfer_buffer)
kfree(write_urb_pool[i]->transfer_buffer);
usb_free_urb (write_urb_pool[i]);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 9073ea84d8d3..9d3a8e831326 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -368,6 +368,9 @@ static struct usb_device_id id_table_8U232AM [] = {
{ USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0, 0x3ff) },
{ } /* Terminating entry */
};
@@ -478,6 +481,9 @@ static struct usb_device_id id_table_FT232BM [] = {
{ USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0x400, 0xffff) },
{ } /* Terminating entry */
};
@@ -595,6 +601,9 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
{ USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) },
+ { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
+ { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
+ { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
{ } /* Terminating entry */
};
@@ -1479,16 +1488,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
} /* Note change no line if hupcl is off */
/* shutdown our bulk read */
- if (port->read_urb) {
- if (usb_unlink_urb (port->read_urb) < 0) {
- /* Generally, this isn't an error. If the previous
- read bulk callback occurred (or is about to occur)
- while the port was being closed or was throtted
- (and is still throttled), the read urb will not
- have been submitted. */
- dbg("%s - failed to unlink read urb (generally not an error)", __FUNCTION__);
- }
- }
+ if (port->read_urb)
+ usb_kill_urb(port->read_urb);
} /* ftdi_close */
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 232213b02860..bc2b6d5aacaa 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -225,6 +225,14 @@
*/
#define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */
+/*
+ * Definitions for B&B Electronics products.
+ */
+#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */
+#define BANDB_USOTL4_PID 0xAC01 /* USOTL4 Isolated RS-485 Converter */
+#define BANDB_USTL4_PID 0xAC02 /* USTL4 RS-485 Converter */
+#define BANDB_USO9ML2_PID 0xAC03 /* USO9ML2 Isolated RS-232 Converter */
+
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 196fea084f21..c88885f8ca05 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -147,9 +147,9 @@ static void generic_cleanup (struct usb_serial_port *port)
if (serial->dev) {
/* shutdown any bulk reads that might be going on */
if (serial->num_bulk_out)
- usb_unlink_urb (port->write_urb);
+ usb_kill_urb(port->write_urb);
if (serial->num_bulk_in)
- usb_unlink_urb (port->read_urb);
+ usb_kill_urb(port->read_urb);
}
}
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index fc3a536f3696..d8d492ef99e8 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -1243,7 +1243,7 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
edge_port->openPending = FALSE;
if (edge_port->write_urb) {
- usb_unlink_urb (edge_port->write_urb);
+ usb_kill_urb(edge_port->write_urb);
}
if (edge_port->write_urb) {
@@ -2448,8 +2448,8 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
if (status) {
/* something went wrong */
dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__);
- usb_unlink_urb (urb);
- usb_free_urb (urb);
+ usb_kill_urb(urb);
+ usb_free_urb(urb);
return status;
}
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 55be299fdf84..41afb4c77f69 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -1977,7 +1977,7 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
/* chase the port close */
TIChasePort (edge_port);
- usb_unlink_urb (port->read_urb);
+ usb_kill_urb(port->read_urb);
/* assuming we can still talk to the device,
* send a close port command to it */
@@ -1992,7 +1992,7 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
--edge_port->edge_serial->num_ports_open;
if (edge_port->edge_serial->num_ports_open <= 0) {
/* last port is now closed, let's shut down our interrupt urb */
- usb_unlink_urb (port->serial->port[0]->interrupt_in_urb);
+ usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
edge_port->edge_serial->num_ports_open = 0;
}
edge_port->close_pending = 0;
@@ -2126,7 +2126,7 @@ static void edge_throttle (struct usb_serial_port *port)
status = TIClearRts (edge_port);
}
- usb_unlink_urb (port->read_urb);
+ usb_kill_urb(port->read_urb);
}
static void edge_unthrottle (struct usb_serial_port *port)
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 8fbce2732c51..1a748b515112 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -288,8 +288,8 @@ static void ipaq_close(struct usb_serial_port *port, struct file *filp)
/*
* shut down bulk read and write
*/
- usb_unlink_urb(port->write_urb);
- usb_unlink_urb(port->read_urb);
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
ipaq_destroy_lists(port);
kfree(priv);
usb_set_serial_port_data(port, NULL);
@@ -419,9 +419,8 @@ static void ipaq_write_gather(struct usb_serial_port *port)
struct ipaq_private *priv = usb_get_serial_port_data(port);
struct usb_serial *serial = port->serial;
int count, room;
- struct ipaq_packet *pkt;
+ struct ipaq_packet *pkt, *tmp;
struct urb *urb = port->write_urb;
- struct list_head *tmp;
if (urb->status == -EINPROGRESS) {
/* Should never happen */
@@ -429,9 +428,7 @@ static void ipaq_write_gather(struct usb_serial_port *port)
return;
}
room = URBDATA_SIZE;
- for (tmp = priv->queue.next; tmp != &priv->queue;) {
- pkt = list_entry(tmp, struct ipaq_packet, list);
- tmp = tmp->next;
+ list_for_each_entry_safe(pkt, tmp, &priv->queue, list) {
count = min(room, (int)(pkt->len - pkt->written));
memcpy(urb->transfer_buffer + (URBDATA_SIZE - room),
pkt->data + pkt->written, count);
@@ -503,22 +500,16 @@ static int ipaq_chars_in_buffer(struct usb_serial_port *port)
static void ipaq_destroy_lists(struct usb_serial_port *port)
{
struct ipaq_private *priv = usb_get_serial_port_data(port);
- struct list_head *tmp;
- struct ipaq_packet *pkt;
+ struct ipaq_packet *pkt, *tmp;
- for (tmp = priv->queue.next; tmp != &priv->queue;) {
- pkt = list_entry(tmp, struct ipaq_packet, list);
- tmp = tmp->next;
+ list_for_each_entry_safe(pkt, tmp, &priv->queue, list) {
kfree(pkt->data);
kfree(pkt);
}
- for (tmp = priv->freelist.next; tmp != &priv->freelist;) {
- pkt = list_entry(tmp, struct ipaq_packet, list);
- tmp = tmp->next;
+ list_for_each_entry_safe(pkt, tmp, &priv->freelist, list) {
kfree(pkt->data);
kfree(pkt);
}
- return;
}
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index cb42cc7c3224..f3a75de21d66 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -322,7 +322,7 @@ static void ir_close (struct usb_serial_port *port, struct file * filp)
dbg("%s - port %d", __FUNCTION__, port->number);
/* shutdown our bulk read */
- usb_unlink_urb (port->read_urb);
+ usb_kill_urb(port->read_urb);
}
static int ir_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index fd6c1b8388aa..47c60ea09e9f 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -291,7 +291,7 @@ static void keyspan_pda_rx_throttle (struct usb_serial_port *port)
upon the device too. */
dbg("keyspan_pda_rx_throttle port %d", port->number);
- usb_unlink_urb(port->interrupt_in_urb);
+ usb_kill_urb(port->interrupt_in_urb);
}
@@ -712,8 +712,8 @@ static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
keyspan_pda_set_modem_info(serial, 0);
/* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->interrupt_in_urb);
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->interrupt_in_urb);
}
}
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index c5207d19401a..9e60b3476775 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -336,12 +336,12 @@ static void klsi_105_shutdown (struct usb_serial *serial)
for (j = 0; j < NUM_URBS; j++) {
if (write_urbs[j]) {
/* FIXME - uncomment the following
- * usb_unlink_urb call when the host
+ * usb_kill_urb call when the host
* controllers get fixed to set
* urb->dev = NULL after the urb is
* finished. Otherwise this call
* oopses. */
- /* usb_unlink_urb(write_urbs[j]); */
+ /* usb_kill_urb(write_urbs[j]); */
if (write_urbs[j]->transfer_buffer)
kfree(write_urbs[j]->transfer_buffer);
usb_free_urb (write_urbs[j]);
@@ -467,12 +467,12 @@ static void klsi_105_close (struct usb_serial_port *port, struct file *filp)
err("Disabling read failed (error = %d)", rc);
/* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
/* unlink our write pool */
/* FIXME */
/* wgg - do I need this? I think so. */
- usb_unlink_urb (port->interrupt_in_urb);
+ usb_kill_urb(port->interrupt_in_urb);
info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out);
} /* klsi_105_close */
@@ -994,7 +994,7 @@ static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file,
static void klsi_105_throttle (struct usb_serial_port *port)
{
dbg("%s - port %d", __FUNCTION__, port->number);
- usb_unlink_urb (port->read_urb);
+ usb_kill_urb(port->read_urb);
}
static void klsi_105_unthrottle (struct usb_serial_port *port)
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index b479916ce269..33539874bd0c 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -350,14 +350,13 @@ static void kobil_close (struct usb_serial_port *port, struct file *filp)
{
dbg("%s - port %d", __FUNCTION__, port->number);
- if (port->write_urb){
- usb_unlink_urb( port->write_urb );
+ if (port->write_urb) {
+ usb_kill_urb(port->write_urb);
usb_free_urb( port->write_urb );
port->write_urb = NULL;
}
- if (port->interrupt_in_urb){
- usb_unlink_urb (port->interrupt_in_urb);
- }
+ if (port->interrupt_in_urb)
+ usb_kill_urb(port->interrupt_in_urb);
}
@@ -458,9 +457,8 @@ static int kobil_write (struct usb_serial_port *port, int from_user,
((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) {
// stop reading (except TWIN and KAAN SIM)
- if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) ) {
- usb_unlink_urb( port->interrupt_in_urb );
- }
+ if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) )
+ usb_kill_urb(port->interrupt_in_urb);
todo = priv->filled - priv->cur_pos;
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index b4961f0d2509..3ae89d03b883 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -480,9 +480,9 @@ static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
if (port->serial->dev) {
/* shutdown our urbs */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- usb_unlink_urb (port->interrupt_in_urb);
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
+ usb_kill_urb(port->interrupt_in_urb);
}
} /* mct_u232_close */
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 371aa2e8e3f1..7032d5f7c6e1 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -183,8 +183,8 @@ static void omninet_close (struct usb_serial_port *port, struct file * filp)
dbg("%s - port %d", __FUNCTION__, port->number);
wport = serial->port[1];
- usb_unlink_urb(wport->write_urb);
- usb_unlink_urb(port->read_urb);
+ usb_kill_urb(wport->write_urb);
+ usb_kill_urb(port->read_urb);
od = usb_get_serial_port_data(port);
if (od)
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index c61e56829a96..5be9c370313b 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -55,11 +55,26 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.11"
+#define DRIVER_VERSION "v0.12"
#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
static int debug;
+#define PL2303_CLOSING_WAIT (30*HZ)
+
+#define PL2303_BUF_SIZE 1024
+#define PL2303_TMP_BUF_SIZE 1024
+
+static char pl2303_tmp_buf[PL2303_TMP_BUF_SIZE];
+static DECLARE_MUTEX(pl2303_tmp_buf_sem);
+
+struct pl2303_buf {
+ unsigned int buf_size;
+ char *buf_buf;
+ char *buf_get;
+ char *buf_put;
+};
+
static struct usb_device_id id_table [] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
@@ -134,12 +149,24 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
static int pl2303_write (struct usb_serial_port *port, int from_user,
const unsigned char *buf, int count);
+static void pl2303_send (struct usb_serial_port *port);
+static int pl2303_write_room(struct usb_serial_port *port);
+static int pl2303_chars_in_buffer(struct usb_serial_port *port);
static void pl2303_break_ctl(struct usb_serial_port *port,int break_state);
static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file);
static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear);
static int pl2303_startup (struct usb_serial *serial);
static void pl2303_shutdown (struct usb_serial *serial);
+static struct pl2303_buf *pl2303_buf_alloc(unsigned int size);
+static void pl2303_buf_free(struct pl2303_buf *pb);
+static void pl2303_buf_clear(struct pl2303_buf *pb);
+static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb);
+static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb);
+static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+ unsigned int count);
+static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+ unsigned int count);
/* All of the device info needed for the PL2303 SIO serial converter */
@@ -162,6 +189,8 @@ static struct usb_serial_device_type pl2303_device = {
.read_bulk_callback = pl2303_read_bulk_callback,
.read_int_callback = pl2303_read_int_callback,
.write_bulk_callback = pl2303_write_bulk_callback,
+ .write_room = pl2303_write_room,
+ .chars_in_buffer = pl2303_chars_in_buffer,
.attach = pl2303_startup,
.shutdown = pl2303_shutdown,
};
@@ -174,6 +203,8 @@ enum pl2303_type {
struct pl2303_private {
spinlock_t lock;
+ struct pl2303_buf *buf;
+ int write_urb_in_use;
wait_queue_head_t delta_msr_wait;
u8 line_control;
u8 line_status;
@@ -201,14 +232,28 @@ static int pl2303_startup (struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL);
if (!priv)
- return -ENOMEM;
+ goto cleanup;
memset (priv, 0x00, sizeof (struct pl2303_private));
spin_lock_init(&priv->lock);
+ priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
+ if (priv->buf == NULL) {
+ kfree(priv);
+ goto cleanup;
+ }
init_waitqueue_head(&priv->delta_msr_wait);
priv->type = type;
usb_set_serial_port_data(serial->port[i], priv);
}
return 0;
+
+cleanup:
+ for (--i; i>=0; --i) {
+ priv = usb_get_serial_port_data(serial->port[i]);
+ pl2303_buf_free(priv->buf);
+ kfree(priv);
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ return -ENOMEM;
}
static int set_control_lines (struct usb_device *dev, u8 value)
@@ -224,40 +269,109 @@ static int set_control_lines (struct usb_device *dev, u8 value)
static int pl2303_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
{
- int result;
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
if (!count)
return count;
- if (port->write_urb->status == -EINPROGRESS) {
- dbg("%s - already writing", __FUNCTION__);
- return 0;
- }
-
- count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
if (from_user) {
- if (copy_from_user (port->write_urb->transfer_buffer, buf, count))
+ if (count > PL2303_TMP_BUF_SIZE)
+ count = PL2303_TMP_BUF_SIZE;
+ down(&pl2303_tmp_buf_sem);
+ if (copy_from_user(pl2303_tmp_buf, buf, count)) {
+ up(&pl2303_tmp_buf_sem);
return -EFAULT;
- } else {
- memcpy (port->write_urb->transfer_buffer, buf, count);
+ }
+ buf = pl2303_tmp_buf;
}
-
+
+ spin_lock_irqsave(&priv->lock, flags);
+ count = pl2303_buf_put(priv->buf, buf, count);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (from_user)
+ up(&pl2303_tmp_buf_sem);
+
+ pl2303_send(port);
+
+ return count;
+}
+
+static void pl2303_send(struct usb_serial_port *port)
+{
+ int count, result;
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->write_urb_in_use) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
+ port->bulk_out_size);
+
+ if (count == 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ priv->write_urb_in_use = 1;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer);
port->write_urb->transfer_buffer_length = count;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
- else
- result = count;
+ priv->write_urb_in_use = 0;
+ // TODO: reschedule pl2303_send
+ }
- return result;
+ schedule_work(&port->work);
}
+static int pl2303_write_room(struct usb_serial_port *port)
+{
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+ int room = 0;
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ room = pl2303_buf_space_avail(priv->buf);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ dbg("%s - returns %d", __FUNCTION__, room);
+ return room;
+}
+
+static int pl2303_chars_in_buffer(struct usb_serial_port *port)
+{
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+ int chars = 0;
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+ spin_lock_irqsave(&priv->lock, flags);
+ chars = pl2303_buf_data_avail(priv->buf);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ dbg("%s - returns %d", __FUNCTION__, chars);
+ return chars;
+}
static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{
@@ -422,7 +536,7 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
}
kfree (buf);
-}
+}
static int pl2303_open (struct usb_serial_port *port, struct file *filp)
{
@@ -461,7 +575,7 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp)
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0);
-
+
if (priv->type == HX) {
/* HX chip */
SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44);
@@ -504,45 +618,67 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp)
static void pl2303_close (struct usb_serial_port *port, struct file *filp)
{
- struct pl2303_private *priv;
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int c_cflag;
- int result;
+ int bps;
+ long timeout;
+ wait_queue_t wait; \
dbg("%s - port %d", __FUNCTION__, port->number);
- /* shutdown our urbs */
- dbg("%s - shutting down urbs", __FUNCTION__);
- result = usb_unlink_urb (port->write_urb);
- if (result)
- dbg("%s - usb_unlink_urb (write_urb)"
- " failed with reason: %d", __FUNCTION__,
- result);
+ /* wait for data to drain from the buffer */
+ spin_lock_irqsave(&priv->lock, flags);
+ timeout = PL2303_CLOSING_WAIT;
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&port->tty->write_wait, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (pl2303_buf_data_avail(priv->buf) == 0
+ || timeout == 0 || signal_pending(current)
+ || !usb_get_intfdata(port->serial->interface)) /* disconnect */
+ break;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ timeout = schedule_timeout(timeout);
+ spin_lock_irqsave(&priv->lock, flags);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&port->tty->write_wait, &wait);
+ /* clear out any remaining data in the buffer */
+ pl2303_buf_clear(priv->buf);
+ spin_unlock_irqrestore(&priv->lock, flags);
- result = usb_unlink_urb (port->read_urb);
- if (result)
- dbg("%s - usb_unlink_urb (read_urb) "
- "failed with reason: %d", __FUNCTION__,
- result);
+ /* wait for characters to drain from the device */
+ /* (this is long enough for the entire 256 byte */
+ /* pl2303 hardware buffer to drain with no flow */
+ /* control for data rates of 1200 bps or more, */
+ /* for lower rates we should really know how much */
+ /* data is in the buffer to compute a delay */
+ /* that is not unnecessarily long) */
+ bps = tty_get_baud_rate(port->tty);
+ if (bps > 1200)
+ timeout = max((HZ*2560)/bps,HZ/10);
+ else
+ timeout = 2*HZ;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(timeout);
- result = usb_unlink_urb (port->interrupt_in_urb);
- if (result)
- dbg("%s - usb_unlink_urb (interrupt_in_urb)"
- " failed with reason: %d", __FUNCTION__,
- result);
+ /* shutdown our urbs */
+ dbg("%s - shutting down urbs", __FUNCTION__);
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
+ usb_kill_urb(port->interrupt_in_urb);
if (port->tty) {
c_cflag = port->tty->termios->c_cflag;
if (c_cflag & HUPCL) {
/* drop DTR and RTS */
- priv = usb_get_serial_port_data(port);
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = 0;
spin_unlock_irqrestore (&priv->lock, flags);
set_control_lines (port->serial->dev, 0);
}
}
-
}
static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
@@ -672,12 +808,17 @@ static void pl2303_break_ctl (struct usb_serial_port *port, int break_state)
static void pl2303_shutdown (struct usb_serial *serial)
{
int i;
+ struct pl2303_private *priv;
dbg("%s", __FUNCTION__);
for (i = 0; i < serial->num_ports; ++i) {
- kfree (usb_get_serial_port_data(serial->port[i]));
- usb_set_serial_port_data(serial->port[i], NULL);
+ priv = usb_get_serial_port_data(serial->port[i]);
+ if (priv) {
+ pl2303_buf_free(priv->buf);
+ kfree(priv);
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
}
}
@@ -815,11 +956,23 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
int result;
dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (urb->status) {
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ priv->write_urb_in_use = 0;
+ return;
+ default:
/* error in the urb, so we have to resubmit it */
dbg("%s - Overflow in write", __FUNCTION__);
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
@@ -828,14 +981,199 @@ static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", __FUNCTION__, result);
+ else
+ return;
+ }
- return;
+ priv->write_urb_in_use = 0;
+
+ /* send any buffered data */
+ pl2303_send(port);
+}
+
+
+/*
+ * pl2303_buf_alloc
+ *
+ * Allocate a circular buffer and all associated memory.
+ */
+
+static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
+{
+
+ struct pl2303_buf *pb;
+
+
+ if (size == 0)
+ return NULL;
+
+ pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+ if (pb == NULL)
+ return NULL;
+
+ pb->buf_buf = kmalloc(size, GFP_KERNEL);
+ if (pb->buf_buf == NULL) {
+ kfree(pb);
+ return NULL;
}
- schedule_work(&port->work);
+ pb->buf_size = size;
+ pb->buf_get = pb->buf_put = pb->buf_buf;
+
+ return pb;
+
+}
+
+
+/*
+ * pl2303_buf_free
+ *
+ * Free the buffer and all associated memory.
+ */
+
+static void pl2303_buf_free(struct pl2303_buf *pb)
+{
+ if (pb != NULL) {
+ if (pb->buf_buf != NULL)
+ kfree(pb->buf_buf);
+ kfree(pb);
+ }
+}
+
+
+/*
+ * pl2303_buf_clear
+ *
+ * Clear out all data in the circular buffer.
+ */
+
+static void pl2303_buf_clear(struct pl2303_buf *pb)
+{
+ if (pb != NULL)
+ pb->buf_get = pb->buf_put;
+ /* equivalent to a get of all data available */
+}
+
+
+/*
+ * pl2303_buf_data_avail
+ *
+ * Return the number of bytes of data available in the circular
+ * buffer.
+ */
+
+static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
+{
+ if (pb != NULL)
+ return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
+ else
+ return 0;
+}
+
+
+/*
+ * pl2303_buf_space_avail
+ *
+ * Return the number of bytes of space available in the circular
+ * buffer.
+ */
+
+static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
+{
+ if (pb != NULL)
+ return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
+ else
+ return 0;
+}
+
+
+/*
+ * pl2303_buf_put
+ *
+ * Copy data data from a user buffer and put it into the circular buffer.
+ * Restrict to the amount of space available.
+ *
+ * Return the number of bytes copied.
+ */
+
+static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+ unsigned int count)
+{
+
+ unsigned int len;
+
+
+ if (pb == NULL)
+ return 0;
+
+ len = pl2303_buf_space_avail(pb);
+ if (count > len)
+ count = len;
+
+ if (count == 0)
+ return 0;
+
+ len = pb->buf_buf + pb->buf_size - pb->buf_put;
+ if (count > len) {
+ memcpy(pb->buf_put, buf, len);
+ memcpy(pb->buf_buf, buf+len, count - len);
+ pb->buf_put = pb->buf_buf + count - len;
+ } else {
+ memcpy(pb->buf_put, buf, count);
+ if (count < len)
+ pb->buf_put += count;
+ else /* count == len */
+ pb->buf_put = pb->buf_buf;
+ }
+
+ return count;
+
}
+/*
+ * pl2303_buf_get
+ *
+ * Get data from the circular buffer and copy to the given buffer.
+ * Restrict to the amount of data available.
+ *
+ * Return the number of bytes copied.
+ */
+
+static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+ unsigned int count)
+{
+
+ unsigned int len;
+
+
+ if (pb == NULL)
+ return 0;
+
+ len = pl2303_buf_data_avail(pb);
+ if (count > len)
+ count = len;
+
+ if (count == 0)
+ return 0;
+
+ len = pb->buf_buf + pb->buf_size - pb->buf_get;
+ if (count > len) {
+ memcpy(buf, pb->buf_get, len);
+ memcpy(buf+len, pb->buf_buf, count - len);
+ pb->buf_get = pb->buf_buf + count - len;
+ } else {
+ memcpy(buf, pb->buf_get, count);
+ if (count < len)
+ pb->buf_get += count;
+ else /* count == len */
+ pb->buf_get = pb->buf_buf;
+ }
+
+ return count;
+
+}
+
static int __init pl2303_init (void)
{
int retval;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 0e59c134134c..6b2aa1f6aa86 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -388,7 +388,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
good_spot = 1;
for (j = 1; j <= num_ports-1; ++j)
- if ((serial_table[i+j]) || (i+j >= SERIAL_TTY_MINORS)) {
+ if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) {
good_spot = 0;
i += j;
break;
@@ -455,15 +455,15 @@ static void destroy_serial(struct kref *kref)
if (!port)
continue;
if (port->read_urb) {
- usb_unlink_urb(port->read_urb);
+ usb_kill_urb(port->read_urb);
usb_free_urb(port->read_urb);
}
if (port->write_urb) {
- usb_unlink_urb(port->write_urb);
+ usb_kill_urb(port->write_urb);
usb_free_urb(port->write_urb);
}
if (port->interrupt_in_urb) {
- usb_unlink_urb(port->interrupt_in_urb);
+ usb_kill_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_in_urb);
}
kfree(port->bulk_in_buffer);
@@ -819,15 +819,15 @@ static void port_release(struct device *dev)
dbg ("%s - %s", __FUNCTION__, dev->bus_id);
if (port->read_urb) {
- usb_unlink_urb(port->read_urb);
+ usb_kill_urb(port->read_urb);
usb_free_urb(port->read_urb);
}
if (port->write_urb) {
- usb_unlink_urb(port->write_urb);
+ usb_kill_urb(port->write_urb);
usb_free_urb(port->write_urb);
}
if (port->interrupt_in_urb) {
- usb_unlink_urb(port->interrupt_in_urb);
+ usb_kill_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_in_urb);
}
kfree(port->bulk_in_buffer);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 8a0a75533e70..0e5d90552789 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -446,9 +446,9 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
dbg("%s - port %d", __FUNCTION__, port->number);
/* shutdown our urbs */
- usb_unlink_urb (port->read_urb);
+ usb_kill_urb(port->read_urb);
if (port->interrupt_in_urb)
- usb_unlink_urb (port->interrupt_in_urb);
+ usb_kill_urb(port->interrupt_in_urb);
/* Try to send shutdown message, if the device is gone, this will just fail. */
transfer_buffer = kmalloc (0x12, GFP_KERNEL);
@@ -655,7 +655,7 @@ exit:
static void visor_throttle (struct usb_serial_port *port)
{
dbg("%s - port %d", __FUNCTION__, port->number);
- usb_unlink_urb (port->read_urb);
+ usb_kill_urb(port->read_urb);
}
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index b27741bf5497..fc20c8324fe7 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -680,7 +680,7 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) {
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
urb = wrap->urb;
- usb_unlink_urb(urb);
+ usb_kill_urb(urb);
list_del(tmp);
list_add(tmp, &info->rx_urbs_free);
}
@@ -691,7 +691,7 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) {
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
urb = wrap->urb;
- usb_unlink_urb(urb);
+ usb_kill_urb(urb);
list_del(tmp);
list_add(tmp, &info->tx_urbs_free);
}
@@ -1344,7 +1344,7 @@ static void stop_command_port(struct usb_serial *serial)
spin_lock_irqsave(&command_info->lock, flags);
command_info->port_running--;
if (!command_info->port_running)
- usb_unlink_urb(command_port->read_urb);
+ usb_kill_urb(command_port->read_urb);
spin_unlock_irqrestore(&command_info->lock, flags);
}
@@ -1372,7 +1372,7 @@ static int start_port_read(struct usb_serial_port *port)
list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) {
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
urb = wrap->urb;
- usb_unlink_urb(urb);
+ usb_kill_urb(urb);
list_del(tmp);
list_add(tmp, &info->rx_urbs_free);
}
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index a6aa4a918d1e..b6db57596e96 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -1052,12 +1052,6 @@ static int isd200_get_inquiry_data( struct us_data *us )
/* Standard IDE interface only supports disks */
info->InquiryData.DeviceType = DIRECT_ACCESS_DEVICE;
- /* Fix-up the return data from an INQUIRY command to show
- * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
- * in Linux.
- */
- info->InquiryData.Versions = 0x2;
-
/* The length must be at least 36 (5 + 31) */
info->InquiryData.AdditionalLength = 0x1F;
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index 5141c508e3a1..2836c1735d9e 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -58,38 +58,6 @@
***********************************************************************/
/*
- * Fix-up the return data from an INQUIRY command to show
- * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
- */
-static void fix_inquiry_data(struct scsi_cmnd *srb)
-{
- unsigned char databuf[3];
- unsigned int index, offset;
-
- /* verify that it's an INQUIRY command */
- if (srb->cmnd[0] != INQUIRY)
- return;
-
- index = offset = 0;
- if (usb_stor_access_xfer_buf(databuf, sizeof(databuf), srb,
- &index, &offset, FROM_XFER_BUF) != sizeof(databuf))
- return;
-
- if ((databuf[2] & 7) == 2)
- return;
-
- US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2 - was %d\n",
- databuf[2] & 7);
-
- /* Change the SCSI revision number */
- databuf[2] = (databuf[2] & ~7) | 2;
-
- index = offset = 0;
- usb_stor_access_xfer_buf(databuf, sizeof(databuf), srb,
- &index, &offset, TO_XFER_BUF);
-}
-
-/*
* Fix-up the return data from a READ CAPACITY command. My Feiya reader
* returns a value that is 1 too large.
*/
@@ -137,10 +105,6 @@ void usb_stor_qic157_command(struct scsi_cmnd *srb, struct us_data *us)
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
- if (srb->result == SAM_STAT_GOOD) {
- /* fix the INQUIRY data if necessary */
- fix_inquiry_data(srb);
- }
}
void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us)
@@ -160,11 +124,6 @@ void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us)
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
-
- if (srb->result == SAM_STAT_GOOD) {
- /* fix the INQUIRY data if necessary */
- fix_inquiry_data(srb);
- }
}
@@ -208,11 +167,6 @@ void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us)
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
-
- if (srb->result == SAM_STAT_GOOD) {
- /* Fix the data for an INQUIRY, if necessary */
- fix_inquiry_data(srb);
- }
}
void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
@@ -222,9 +176,6 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
usb_stor_invoke_transport(srb, us);
if (srb->result == SAM_STAT_GOOD) {
- /* Fix the INQUIRY data if necessary */
- fix_inquiry_data(srb);
-
/* Fix the READ CAPACITY result if necessary */
if (us->flags & US_FL_FIX_CAPACITY)
fix_read_capacity(srb);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index c18cd06ea31c..29f4e59759e6 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -98,6 +98,23 @@ static int slave_configure(struct scsi_device *sdev)
* the end, scatter-gather buffers follow page boundaries. */
blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
+ /* Set the SCSI level to at least 2. We'll leave it at 3 if that's
+ * what is originally reported. We need this to avoid confusing
+ * the SCSI layer with devices that report 0 or 1, but need 10-byte
+ * commands (ala ATAPI devices behind certain bridges, or devices
+ * which simply have broken INQUIRY data).
+ *
+ * NOTE: This means /dev/sg programs (ala cdrecord) will get the
+ * actual information. This seems to be the preference for
+ * programs like that.
+ *
+ * NOTE: This also means that /proc/scsi/scsi and sysfs may report
+ * the actual value or the modified one, depending on where the
+ * data comes from.
+ */
+ if (sdev->scsi_level < SCSI_2)
+ sdev->scsi_level = SCSI_2;
+
/* According to the technical support people at Genesys Logic,
* devices using their chips have problems transferring more than
* 32 KB at a time. In practice people have found that 64 KB
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 4fe25f6b0432..9d0d846e19e3 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -36,13 +36,16 @@
/* If you edit this file, please try to keep it sorted first by VendorID,
* then by ProductID.
*
- * If you want to add an entry for this file, please send the following
- * to greg@kroah.com:
- * - patch that adds the entry for your device which includes your
- * email address right above the entry.
+ * If you want to add an entry for this file, be sure to include the
+ * following information:
+ * - a patch that adds the entry for your device, including your
+ * email address right above the entry (plus maybe a brief
+ * explanation of the reason for the entry),
* - a copy of /proc/bus/usb/devices with your device plugged in
* running with this patch.
- *
+ * Send your submission to either Phil Dibowitz <phil@ipom.com> or
+ * Alan Stern <stern@rowland.harvard.edu>, and don't forget to CC: the
+ * USB development list <linux-usb-devel@lists.sourceforge.net>.
*/
UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100,
@@ -68,16 +71,6 @@ UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001,
US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0),
#endif
-/* <torsten.scherer@uni-bielefeld.de>: I don't know the name of the bridge
- * manufacturer, but I've got an external USB drive by the Revoltec company
- * that needs this. otherwise the drive is recognized as /dev/sda, but any
- * access to it blocks indefinitely.
- */
-UNUSUAL_DEV( 0x0402, 0x5621, 0x0103, 0x0103,
- "Revoltec",
- "USB/IDE Bridge (ATA/ATAPI)",
- US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
-
/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
* Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
* always fails and confuses drive.
@@ -180,6 +173,16 @@ UNUSUAL_DEV( 0x04da, 0x0d05, 0x0000, 0x0000,
"CD-R/RW Drive",
US_SC_8070, US_PR_CB, NULL, 0),
+/* Reported by Adriaan Penning <a.penning@luon.net>
+ * Note that these cameras report "Medium not present" after
+ * ALLOW_MEDIUM_REMOVAL, so they also need to be marked
+ * NOT_LOCKABLE in the SCSI blacklist (and the vendor is MATSHITA). */
+UNUSUAL_DEV( 0x04da, 0x2372, 0x0000, 0x9999,
+ "Panasonic",
+ "DMC-LCx Camera",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
/* Most of the following entries were developed with the help of
* Shuttle/SCM directly.
*/
diff --git a/include/asm-i386/mach-summit/mach_mpparse.h b/include/asm-i386/mach-summit/mach_mpparse.h
index 1cce2b924a80..2b9e6d55bef1 100644
--- a/include/asm-i386/mach-summit/mach_mpparse.h
+++ b/include/asm-i386/mach-summit/mach_mpparse.h
@@ -22,6 +22,7 @@ static inline void mpc_oem_pci_bus(struct mpc_config_bus *m,
{
}
+extern int usb_early_handoff;
static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
char *productid)
{
@@ -31,6 +32,7 @@ static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
|| !strncmp(productid, "RUTHLESS SMP", 12))){
use_cyclone = 1; /*enable cyclone-timer*/
setup_summit();
+ usb_early_handoff = 1;
return 1;
}
return 0;
@@ -44,6 +46,7 @@ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
|| !strncmp(oem_table_id, "EXA", 3))){
use_cyclone = 1; /*enable cyclone-timer*/
setup_summit();
+ usb_early_handoff = 1;
return 1;
}
return 0;
diff --git a/include/linux/usb.h b/include/linux/usb.h
index a43c95a016d7..d07d5aba9e7f 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -264,7 +264,6 @@ struct usb_bus {
int bandwidth_isoc_reqs; /* number of Isoc. requests */
struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */
- struct dentry *usbdevfs_dentry; /* usbdevfs dentry entry for the bus */
struct class_device class_dev; /* class device for this bus */
void (*release)(struct usb_bus *bus); /* function to destroy this bus's memory */
@@ -315,7 +314,6 @@ struct usb_device {
struct list_head filelist;
struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */
- struct dentry *usbdevfs_dentry; /* usbdevfs dentry entry for the device */
/*
* Child devices - these can be either new devices
diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
index 78f47434b757..af49afaf7bb4 100644
--- a/include/linux/usbdevice_fs.h
+++ b/include/linux/usbdevice_fs.h
@@ -166,16 +166,6 @@ struct dev_state {
unsigned long ifclaimed;
};
-/* internal methods & data */
-extern struct usb_driver usbdevfs_driver;
-extern struct file_operations usbdevfs_drivers_fops;
-extern struct file_operations usbdevfs_devices_fops;
-extern struct file_operations usbdevfs_device_file_operations;
-extern struct inode_operations usbdevfs_device_inode_operations;
-extern struct inode_operations usbdevfs_bus_inode_operations;
-extern struct file_operations usbdevfs_bus_file_operations;
-extern void usbdevfs_conn_disc_event(void);
-
#endif /* __KERNEL__ */
/* --------------------------------------------------------------------- */