summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-03-08 17:49:06 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-03-08 17:49:06 -0800
commitabe26395fab4014299cbda53cc2615de83ea6835 (patch)
tree5f6dd08490d9c5e1754df6d90b17b2fd815e4015
parent9edf0fffb657b48ccf1c36d0a5dea61c4189f048 (diff)
parentd9795da7533d783a7bd2b9973ef864f0aa6cc7bd (diff)
Merge bk://gkernel.bkbits.net/net-drivers-2.6
into ppc970.osdl.org:/home/torvalds/v2.6/linux
-rw-r--r--CREDITS6
-rw-r--r--Documentation/arm/IXP20002
-rw-r--r--Documentation/arm/Samsung-S3C24XX/Overview.txt8
-rw-r--r--Documentation/usb/error-codes.txt28
-rw-r--r--Documentation/usb/sn9c102.txt13
-rw-r--r--MAINTAINERS20
-rw-r--r--arch/arm/common/rtctime.c2
-rw-r--r--arch/arm/common/scoop.c116
-rw-r--r--arch/arm/configs/s3c2410_defconfig1
-rw-r--r--arch/arm/mach-ixp2000/enp2611.c2
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x01.c2
-rw-r--r--arch/arm/mach-omap/Kconfig32
-rw-r--r--arch/arm/mach-omap/time.c206
-rw-r--r--arch/arm/mach-pxa/corgi.c2
-rw-r--r--arch/arm/mach-pxa/poodle.c2
-rw-r--r--arch/arm/mach-s3c2410/Kconfig8
-rw-r--r--arch/arm/mach-s3c2410/Makefile1
-rw-r--r--arch/arm/mach-s3c2410/mach-n30.c155
-rw-r--r--arch/arm/mach-sa1100/collie.c2
-rw-r--r--arch/parisc/kernel/binfmt_elf32.c1
-rw-r--r--arch/parisc/kernel/entry.S40
-rw-r--r--arch/parisc/kernel/firmware.c6
-rw-r--r--arch/parisc/kernel/hardware.c24
-rw-r--r--arch/parisc/kernel/head.S43
-rw-r--r--arch/parisc/kernel/hpmc.S36
-rw-r--r--arch/parisc/kernel/ioctl32.c2
-rw-r--r--arch/parisc/kernel/irq.c104
-rw-r--r--arch/parisc/kernel/perf.c57
-rw-r--r--arch/parisc/kernel/process.c8
-rw-r--r--arch/parisc/kernel/real2.S3
-rw-r--r--arch/parisc/kernel/setup.c6
-rw-r--r--arch/parisc/kernel/signal.c30
-rw-r--r--arch/parisc/kernel/signal32.c27
-rw-r--r--arch/parisc/kernel/signal32.h12
-rw-r--r--arch/parisc/kernel/sys_parisc.c16
-rw-r--r--arch/parisc/kernel/sys_parisc32.c70
-rw-r--r--arch/parisc/kernel/traps.c18
-rw-r--r--arch/parisc/kernel/unaligned.c4
-rw-r--r--arch/parisc/lib/checksum.c6
-rw-r--r--arch/parisc/math-emu/driver.c3
-rw-r--r--arch/parisc/mm/fault.c2
-rw-r--r--drivers/block/as-iosched.c30
-rw-r--r--drivers/block/cfq-iosched.c14
-rw-r--r--drivers/block/elevator.c28
-rw-r--r--drivers/block/ll_rw_blk.c21
-rw-r--r--drivers/bluetooth/bfusb.c8
-rw-r--r--drivers/char/watchdog/pcwd_usb.c2
-rw-r--r--drivers/ide/ide-disk.c20
-rw-r--r--drivers/media/dvb/b2c2/b2c2-usb-core.c10
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c4
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-firmware.c2
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb.h2
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c4
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c8
-rw-r--r--drivers/media/video/cpia_usb.c4
-rw-r--r--drivers/net/irda/irda-usb.c2
-rw-r--r--drivers/net/irda/stir4200.c6
-rw-r--r--drivers/parisc/eisa_eeprom.c1
-rw-r--r--drivers/parisc/gsc.c6
-rw-r--r--drivers/parisc/hppb.c1
-rw-r--r--drivers/pcmcia/pxa2xx_sharpsl.c40
-rw-r--r--drivers/scsi/scsi_lib.c2
-rw-r--r--drivers/scsi/sd.c18
-rw-r--r--drivers/serial/8250.c1
-rw-r--r--drivers/serial/8250_pci.c12
-rw-r--r--drivers/usb/Kconfig2
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/atm/speedtch.c8
-rw-r--r--drivers/usb/class/audio.c56
-rw-r--r--drivers/usb/class/cdc-acm.c88
-rw-r--r--drivers/usb/class/cdc-acm.h49
-rw-r--r--drivers/usb/class/usblp.c2
-rw-r--r--drivers/usb/core/config.c3
-rw-r--r--drivers/usb/core/devices.c25
-rw-r--r--drivers/usb/core/devio.c260
-rw-r--r--drivers/usb/core/hcd-pci.c159
-rw-r--r--drivers/usb/core/hcd.c310
-rw-r--r--drivers/usb/core/hcd.h74
-rw-r--r--drivers/usb/core/hub.c124
-rw-r--r--drivers/usb/core/hub.h1
-rw-r--r--drivers/usb/core/message.c73
-rw-r--r--drivers/usb/core/sysfs.c92
-rw-r--r--drivers/usb/core/usb.c5
-rw-r--r--drivers/usb/gadget/Kconfig8
-rw-r--r--drivers/usb/gadget/dummy_hcd.c81
-rw-r--r--drivers/usb/gadget/ether.c250
-rw-r--r--drivers/usb/gadget/gadget_chips.h6
-rw-r--r--drivers/usb/gadget/net2280.c25
-rw-r--r--drivers/usb/gadget/omap_udc.c30
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c1
-rw-r--r--drivers/usb/gadget/rndis.c2
-rw-r--r--drivers/usb/gadget/serial.c157
-rw-r--r--drivers/usb/gadget/zero.c2
-rw-r--r--drivers/usb/host/Kconfig40
-rw-r--r--drivers/usb/host/ehci-hcd.c53
-rw-r--r--drivers/usb/host/ehci-hub.c4
-rw-r--r--drivers/usb/host/ehci-q.c6
-rw-r--r--drivers/usb/host/ehci-sched.c8
-rw-r--r--drivers/usb/host/ehci.h8
-rw-r--r--drivers/usb/host/ohci-au1xxx.c136
-rw-r--r--drivers/usb/host/ohci-dbg.c4
-rw-r--r--drivers/usb/host/ohci-hcd.c47
-rw-r--r--drivers/usb/host/ohci-lh7a404.c138
-rw-r--r--drivers/usb/host/ohci-omap.c177
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c234
-rw-r--r--drivers/usb/host/ohci-pxa27x.c127
-rw-r--r--drivers/usb/host/ohci-q.c9
-rw-r--r--drivers/usb/host/ohci-sa1111.c130
-rw-r--r--drivers/usb/host/ohci.h48
-rw-r--r--drivers/usb/host/sl811-hcd.c73
-rw-r--r--drivers/usb/host/uhci-debug.c9
-rw-r--r--drivers/usb/host/uhci-hcd.c1501
-rw-r--r--drivers/usb/host/uhci-q.c1488
-rw-r--r--drivers/usb/image/mdc800.c42
-rw-r--r--drivers/usb/input/aiptek.c23
-rw-r--r--drivers/usb/input/ati_remote.c36
-rw-r--r--drivers/usb/input/hid-core.c38
-rw-r--r--drivers/usb/input/mtouchusb.c22
-rw-r--r--drivers/usb/input/powermate.c2
-rw-r--r--drivers/usb/input/touchkitusb.c19
-rw-r--r--drivers/usb/input/usbkbd.c20
-rw-r--r--drivers/usb/input/usbmouse.c19
-rw-r--r--drivers/usb/input/wacom.c2
-rw-r--r--drivers/usb/media/ibmcam.c4
-rw-r--r--drivers/usb/media/konicawc.c2
-rw-r--r--drivers/usb/media/ov511.c6
-rw-r--r--drivers/usb/media/se401.c6
-rw-r--r--drivers/usb/media/sn9c102.h8
-rw-r--r--drivers/usb/media/sn9c102_core.c52
-rw-r--r--drivers/usb/media/ultracam.c4
-rw-r--r--drivers/usb/media/vicam.c4
-rw-r--r--drivers/usb/media/w9968cf.h2
-rw-r--r--drivers/usb/misc/Kconfig2
-rw-r--r--drivers/usb/misc/Makefile2
-rw-r--r--drivers/usb/misc/auerswald.c21
-rw-r--r--drivers/usb/misc/cytherm.c2
-rw-r--r--drivers/usb/misc/idmouse.c16
-rw-r--r--drivers/usb/misc/legousbtower.c4
-rw-r--r--drivers/usb/misc/phidgetkit.c29
-rw-r--r--drivers/usb/misc/phidgetservo.c4
-rw-r--r--drivers/usb/misc/rio500.c8
-rw-r--r--drivers/usb/misc/sisusbvga/Kconfig14
-rw-r--r--drivers/usb/misc/sisusbvga/Makefile6
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c3144
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.h278
-rw-r--r--drivers/usb/misc/usblcd.c4
-rw-r--r--drivers/usb/misc/usbled.c2
-rw-r--r--drivers/usb/misc/usbtest.c10
-rw-r--r--drivers/usb/misc/uss720.c12
-rw-r--r--drivers/usb/mon/Kconfig22
-rw-r--r--drivers/usb/mon/Makefile7
-rw-r--r--drivers/usb/mon/mon_main.c377
-rw-r--r--drivers/usb/mon/mon_stat.c74
-rw-r--r--drivers/usb/mon/mon_text.c395
-rw-r--r--drivers/usb/mon/usb_mon.h51
-rw-r--r--drivers/usb/net/Kconfig21
-rw-r--r--drivers/usb/net/Makefile3
-rw-r--r--drivers/usb/net/catc.c2
-rw-r--r--drivers/usb/net/kaweth.c13
-rw-r--r--drivers/usb/net/pegasus.c61
-rw-r--r--drivers/usb/net/pegasus.h1
-rw-r--r--drivers/usb/net/rtl8150.c4
-rw-r--r--drivers/usb/net/usbnet.c589
-rw-r--r--drivers/usb/net/zd1201.c1905
-rw-r--r--drivers/usb/net/zd1201.h147
-rw-r--r--drivers/usb/serial/belkin_sa.c2
-rw-r--r--drivers/usb/serial/cyberjack.c7
-rw-r--r--drivers/usb/serial/cypress_m8.c6
-rw-r--r--drivers/usb/serial/ezusb.c2
-rw-r--r--drivers/usb/serial/ftdi_sio.c5
-rw-r--r--drivers/usb/serial/ftdi_sio.h1
-rw-r--r--drivers/usb/serial/io_edgeport.c49
-rw-r--r--drivers/usb/serial/io_ti.c7
-rw-r--r--drivers/usb/serial/ipaq.c2
-rw-r--r--drivers/usb/serial/ipw.c18
-rw-r--r--drivers/usb/serial/ir-usb.c2
-rw-r--r--drivers/usb/serial/keyspan_pda.c14
-rw-r--r--drivers/usb/serial/kl5kusb105.c2
-rw-r--r--drivers/usb/serial/mct_u232.c2
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c6
-rw-r--r--drivers/usb/serial/visor.c4
-rw-r--r--drivers/usb/serial/whiteheat.c5
-rw-r--r--drivers/usb/storage/Kconfig22
-rw-r--r--drivers/usb/storage/Makefile2
-rw-r--r--drivers/usb/storage/protocol.c39
-rw-r--r--drivers/usb/storage/scsiglue.c29
-rw-r--r--drivers/usb/storage/shuttle_usbat.c1258
-rw-r--r--drivers/usb/storage/shuttle_usbat.h82
-rw-r--r--drivers/usb/storage/transport.c28
-rw-r--r--drivers/usb/storage/transport.h4
-rw-r--r--drivers/usb/storage/unusual_devs.h82
-rw-r--r--drivers/usb/storage/usb.c48
-rw-r--r--drivers/usb/storage/usb.h6
-rw-r--r--drivers/usb/usb-skeleton.c4
-rw-r--r--drivers/video/backlight/corgi_bl.c4
-rw-r--r--drivers/w1/dscore.c10
-rw-r--r--fs/compat_ioctl.c229
-rw-r--r--include/asm-arm/arch-ixp2000/io.h2
-rw-r--r--include/asm-arm/arch-ixp2000/ixdp2x01.h2
-rw-r--r--include/asm-arm/arch-ixp2000/platform.h4
-rw-r--r--include/asm-arm/arch-pxa/corgi.h4
-rw-r--r--include/asm-arm/hardware/scoop.h10
-rw-r--r--include/asm-parisc/checksum.h4
-rw-r--r--include/asm-parisc/compat.h8
-rw-r--r--include/asm-parisc/ide.h2
-rw-r--r--include/asm-parisc/irq.h8
-rw-r--r--include/asm-parisc/numnodes.h2
-rw-r--r--include/asm-parisc/serial.h2
-rw-r--r--include/asm-parisc/signal.h7
-rw-r--r--include/linux/blkdev.h2
-rw-r--r--include/linux/compat_ioctl.h3
-rw-r--r--include/linux/elevator.h3
-rw-r--r--include/linux/pci_ids.h4
-rw-r--r--include/linux/usb.h17
-rw-r--r--include/linux/usb_cdc.h162
-rw-r--r--include/linux/usbdevice_fs.h23
-rw-r--r--sound/oss/harmony.c2
-rw-r--r--sound/parisc/harmony.c13
-rw-r--r--sound/usb/usbmixer.c4
-rw-r--r--sound/usb/usx2y/usX2Yhwdep.c2
220 files changed, 12766 insertions, 4553 deletions
diff --git a/CREDITS b/CREDITS
index 6dec36f4e90c..ad1690cbe311 100644
--- a/CREDITS
+++ b/CREDITS
@@ -841,6 +841,11 @@ E: cort@fsmlabs.com
W: http://www.fsmlabs.com/linuxppcbk.html
D: PowerPC
+N: Daniel Drake
+E: dsd@gentoo.org
+D: USBAT02 CompactFlash support in usb-storage
+S: UK
+
N: Oleg Drokin
E: green@ccssu.crimea.ua
W: http://www.ccssu.crimea.ua/~green
@@ -3427,6 +3432,7 @@ N: Jeroen Vreeken
E: pe1rxq@amsat.org
W: http://www.chello.nl/~j.vreeken/
D: SE401 usb webcam driver
+D: ZD1201 usb wireless lan driver
S: Maastrichterweg 63
S: 5554 GG Valkenswaard
S: The Netherlands
diff --git a/Documentation/arm/IXP2000 b/Documentation/arm/IXP2000
index 969f165932f2..e0148b6b2c40 100644
--- a/Documentation/arm/IXP2000
+++ b/Documentation/arm/IXP2000
@@ -45,7 +45,7 @@ MAILING LISTS REGARDING THE INTEL SDK.
4. Usage Notes
-- The IXP2000 platforms ususally have rather complex PCI bus topologies
+- The IXP2000 platforms usually have rather complex PCI bus topologies
with large memory space requirements. In addition, b/c of the way the
Intel SDK is designed, devices are enumerated in a very specific
way. B/c of this this, we use "pci=firmware" option in the kernel
diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt
index 85fbc7ca0290..10654978f06a 100644
--- a/Documentation/arm/Samsung-S3C24XX/Overview.txt
+++ b/Documentation/arm/Samsung-S3C24XX/Overview.txt
@@ -48,12 +48,15 @@ Machines
Handheld (IPAQ), available in several varieties
-
HP iPAQ rx3715
S3C2440 based IPAQ, with a number of variations depending on
features shipped.
+ Acer N30
+
+ A S3C2410 based PDA from Acer. There is a Wiki page at
+ http://handhelds.org/moin/moin.cgi/AcerN30Documentation .
NAND
----
@@ -103,7 +106,7 @@ Port Contributors
Dimitry Andric
Shannon Holland
Guillaume Gourat (NexVision)
-
+ Christer Weinigel (wingel) (Acer N30)
Document Changes
----------------
@@ -115,6 +118,7 @@ Document Changes
21 Jan 2005 - BJD - Added rx3715, added Shannon to contributors
10 Feb 2005 - BJD - Added Guillaume Gourat to contributors
02 Mar 2005 - BJD - Added SMDK2440 to list of machines
+ 06 Mar 2005 - BJD - Added Christer Weinigel
Document Author
---------------
diff --git a/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt
index 9e41284f7e75..1e36f1661cd0 100644
--- a/Documentation/usb/error-codes.txt
+++ b/Documentation/usb/error-codes.txt
@@ -23,6 +23,9 @@ USB-specific:
-ENODEV specified USB-device or bus doesn't exist
+-ENOENT specified interface or endpoint does not exist or
+ is not enabled
+
-ENXIO host controller driver does not support queuing of this type
of urb. (treat as a host controller bug.)
@@ -88,13 +91,19 @@ one or more packets could finish before an error stops further endpoint I/O.
prescribed bus turn-around time
c) unknown USB error
- In cases b) and c) either -EPROTO or -EILSEQ
- may be returned. Note that often the controller
- hardware does not distinguish among cases a),
- b), and c), so a driver cannot tell whether
- there was a protocol error, a failure to respond
- (often caused by device disconnect), or some
- other fault.
+ Note that often the controller hardware does not
+ distinguish among cases a), b), and c), so a
+ driver cannot tell whether there was a protocol
+ error, a failure to respond (often caused by
+ device disconnect), or some other fault.
+
+-ETIMEDOUT (**) No response packet received within the prescribed
+ bus turn-around time. This error may instead be
+ reported as -EPROTO or -EILSEQ.
+
+ Note that the synchronous USB message functions
+ also use this code to indicate timeout expired
+ before the transfer completed.
-EPIPE (**) Endpoint stalled. For non-control endpoints,
reset this status with usb_clear_halt().
@@ -152,4 +161,7 @@ usb_register():
usb_get_*/usb_set_*():
usb_control_msg():
usb_bulk_msg():
--ETIMEDOUT timeout expired before the transfer completed
+-ETIMEDOUT Timeout expired before the transfer completed.
+ In the future this code may change to -ETIME,
+ whose definition is a closer match to this sort
+ of error.
diff --git a/Documentation/usb/sn9c102.txt b/Documentation/usb/sn9c102.txt
index f6911442b141..cf9a1187edce 100644
--- a/Documentation/usb/sn9c102.txt
+++ b/Documentation/usb/sn9c102.txt
@@ -210,8 +210,8 @@ There are other four entries in the directory above for each registered camera:
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. Note that "i2c_reg" and "i2c_val" won't be
-created if the sensor does not actually support the standard I2C protocol or
+use is not intended for end-users. Note that "i2c_reg" and "i2c_val" will not
+be created if the sensor does not actually support the standard I2C protocol or
its registers are not 8-bit long. Also, remember that you must be logged in as
root before writing to them.
@@ -341,15 +341,8 @@ TAS5130D1B Taiwan Advanced Sensor Corporation
All the available control settings of each image sensor are supported through
the V4L2 interface.
-If you think your camera is based on the above hardware and is not actually
-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 the author reporting the kernel
-messages, so that a new entry in the list of supported devices can be added.
-
Donations of new models for further testing and support would be much
-appreciated. Non-available hardware won't be supported by the author of this
+appreciated. Non-available hardware will not be supported by the author of this
driver.
diff --git a/MAINTAINERS b/MAINTAINERS
index 759dec7ae036..3896520168c2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2055,6 +2055,12 @@ M: thomas@winischhofer.net
W: http://www.winischhofer.net/linuxsisvga.shtml
S: Maintained
+SIS USB2VGA DRIVER
+P: Thomas Winischhofer
+M: thomas@winischhofer.net
+W: http://www.winischhofer.at/linuxsisusbvga.shtml
+S: Maintained
+
SMSC47M1 HARDWARE MONITOR DRIVER
P: Jean Delvare
M: khali@linux-fr.org
@@ -2404,6 +2410,12 @@ L: linux-usb-devel@lists.sourceforge.net
W: http://www.chello.nl/~j.vreeken/se401/
S: Maintained
+USB SERIAL CYBERJACK DRIVER
+P: Matthias Bruestle and Harald Welte
+M: support@reiner-sct.com
+W: http://www.reiner-sct.de/support/treiber_cyberjack.php
+S: Maintained
+
USB SERIAL DIGI ACCELEPORT DRIVER
P: Peter Berger and Al Borchers
M: pberger@brimson.com
@@ -2505,6 +2517,14 @@ L: linux-usb-devel@lists.sourceforge.net
W: http://www.linux-projects.org
S: Maintained
+USB ZD1201 DRIVER
+P: Jeroen Vreeken
+M: pe1rxq@amsat.org
+L: linux-usb-users@lists.sourceforge.net
+L: linux-usb-devel@lists.sourceforge.net
+W: http://linux-lc100020.sourceforge.net
+S: Maintained
+
USER-MODE LINUX
P: Jeff Dike
M: jdike@karaya.com
diff --git a/arch/arm/common/rtctime.c b/arch/arm/common/rtctime.c
index edfc00af56b1..c397e71f938d 100644
--- a/arch/arm/common/rtctime.c
+++ b/arch/arm/common/rtctime.c
@@ -101,7 +101,7 @@ int rtc_valid_tm(struct rtc_time *tm)
if (tm->tm_year < 70 ||
tm->tm_mon >= 12 ||
tm->tm_mday < 1 ||
- tm->tm_mday > month_days(tm->tm_mon, yrs) ||
+ tm->tm_mday > month_days(tm->tm_mon, tm->tm_year + 1900) ||
tm->tm_hour >= 24 ||
tm->tm_min >= 60 ||
tm->tm_sec >= 60)
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c
index 811c55498280..cfd0d3e550d9 100644
--- a/arch/arm/common/scoop.c
+++ b/arch/arm/common/scoop.c
@@ -15,47 +15,52 @@
#include <asm/io.h>
#include <asm/hardware/scoop.h>
-static void __iomem *scoop_io_base;
+#define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr)))
-#define SCOOP_REG(adr) (*(volatile unsigned short*)(scoop_io_base+(adr)))
+struct scoop_dev {
+ void *base;
+ spinlock_t scoop_lock;
+ u32 scoop_gpwr;
+};
-void reset_scoop(void)
+void reset_scoop(struct device *dev)
{
- SCOOP_REG(SCOOP_MCR) = 0x0100; // 00
- SCOOP_REG(SCOOP_CDR) = 0x0000; // 04
- SCOOP_REG(SCOOP_CPR) = 0x0000; // 0C
- SCOOP_REG(SCOOP_CCR) = 0x0000; // 10
- SCOOP_REG(SCOOP_IMR) = 0x0000; // 18
- SCOOP_REG(SCOOP_IRM) = 0x00FF; // 14
- SCOOP_REG(SCOOP_ISR) = 0x0000; // 1C
- SCOOP_REG(SCOOP_IRM) = 0x0000;
+ struct scoop_dev *sdev = dev_get_drvdata(dev);
+
+ SCOOP_REG(sdev->base,SCOOP_MCR) = 0x0100; // 00
+ SCOOP_REG(sdev->base,SCOOP_CDR) = 0x0000; // 04
+ SCOOP_REG(sdev->base,SCOOP_CPR) = 0x0000; // 0C
+ SCOOP_REG(sdev->base,SCOOP_CCR) = 0x0000; // 10
+ SCOOP_REG(sdev->base,SCOOP_IMR) = 0x0000; // 18
+ SCOOP_REG(sdev->base,SCOOP_IRM) = 0x00FF; // 14
+ SCOOP_REG(sdev->base,SCOOP_ISR) = 0x0000; // 1C
+ SCOOP_REG(sdev->base,SCOOP_IRM) = 0x0000;
}
-static DEFINE_SPINLOCK(scoop_lock);
-static u32 scoop_gpwr;
-
-unsigned short set_scoop_gpio(unsigned short bit)
+unsigned short set_scoop_gpio(struct device *dev, unsigned short bit)
{
unsigned short gpio_bit;
unsigned long flag;
+ struct scoop_dev *sdev = dev_get_drvdata(dev);
- spin_lock_irqsave(&scoop_lock, flag);
- gpio_bit = SCOOP_REG(SCOOP_GPWR) | bit;
- SCOOP_REG(SCOOP_GPWR) = gpio_bit;
- spin_unlock_irqrestore(&scoop_lock, flag);
+ spin_lock_irqsave(&sdev->scoop_lock, flag);
+ gpio_bit = SCOOP_REG(sdev->base, SCOOP_GPWR) | bit;
+ SCOOP_REG(sdev->base, SCOOP_GPWR) = gpio_bit;
+ spin_unlock_irqrestore(&sdev->scoop_lock, flag);
return gpio_bit;
}
-unsigned short reset_scoop_gpio(unsigned short bit)
+unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit)
{
unsigned short gpio_bit;
unsigned long flag;
+ struct scoop_dev *sdev = dev_get_drvdata(dev);
- spin_lock_irqsave(&scoop_lock, flag);
- gpio_bit = SCOOP_REG(SCOOP_GPWR) & ~bit;
- SCOOP_REG(SCOOP_GPWR) = gpio_bit;
- spin_unlock_irqrestore(&scoop_lock, flag);
+ spin_lock_irqsave(&sdev->scoop_lock, flag);
+ gpio_bit = SCOOP_REG(sdev->base, SCOOP_GPWR) & ~bit;
+ SCOOP_REG(sdev->base,SCOOP_GPWR) = gpio_bit;
+ spin_unlock_irqrestore(&sdev->scoop_lock, flag);
return gpio_bit;
}
@@ -63,25 +68,30 @@ unsigned short reset_scoop_gpio(unsigned short bit)
EXPORT_SYMBOL(set_scoop_gpio);
EXPORT_SYMBOL(reset_scoop_gpio);
-unsigned short read_scoop_reg(unsigned short reg)
+unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
{
- return SCOOP_REG(reg);
+ struct scoop_dev *sdev = dev_get_drvdata(dev);
+ return SCOOP_REG(sdev->base,reg);
}
-void write_scoop_reg(unsigned short reg, unsigned short data)
+void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
{
- SCOOP_REG(reg)=data;
+ struct scoop_dev *sdev = dev_get_drvdata(dev);
+ SCOOP_REG(sdev->base,reg)=data;
}
EXPORT_SYMBOL(reset_scoop);
EXPORT_SYMBOL(read_scoop_reg);
EXPORT_SYMBOL(write_scoop_reg);
+#ifdef CONFIG_PM
static int scoop_suspend(struct device *dev, uint32_t state, uint32_t level)
{
if (level == SUSPEND_POWER_DOWN) {
- scoop_gpwr = SCOOP_REG(SCOOP_GPWR);
- SCOOP_REG(SCOOP_GPWR) = 0;
+ struct scoop_dev *sdev = dev_get_drvdata(dev);
+
+ sdev->scoop_gpwr = SCOOP_REG(sdev->base,SCOOP_GPWR);
+ SCOOP_REG(sdev->base,SCOOP_GPWR) = 0;
}
return 0;
}
@@ -89,13 +99,20 @@ static int scoop_suspend(struct device *dev, uint32_t state, uint32_t level)
static int scoop_resume(struct device *dev, uint32_t level)
{
if (level == RESUME_POWER_ON) {
- SCOOP_REG(SCOOP_GPWR) = scoop_gpwr;
+ struct scoop_dev *sdev = dev_get_drvdata(dev);
+
+ SCOOP_REG(sdev->base,SCOOP_GPWR) = sdev->scoop_gpwr;
}
return 0;
}
+#else
+#define scoop_suspend NULL
+#define scoop_resume NULL
+#endif
int __init scoop_probe(struct device *dev)
{
+ struct scoop_dev *devptr;
struct scoop_config *inf;
struct platform_device *pdev = to_platform_device(dev);
struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -103,25 +120,50 @@ int __init scoop_probe(struct device *dev)
if (!mem)
return -EINVAL;
+ devptr = kmalloc(sizeof(struct scoop_dev), GFP_KERNEL);
+
+ if (!devptr)
+ return -ENOMEM;
+
+ memset(devptr, 0, sizeof(struct scoop_dev));
+ spin_lock_init(&devptr->scoop_lock);
+
inf = dev->platform_data;
- scoop_io_base = ioremap(mem->start, 0x1000);
- if (!scoop_io_base)
+ devptr->base = ioremap(mem->start, mem->end - mem->start + 1);
+
+ if (!devptr->base) {
+ kfree(devptr);
return -ENOMEM;
+ }
- SCOOP_REG(SCOOP_MCR) = 0x0140;
+ dev_set_drvdata(dev, devptr);
- reset_scoop();
+ printk("Sharp Scoop Device found at 0x%08x -> 0x%08x\n",(unsigned int)mem->start,(unsigned int)devptr->base);
- SCOOP_REG(SCOOP_GPCR) = inf->io_dir & 0xffff;
- SCOOP_REG(SCOOP_GPWR) = inf->io_out & 0xffff;
+ SCOOP_REG(devptr->base, SCOOP_MCR) = 0x0140;
+ reset_scoop(dev);
+ SCOOP_REG(devptr->base, SCOOP_GPCR) = inf->io_dir & 0xffff;
+ SCOOP_REG(devptr->base, SCOOP_GPWR) = inf->io_out & 0xffff;
return 0;
}
+static int scoop_remove(struct device *dev)
+{
+ struct scoop_dev *sdev = dev_get_drvdata(dev);
+ if (sdev) {
+ iounmap(sdev->base);
+ kfree(sdev);
+ dev_set_drvdata(dev, NULL);
+ }
+ return 0;
+}
+
static struct device_driver scoop_driver = {
.name = "sharp-scoop",
.bus = &platform_bus_type,
.probe = scoop_probe,
+ .remove = scoop_remove,
.suspend = scoop_suspend,
.resume = scoop_resume,
};
diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig
index e98bbb53586b..b21333f00f53 100644
--- a/arch/arm/configs/s3c2410_defconfig
+++ b/arch/arm/configs/s3c2410_defconfig
@@ -86,6 +86,7 @@ CONFIG_ARCH_S3C2410=y
#
CONFIG_ARCH_BAST=y
CONFIG_ARCH_H1940=y
+CONFIG_MACH_N30=y
CONFIG_ARCH_SMDK2410=y
CONFIG_ARCH_S3C2440=y
CONFIG_MACH_VR1000=y
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
index e4d2992d9427..b51b9a58eecf 100644
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -6,7 +6,7 @@
* Created 2004 by Lennert Buytenhek from the ixdp2x01 code. The
* original version carries the following notices:
*
- * Original Author: Andrzej Mialwoski <andrzej.mialwoski@intel.com>
+ * Original Author: Andrzej Mialkowski <andrzej.mialkowski@intel.com>
* Maintainer: Deepak Saxena <dsaxena@plexity.net>
*
* Copyright (C) 2002-2003 Intel Corp.
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index 0e919bbf9d92..e94dace3d412 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -3,7 +3,7 @@
*
* Code common to Intel IXDP2401 and IXDP2801 platforms
*
- * Original Author: Andrzej Mialwoski <andrzej.mialwoski@intel.com>
+ * Original Author: Andrzej Mialkowski <andrzej.mialkowski@intel.com>
* Maintainer: Deepak Saxena <dsaxena@plexity.net>
*
* Copyright (C) 2002-2003 Intel Corp.
diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
index f8d265d7088d..a53cac9080c6 100644
--- a/arch/arm/mach-omap/Kconfig
+++ b/arch/arm/mach-omap/Kconfig
@@ -113,6 +113,38 @@ config OMAP_MUX_WARNINGS
printed, it's safe to deselect OMAP_MUX for your product.
choice
+ prompt "System timer"
+ default OMAP_MPU_TIMER
+
+config OMAP_MPU_TIMER
+ bool "Use mpu timer"
+ help
+ Select this option if you want to use the OMAP mpu timer. This
+ timer provides more intra-tick resolution than the 32KHz timer,
+ but consumes more power.
+
+config OMAP_32K_TIMER
+ bool "Use 32KHz timer"
+ depends on ARCH_OMAP16XX
+ help
+ Select this option if you want to enable the OMAP 32KHz timer.
+ This timer saves power compared to the OMAP_MPU_TIMER, and has
+ support for no tick during idle. The 32KHz timer provides less
+ intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
+ currently only available for OMAP-16xx.
+
+endchoice
+
+config OMAP_32K_TIMER_HZ
+ int "Kernel internal timer frequency for 32KHz timer"
+ range 32 1024
+ depends on OMAP_32K_TIMER
+ default "128"
+ help
+ Kernel internal timer frequency should be a divisor of 32768,
+ such as 64 or 128.
+
+choice
prompt "Low-level debug console UART"
depends on ARCH_OMAP
default OMAP_LL_DEBUG_UART1
diff --git a/arch/arm/mach-omap/time.c b/arch/arm/mach-omap/time.c
index f673eeedd1d9..4205fdcb632c 100644
--- a/arch/arm/mach-omap/time.c
+++ b/arch/arm/mach-omap/time.c
@@ -51,6 +51,8 @@
struct sys_timer omap_timer;
+#ifdef CONFIG_OMAP_MPU_TIMER
+
/*
* ---------------------------------------------------------------------------
* MPU timer
@@ -67,6 +69,36 @@ struct sys_timer omap_timer;
#define MPU_TIMER_AR (1 << 1)
#define MPU_TIMER_ST (1 << 0)
+/* cycles to nsec conversions taken from arch/i386/kernel/timers/timer_tsc.c,
+ * converted to use kHz by Kevin Hilman */
+/* convert from cycles(64bits) => nanoseconds (64bits)
+ * basic equation:
+ * ns = cycles / (freq / ns_per_sec)
+ * ns = cycles * (ns_per_sec / freq)
+ * ns = cycles * (10^9 / (cpu_khz * 10^3))
+ * ns = cycles * (10^6 / cpu_khz)
+ *
+ * Then we use scaling math (suggested by george at mvista.com) to get:
+ * ns = cycles * (10^6 * SC / cpu_khz / SC
+ * ns = cycles * cyc2ns_scale / SC
+ *
+ * And since SC is a constant power of two, we can convert the div
+ * into a shift.
+ * -johnstul at us.ibm.com "math is hard, lets go shopping!"
+ */
+static unsigned long cyc2ns_scale;
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+
+static inline void set_cyc2ns_scale(unsigned long cpu_khz)
+{
+ cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
+}
+
+static inline unsigned long long cycles_2_ns(unsigned long long cyc)
+{
+ return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
+}
+
/*
* MPU_TICKS_PER_SEC must be an even number, otherwise machinecycles_to_usecs
* will break. On P2, the timer count rate is 6.5 MHz after programming PTV
@@ -112,8 +144,10 @@ static inline void omap_mpu_timer_start(int nr, unsigned long load_val)
unsigned long omap_mpu_timer_ticks_to_usecs(unsigned long nr_ticks)
{
- /* Round up to nearest usec */
- return ((nr_ticks * 1000) / (MPU_TICKS_PER_SEC / 2 / 1000) + 1) >> 1;
+ unsigned long long nsec;
+
+ nsec = cycles_2_ns((unsigned long long)nr_ticks);
+ return (unsigned long)nsec / 1000;
}
/*
@@ -158,22 +192,190 @@ static struct irqaction omap_mpu_timer_irq = {
.handler = omap_mpu_timer_interrupt
};
+static unsigned long omap_mpu_timer1_overflows;
+static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ omap_mpu_timer1_overflows++;
+ return IRQ_HANDLED;
+}
+
+static struct irqaction omap_mpu_timer1_irq = {
+ .name = "mpu timer1 overflow",
+ .flags = SA_INTERRUPT,
+ .handler = omap_mpu_timer1_interrupt
+};
+
static __init void omap_init_mpu_timer(void)
{
+ set_cyc2ns_scale(MPU_TICKS_PER_SEC / 1000);
omap_timer.offset = omap_mpu_timer_gettimeoffset;
+ setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
setup_irq(INT_TIMER2, &omap_mpu_timer_irq);
omap_mpu_timer_start(0, 0xffffffff);
omap_mpu_timer_start(1, MPU_TIMER_TICK_PERIOD);
}
/*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+ unsigned long ticks = 0 - omap_mpu_timer_read(0);
+ unsigned long long ticks64;
+
+ ticks64 = omap_mpu_timer1_overflows;
+ ticks64 <<= 32;
+ ticks64 |= ticks;
+
+ return cycles_2_ns(ticks64);
+}
+#endif /* CONFIG_OMAP_MPU_TIMER */
+
+#ifdef CONFIG_OMAP_32K_TIMER
+
+#ifdef CONFIG_ARCH_OMAP1510
+#error OMAP 32KHz timer does not currently work on 1510!
+#endif
+
+/*
+ * ---------------------------------------------------------------------------
+ * 32KHz OS timer
+ *
+ * This currently works only on 16xx, as 1510 does not have the continuous
+ * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track
+ * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer
+ * on 1510 would be possible, but the timer would not be as accurate as
+ * with the 32KHz synchronized timer.
+ * ---------------------------------------------------------------------------
+ */
+#define OMAP_32K_TIMER_BASE 0xfffb9000
+#define OMAP_32K_TIMER_CR 0x08
+#define OMAP_32K_TIMER_TVR 0x00
+#define OMAP_32K_TIMER_TCR 0x04
+
+#define OMAP_32K_TICKS_PER_HZ (32768 / HZ)
+
+/*
+ * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
+ * so with HZ = 100, TVR = 327.68.
+ */
+#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1)
+#define MAX_SKIP_JIFFIES 25
+#define TIMER_32K_SYNCHRONIZED 0xfffbc410
+
+#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \
+ (((nr_jiffies) * (clock_rate)) / HZ)
+
+static inline void omap_32k_timer_write(int val, int reg)
+{
+ omap_writew(val, reg + OMAP_32K_TIMER_BASE);
+}
+
+static inline unsigned long omap_32k_timer_read(int reg)
+{
+ return omap_readl(reg + OMAP_32K_TIMER_BASE) & 0xffffff;
+}
+
+/*
+ * The 32KHz synchronized timer is an additional timer on 16xx.
+ * It is always running.
+ */
+static inline unsigned long omap_32k_sync_timer_read(void)
+{
+ return omap_readl(TIMER_32K_SYNCHRONIZED);
+}
+
+static inline void omap_32k_timer_start(unsigned long load_val)
+{
+ omap_32k_timer_write(load_val, OMAP_32K_TIMER_TVR);
+ omap_32k_timer_write(0x0f, OMAP_32K_TIMER_CR);
+}
+
+static inline void omap_32k_timer_stop(void)
+{
+ omap_32k_timer_write(0x0, OMAP_32K_TIMER_CR);
+}
+
+/*
+ * Rounds down to nearest usec
+ */
+static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k)
+{
+ return (ticks_32k * 5*5*5*5*5*5) >> 9;
+}
+
+static unsigned long omap_32k_last_tick = 0;
+
+/*
+ * Returns elapsed usecs since last 32k timer interrupt
+ */
+static unsigned long omap_32k_timer_gettimeoffset(void)
+{
+ unsigned long now = omap_32k_sync_timer_read();
+ return omap_32k_ticks_to_usecs(now - omap_32k_last_tick);
+}
+
+/*
+ * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this
+ * function is also called from other interrupts to remove latency
+ * issues with dynamic tick. In the dynamic tick case, we need to lock
+ * with irqsave.
+ */
+static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ unsigned long flags;
+ unsigned long now;
+
+ write_seqlock_irqsave(&xtime_lock, flags);
+ now = omap_32k_sync_timer_read();
+
+ while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) {
+ omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
+ timer_tick(regs);
+ }
+
+ /* Restart timer so we don't drift off due to modulo or dynamic tick.
+ * By default we program the next timer to be continuous to avoid
+ * latencies during high system load. During dynamic tick operation the
+ * continuous timer can be overridden from pm_idle to be longer.
+ */
+ omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction omap_32k_timer_irq = {
+ .name = "32KHz timer",
+ .flags = SA_INTERRUPT,
+ .handler = omap_32k_timer_interrupt
+};
+
+static __init void omap_init_32k_timer(void)
+{
+ setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
+ omap_timer.offset = omap_32k_timer_gettimeoffset;
+ omap_32k_last_tick = omap_32k_sync_timer_read();
+ omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+}
+#endif /* CONFIG_OMAP_32K_TIMER */
+
+/*
* ---------------------------------------------------------------------------
* Timer initialization
* ---------------------------------------------------------------------------
*/
void __init omap_timer_init(void)
{
+#if defined(CONFIG_OMAP_MPU_TIMER)
omap_init_mpu_timer();
+#elif defined(CONFIG_OMAP_32K_TIMER)
+ omap_init_32k_timer();
+#else
+#error No system timer selected in Kconfig!
+#endif
}
struct sys_timer omap_timer = {
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index 5260436cdb3b..94841068a688 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -59,7 +59,7 @@ static struct scoop_config corgi_scoop_setup = {
.io_out = CORGI_SCOOP_IO_OUT,
};
-static struct platform_device corgiscoop_device = {
+struct platform_device corgiscoop_device = {
.name = "sharp-scoop",
.id = -1,
.dev = {
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index d49bc5814022..5ee67808224a 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -51,7 +51,7 @@ static struct scoop_config poodle_scoop_setup = {
.io_out = POODLE_SCOOP_IO_OUT,
};
-static struct platform_device poodle_scoop_device = {
+struct platform_device poodle_scoop_device = {
.name = "sharp-scoop",
.id = -1,
.dev = {
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 2433edd219fd..cc5eeb7e7fc3 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -19,6 +19,14 @@ config ARCH_H1940
<http://www.handhelds.org/projects/h1940.html>.
+config MACH_N30
+ bool "Acer N30"
+ select CPU_S3C2410
+ help
+ Say Y here if you are using the Acer N30
+
+ <http://zoo.weinigel.se/n30>.
+
config ARCH_SMDK2410
bool "SMDK2410/A9M2410"
select CPU_S3C2410
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index a895baff9fde..1d00d29f0dc5 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o
obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
obj-$(CONFIG_ARCH_H1940) += mach-h1940.o
+obj-$(CONFIG_MACH_N30) += mach-n30.o
obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o
obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o
obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
new file mode 100644
index 000000000000..044c8d9e04a0
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -0,0 +1,155 @@
+/* linux/arch/arm/mach-s3c2410/mach-n30.c
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Copyright (c) 2005 Christer Weinigel <christer@weinigel.se>
+ *
+ * There is a wiki with more information about the n30 port at
+ * http://handhelds.org/moin/moin.cgi/AcerN30Documentation .
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/iomd.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/iic.h>
+
+#include <linux/serial_core.h>
+
+#include "s3c2410.h"
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+
+static struct map_desc n30_iodesc[] __initdata = {
+ /* nothing here yet */
+};
+
+static struct s3c2410_uartcfg n30_uartcfgs[] = {
+ /* Normal serial port */
+ [0] = {
+ .hwport = 0,
+ .flags = 0,
+ .ucon = 0x2c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ },
+ /* IR port */
+ [1] = {
+ .hwport = 1,
+ .flags = 0,
+ .uart_flags = UPF_CONS_FLOW,
+ .ucon = 0x2c5,
+ .ulcon = 0x43,
+ .ufcon = 0x51,
+ },
+ /* The BlueTooth controller is connected to port 2 */
+ [2] = {
+ .hwport = 2,
+ .flags = 0,
+ .ucon = 0x2c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ },
+};
+
+static struct platform_device *n30_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_lcd,
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+ &s3c_device_iis,
+ &s3c_device_usbgadget,
+};
+
+static struct s3c2410_platform_i2c n30_i2ccfg = {
+ .flags = 0,
+ .slave_addr = 0x10,
+ .bus_freq = 10*1000,
+ .max_freq = 10*1000,
+};
+
+static struct s3c24xx_board n30_board __initdata = {
+ .devices = n30_devices,
+ .devices_count = ARRAY_SIZE(n30_devices)
+};
+
+void __init n30_map_io(void)
+{
+ s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc));
+ s3c24xx_init_clocks(0);
+ s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs));
+ s3c24xx_set_board(&n30_board);
+}
+
+void __init n30_init_irq(void)
+{
+ s3c24xx_init_irq();
+}
+
+
+static int n30_usbstart_thread(void *unused)
+{
+ /* Turn off suspend on both USB ports, and switch the
+ * selectable USB port to USB device mode. */
+ writel(readl(S3C2410_MISCCR) & ~0x00003008, S3C2410_MISCCR);
+
+ /* Turn off the D+ pull up for 3 seconds so that the USB host
+ * at the other end will do a rescan of the USB bus. */
+ s3c2410_gpio_setpin(S3C2410_GPB3, 0);
+
+ msleep_interruptible(3*HZ);
+
+ s3c2410_gpio_setpin(S3C2410_GPB3, 1);
+
+ return 0;
+}
+
+
+void __init n30_init(void)
+{
+ s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
+
+ kthread_run(n30_usbstart_thread, NULL, "n30_usbstart");
+}
+
+MACHINE_START(N30, "Acer-N30")
+ MAINTAINER("Christer Weinigel <christer@weinigel.se>, Ben Dooks <ben-linux@fluff.org>")
+ BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART)
+ BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
+
+ .timer = &s3c24xx_timer,
+ .init_machine = n30_init,
+ .init_irq = n30_init_irq,
+ .map_io = n30_map_io,
+MACHINE_END
+
+/*
+ Local variables:
+ compile-command: "make ARCH=arm CROSS_COMPILE=/usr/local/arm/3.3.2/bin/arm-linux- -k -C ../../.."
+ c-basic-offset: 8
+ End:
+*/
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index 2bc071a7b7f3..da9412c5d385 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -55,7 +55,7 @@ static struct scoop_config collie_scoop_setup = {
.io_out = COLLIE_SCOOP_IO_OUT,
};
-static struct platform_device colliescoop_device = {
+struct platform_device colliescoop_device = {
.name = "sharp-scoop",
.id = -1,
.dev = {
diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c
index 6fd07e90aad7..d1833f164bbe 100644
--- a/arch/parisc/kernel/binfmt_elf32.c
+++ b/arch/parisc/kernel/binfmt_elf32.c
@@ -37,7 +37,6 @@ typedef unsigned int elf_greg_t;
#include <linux/spinlock.h>
#include <asm/processor.h>
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/elfcore.h>
#include <linux/compat.h> /* struct compat_timeval */
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index b1dd08b03552..ee58d37dbb27 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -76,13 +76,11 @@
mtsp %r0, %sr5
mtsp %r0, %sr6
mtsp %r0, %sr7
- ldil L%KERNEL_PSW, %r1
- ldo R%KERNEL_PSW(%r1), %r1
+ load32 KERNEL_PSW, %r1
mtctl %r1, %cr22
mtctl %r0, %cr17 /* Clear IIASQ tail */
mtctl %r0, %cr17 /* Clear IIASQ head */
- ldil L%4f, %r1
- ldo R%4f(%r1), %r1
+ load32 4f, %r1
mtctl %r1, %cr18 /* Set IIAOQ tail */
ldo 4(%r1), %r1
mtctl %r1, %cr18 /* Set IIAOQ head */
@@ -197,8 +195,7 @@
/* HPMC handler */
.macro hpmc code
nop /* must be a NOP, will be patched later */
- ldil L%PA(os_hpmc), %r3
- ldo R%PA(os_hpmc)(%r3), %r3
+ load32 PA(os_hpmc), %r3
bv,n 0(%r3)
nop
.word 0 /* checksum (will be patched) */
@@ -860,8 +857,7 @@ _switch_to:
callee_save
- ldil L%_switch_to_ret, %r2
- ldo R%_switch_to_ret(%r2), %r2
+ load32 _switch_to_ret, %r2
STREG %r2, TASK_PT_KPC(%r26)
LDREG TASK_PT_KPC(%r25), %r2
@@ -914,16 +910,13 @@ syscall_exit_rfi:
depi 3,31,2,%r19
STREG %r19,PT_IAOQ1(%r16)
LDREG PT_PSW(%r16),%r19
- ldil L%USER_PSW_MASK,%r1
- ldo R%USER_PSW_MASK(%r1),%r1
+ load32 USER_PSW_MASK,%r1
#ifdef __LP64__
- ldil L%USER_PSW_HI_MASK,%r20
- ldo R%USER_PSW_HI_MASK(%r20),%r20
+ load32 USER_PSW_HI_MASK,%r20
depd %r20,31,32,%r1
#endif
and %r19,%r1,%r19 /* Mask out bits that user shouldn't play with */
- ldil L%USER_PSW,%r1
- ldo R%USER_PSW(%r1),%r1
+ load32 USER_PSW,%r1
or %r19,%r1,%r19 /* Make sure default USER_PSW bits are set */
STREG %r19,PT_PSW(%r16)
@@ -955,8 +948,7 @@ intr_return:
.import irq_stat,data
- ldil L%irq_stat,%r19
- ldo R%irq_stat(%r19),%r19
+ load32 irq_stat,%r19
#ifdef CONFIG_SMP
mfctl %cr30,%r1
ldw TI_CPU(%r1),%r1 /* get cpu # - int */
@@ -1079,7 +1071,7 @@ intr_do_signal:
BL do_signal,%r2
copy %r0, %r26 /* sigset_t *oldset = NULL */
- b intr_restore
+ b intr_check_sig
nop
/*
@@ -1607,8 +1599,7 @@ dbit_trap_20w:
#ifdef CONFIG_SMP
CMPIB=,n 0,spc,dbit_nolock_20w
- ldil L%PA(pa_dbit_lock),t0
- ldo R%PA(pa_dbit_lock)(t0),t0
+ load32 PA(pa_dbit_lock),t0
dbit_spin_20w:
ldcw 0(t0),t1
@@ -1644,8 +1635,7 @@ dbit_trap_11:
#ifdef CONFIG_SMP
CMPIB=,n 0,spc,dbit_nolock_11
- ldil L%PA(pa_dbit_lock),t0
- ldo R%PA(pa_dbit_lock)(t0),t0
+ load32 PA(pa_dbit_lock),t0
dbit_spin_11:
ldcw 0(t0),t1
@@ -1685,8 +1675,7 @@ dbit_trap_20:
#ifdef CONFIG_SMP
CMPIB=,n 0,spc,dbit_nolock_20
- ldil L%PA(pa_dbit_lock),t0
- ldo R%PA(pa_dbit_lock)(t0),t0
+ load32 PA(pa_dbit_lock),t0
dbit_spin_20:
ldcw 0(t0),t1
@@ -2082,8 +2071,7 @@ syscall_check_bh:
.import irq_stat,data
- ldil L%irq_stat,%r19
- ldo R%irq_stat(%r19),%r19
+ load32 irq_stat,%r19
#ifdef CONFIG_SMP
/* sched.h: int processor */
@@ -2282,7 +2270,7 @@ syscall_do_signal:
ldo TASK_REGS(%r1), %r20 /* reload pt_regs */
reg_restore %r20
- b,n syscall_restore
+ b,n syscall_check_sig
/*
* get_register is used by the non access tlb miss handlers to
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
index e8b722d25aaf..a836945c8b7d 100644
--- a/arch/parisc/kernel/firmware.c
+++ b/arch/parisc/kernel/firmware.c
@@ -120,10 +120,10 @@ static unsigned long f_extend(unsigned long address)
#ifdef __LP64__
if(unlikely(parisc_narrow_firmware)) {
if((address & 0xff000000) == 0xf0000000)
- return 0xf0f0f0f000000000 | (u32)address;
+ return 0xf0f0f0f000000000UL | (u32)address;
if((address & 0xf0000000) == 0xf0000000)
- return 0xffffffff00000000 | (u32)address;
+ return 0xffffffff00000000UL | (u32)address;
}
#endif
return address;
@@ -912,7 +912,7 @@ int pdc_do_firm_test_reset(unsigned long ftc_bitmap)
*
* Reset the system.
*/
-int pdc_do_reset()
+int pdc_do_reset(void)
{
int retval;
diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c
index 4abd43910db6..2071b5bba15c 100644
--- a/arch/parisc/kernel/hardware.c
+++ b/arch/parisc/kernel/hardware.c
@@ -1296,18 +1296,18 @@ static struct hp_cpu_type_mask {
};
char *cpu_name_version[][2] = {
- [pcx] { "PA7000 (PCX)", "1.0" },
- [pcxs] { "PA7000 (PCX-S)", "1.1a" },
- [pcxt] { "PA7100 (PCX-T)", "1.1b" },
- [pcxt_] { "PA7200 (PCX-T')", "1.1c" },
- [pcxl] { "PA7100LC (PCX-L)", "1.1d" },
- [pcxl2] { "PA7300LC (PCX-L2)", "1.1e" },
- [pcxu] { "PA8000 (PCX-U)", "2.0" },
- [pcxu_] { "PA8200 (PCX-U+)", "2.0" },
- [pcxw] { "PA8500 (PCX-W)", "2.0" },
- [pcxw_] { "PA8600 (PCX-W+)", "2.0" },
- [pcxw2] { "PA8700 (PCX-W2)", "2.0" },
- [mako] { "PA8800 (Mako)", "2.0" }
+ [pcx] = { "PA7000 (PCX)", "1.0" },
+ [pcxs] = { "PA7000 (PCX-S)", "1.1a" },
+ [pcxt] = { "PA7100 (PCX-T)", "1.1b" },
+ [pcxt_] = { "PA7200 (PCX-T')", "1.1c" },
+ [pcxl] = { "PA7100LC (PCX-L)", "1.1d" },
+ [pcxl2] = { "PA7300LC (PCX-L2)", "1.1e" },
+ [pcxu] = { "PA8000 (PCX-U)", "2.0" },
+ [pcxu_] = { "PA8200 (PCX-U+)", "2.0" },
+ [pcxw] = { "PA8500 (PCX-W)", "2.0" },
+ [pcxw_] = { "PA8600 (PCX-W+)", "2.0" },
+ [pcxw2] = { "PA8700 (PCX-W2)", "2.0" },
+ [mako] = { "PA8800 (Mako)", "2.0" }
};
const char * __init
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
index 1fb4c05c3553..ddf7e914f15e 100644
--- a/arch/parisc/kernel/head.S
+++ b/arch/parisc/kernel/head.S
@@ -71,47 +71,42 @@ $bss_loop:
stw,ma %arg2,4(%r1)
stw,ma %arg3,4(%r1)
- /* Initialize startup VM. Just map first 8 MB of memory */
- load32 PA(pg0),%r1
-
-#ifdef __LP64__
- load32 PA(pmd0),%r5
- shrd %r5,PxD_VALUE_SHIFT,%r3
-#else
- shr %r1,PxD_VALUE_SHIFT,%r3
-#endif
- ldo (PxD_FLAG_PRESENT+PxD_FLAG_VALID)(%r3),%r3
-
+ /* Initialize startup VM. Just map first 8/16 MB of memory */
load32 PA(swapper_pg_dir),%r4
mtctl %r4,%cr24 /* Initialize kernel root pointer */
mtctl %r4,%cr25 /* Initialize user root pointer */
#ifdef __LP64__
+ /* Set pmd in pgd */
+ load32 PA(pmd0),%r5
+ shrd %r5,PxD_VALUE_SHIFT,%r3
+ ldo (PxD_FLAG_PRESENT+PxD_FLAG_VALID)(%r3),%r3
stw %r3,ASM_PGD_ENTRY*ASM_PGD_ENTRY_SIZE(%r4)
- shrd %r1,PxD_VALUE_SHIFT,%r3
- ldo (PxD_FLAG_PRESENT+PxD_FLAG_VALID)(%r3),%r3
- ldo ASM_PMD_ENTRY*ASM_PMD_ENTRY_SIZE(%r5),%r5
+ ldo ASM_PMD_ENTRY*ASM_PMD_ENTRY_SIZE(%r5),%r4
#else
+ /* 2-level page table, so pmd == pgd */
ldo ASM_PGD_ENTRY*ASM_PGD_ENTRY_SIZE(%r4),%r4
#endif
+
+ /* Fill in pmd with enough pte directories */
+ load32 PA(pg0),%r1
+ SHRREG %r1,PxD_VALUE_SHIFT,%r3
+ ldo (PxD_FLAG_PRESENT+PxD_FLAG_VALID)(%r3),%r3
+
ldi ASM_PT_INITIAL,%r1
1:
-#ifdef __LP64__
- stw %r3,0(%r5)
-#else
- stw %r3,0(%r4)
-#endif
-
+ stw %r3,0(%r4)
ldo (ASM_PAGE_SIZE >> PxD_VALUE_SHIFT)(%r3),%r3
addib,> -1,%r1,1b
-
#ifdef __LP64__
- ldo ASM_PMD_ENTRY_SIZE(%r5),%r5
+ ldo ASM_PMD_ENTRY_SIZE(%r4),%r4
#else
- ldo ASM_PGD_ENTRY_SIZE(%r4),%r4
+ ldo ASM_PGD_ENTRY_SIZE(%r4),%r4
#endif
+
+ /* Now initialize the PTEs themselves */
ldo _PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */
load32 PA(pg0),%r1
@@ -306,7 +301,7 @@ $rfi:
mtctl %r11,%cr18 /* IIAOQ head */
ldo 4(%r11),%r11
mtctl %r11,%cr18 /* IIAOQ tail */
-
+
/* Jump to hyperspace */
rfi
nop
diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S
index eeb39506c96e..c412c0adc4a9 100644
--- a/arch/parisc/kernel/hpmc.S
+++ b/arch/parisc/kernel/hpmc.S
@@ -121,8 +121,7 @@ os_hpmc:
/* Setup stack pointer. */
- ldil L%PA(hpmc_stack),sp
- ldo R%PA(hpmc_stack)(sp),sp
+ load32 PA(hpmc_stack),sp
ldo 128(sp),sp /* leave room for arguments */
@@ -135,8 +134,7 @@ os_hpmc:
mtctl %r4,ipsw
mtctl %r0,pcsq
mtctl %r0,pcsq
- ldil L%PA(os_hpmc_1),%r4
- ldo R%PA(os_hpmc_1)(%r4),%r4
+ load32 PA(os_hpmc_1),%r4
mtctl %r4,pcoq
ldo 4(%r4),%r4
mtctl %r4,pcoq
@@ -155,12 +153,9 @@ os_hpmc_1:
ldo PDC_PIM(%r0), arg0
ldo PDC_PIM_HPMC(%r0),arg1 /* Transfer HPMC data */
- ldil L%PA(hpmc_raddr),arg2
- ldo R%PA(hpmc_raddr)(arg2),arg2
- ldil L%PA(hpmc_pim_data),arg3
- ldo R%PA(hpmc_pim_data)(arg3),arg3
- ldil L%HPMC_PIM_DATA_SIZE,%r4
- ldo R%HPMC_PIM_DATA_SIZE(%r4),%r4
+ load32 PA(hpmc_raddr),arg2
+ load32 PA(hpmc_pim_data),arg3
+ load32 HPMC_PIM_DATA_SIZE,%r4
stw %r4,-52(sp)
ldil L%PA(os_hpmc_2), rp
@@ -199,16 +194,13 @@ os_hpmc_3:
ldo PDC_IODC(%r0),arg0
ldo PDC_IODC_READ(%r0),arg1
- ldil L%PA(hpmc_raddr),arg2
- ldo R%PA(hpmc_raddr)(arg2),arg2
+ load32 PA(hpmc_raddr),arg2
ldw BOOT_CONSOLE_HPA_OFFSET(%r0),arg3 /* console hpa */
ldo PDC_IODC_RI_INIT(%r0),%r4
stw %r4,-52(sp)
- ldil L%PA(hpmc_iodc_buf),%r4
- ldo R%PA(hpmc_iodc_buf)(%r4),%r4
+ load32 PA(hpmc_iodc_buf),%r4
stw %r4,-56(sp)
- ldil L%HPMC_IODC_BUF_SIZE,%r4
- ldo R%HPMC_IODC_BUF_SIZE(%r4),%r4
+ load32 HPMC_IODC_BUF_SIZE,%r4
stw %r4,-60(sp)
ldil L%PA(os_hpmc_4),rp
@@ -225,16 +217,14 @@ os_hpmc_4:
ldw BOOT_CONSOLE_SPA_OFFSET(%r0),arg2 /* console spa */
depi 0,31,11,arg2 /* clear bits 21-31 */
ldo BOOT_CONSOLE_PATH_OFFSET(%r0),arg3 /* console path */
- ldil L%PA(hpmc_raddr),%r4
- ldo R%PA(hpmc_raddr)(%r4),%r4
+ load32 PA(hpmc_raddr),%r4
stw %r4, -52(sp)
stw %r0, -56(sp) /* HV */
stw %r0, -60(sp) /* HV */
stw %r0, -64(sp) /* HV */
stw %r0, -68(sp) /* lang, must be zero */
- ldil L%PA(hpmc_iodc_buf),%r5
- ldo R%PA(hpmc_iodc_buf)(%r5),%r5
+ load32 PA(hpmc_iodc_buf),%r5
ldil L%PA(os_hpmc_5),rp
bv (%r5)
ldo R%PA(os_hpmc_5)(rp),rp
@@ -249,8 +239,7 @@ os_hpmc_5:
* we don't intend to ever return to user land anyway)
*/
- ldil L%PA(swapper_pg_dir),%r4
- ldo R%PA(swapper_pg_dir)(%r4),%r4
+ load32 PA(swapper_pg_dir),%r4
mtctl %r4,%cr24 /* Initialize kernel root pointer */
mtctl %r4,%cr25 /* Initialize user root pointer */
@@ -265,8 +254,7 @@ os_hpmc_5:
rsm 8,%r0 /* Clear Q bit */
ldi 1,%r8 /* Set trap code to "1" for HPMC */
- ldil L%PA(intr_save), %r1
- ldo R%PA(intr_save)(%r1), %r1
+ load32 PA(intr_save),%r1
be 0(%sr7,%r1)
nop
diff --git a/arch/parisc/kernel/ioctl32.c b/arch/parisc/kernel/ioctl32.c
index 53ef897ec405..1d3824b670d1 100644
--- a/arch/parisc/kernel/ioctl32.c
+++ b/arch/parisc/kernel/ioctl32.c
@@ -563,7 +563,7 @@ static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg)
#endif
-#define HANDLE_IOCTL(cmd, handler) { cmd, (ioctl_trans_handler_t)handler, 0 },
+#define HANDLE_IOCTL(cmd, handler) { cmd, (ioctl_trans_handler_t)handler, NULL },
#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd, sys_ioctl)
#define IOCTL_TABLE_START struct ioctl_trans ioctl_start[] = {
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index 6388172ec235..04febd66b0ea 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -5,6 +5,7 @@
* Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
* Copyright (C) 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org)
* Copyright (C) 1999-2000 Grant Grundler
+ * Copyright (c) 2005 Matthew Wilcox
*
* 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
@@ -22,38 +23,19 @@
*/
#include <linux/bitops.h>
#include <linux/config.h>
-#include <linux/eisa.h>
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/types.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
-#include <linux/irq.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
+#include <linux/types.h>
-#include <asm/cache.h>
-#include <asm/pdc.h>
-
-#undef DEBUG_IRQ
#undef PARISC_IRQ_CR16_COUNTS
extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *);
extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *);
-#ifdef DEBUG_IRQ
-#define DBG_IRQ(irq, x) if ((irq) != TIMER_IRQ) printk x
-#else /* DEBUG_IRQ */
-#define DBG_IRQ(irq, x) do { } while (0)
-#endif /* DEBUG_IRQ */
-
#define EIEM_MASK(irq) (1UL<<(CPU_IRQ_MAX - irq))
/* Bits in EIEM correlate with cpu_irq_action[].
@@ -200,7 +182,25 @@ int txn_claim_irq(int irq)
return cpu_claim_irq(irq, NULL, NULL) ? -1 : irq;
}
-int txn_alloc_irq(void)
+/*
+ * The bits_wide parameter accommodates the limitations of the HW/SW which
+ * use these bits:
+ * Legacy PA I/O (GSC/NIO): 5 bits (architected EIM register)
+ * V-class (EPIC): 6 bits
+ * N/L/A-class (iosapic): 8 bits
+ * PCI 2.2 MSI: 16 bits
+ * Some PCI devices: 32 bits (Symbios SCSI/ATM/HyperFabric)
+ *
+ * On the service provider side:
+ * o PA 1.1 (and PA2.0 narrow mode) 5-bits (width of EIR register)
+ * o PA 2.0 wide mode 6-bits (per processor)
+ * o IA64 8-bits (0-256 total)
+ *
+ * So a Legacy PA I/O device on a PA 2.0 box can't use all the bits supported
+ * by the processor...and the N/L-class I/O subsystem supports more bits than
+ * PA2.0 has. The first case is the problem.
+ */
+int txn_alloc_irq(unsigned int bits_wide)
{
int irq;
@@ -208,6 +208,8 @@ int txn_alloc_irq(void)
for (irq = CPU_IRQ_BASE + 1; irq <= CPU_IRQ_MAX; irq++) {
if (cpu_claim_irq(irq, NULL, NULL) < 0)
continue;
+ if ((irq - CPU_IRQ_BASE) >= (1 << bits_wide))
+ continue;
return irq;
}
@@ -215,7 +217,7 @@ int txn_alloc_irq(void)
return -1;
}
-unsigned long txn_alloc_addr(int virt_irq)
+unsigned long txn_alloc_addr(unsigned int virt_irq)
{
static int next_cpu = -1;
@@ -233,36 +235,8 @@ unsigned long txn_alloc_addr(int virt_irq)
}
-/*
-** The alloc process needs to accept a parameter to accommodate limitations
-** of the HW/SW which use these bits:
-** Legacy PA I/O (GSC/NIO): 5 bits (architected EIM register)
-** V-class (EPIC): 6 bits
-** N/L-class/A500: 8 bits (iosapic)
-** PCI 2.2 MSI: 16 bits (I think)
-** Existing PCI devices: 32-bits (all Symbios SCSI/ATM/HyperFabric)
-**
-** On the service provider side:
-** o PA 1.1 (and PA2.0 narrow mode) 5-bits (width of EIR register)
-** o PA 2.0 wide mode 6-bits (per processor)
-** o IA64 8-bits (0-256 total)
-**
-** So a Legacy PA I/O device on a PA 2.0 box can't use all
-** the bits supported by the processor...and the N/L-class
-** I/O subsystem supports more bits than PA2.0 has. The first
-** case is the problem.
-*/
-unsigned int txn_alloc_data(int virt_irq, unsigned int bits_wide)
+unsigned int txn_alloc_data(unsigned int virt_irq)
{
- /* XXX FIXME : bits_wide indicates how wide the transaction
- ** data is allowed to be...we may need a different virt_irq
- ** if this one won't work. Another reason to index virtual
- ** irq's into a table which can manage CPU/IRQ bit separately.
- */
- if ((virt_irq - CPU_IRQ_BASE) > (1 << (bits_wide - 1))) {
- panic("Sorry -- didn't allocate valid IRQ for this device\n");
- }
-
return virt_irq - CPU_IRQ_BASE;
}
@@ -270,42 +244,35 @@ unsigned int txn_alloc_data(int virt_irq, unsigned int bits_wide)
void do_cpu_irq_mask(struct pt_regs *regs)
{
unsigned long eirr_val;
- unsigned int i=3; /* limit time in interrupt context */
+
+ irq_enter();
/*
- * PSW_I or EIEM bits cannot be enabled until after the
- * interrupts are processed.
- * timer_interrupt() assumes it won't get interrupted when it
- * holds the xtime_lock...an unmasked interrupt source could
- * interrupt and deadlock by trying to grab xtime_lock too.
- * Keeping PSW_I and EIEM disabled avoids this.
+ * Only allow interrupt processing to be interrupted by the
+ * timer tick
*/
- set_eiem(0UL); /* disable all extr interrupt for now */
+ set_eiem(EIEM_MASK(TIMER_IRQ));
/* 1) only process IRQs that are enabled/unmasked (cpu_eiem)
* 2) We loop here on EIRR contents in order to avoid
* nested interrupts or having to take another interrupt
* when we could have just handled it right away.
- * 3) Limit the number of times we loop to make sure other
- * processing can occur.
*/
for (;;) {
unsigned long bit = (1UL << (BITS_PER_LONG - 1));
unsigned int irq;
eirr_val = mfctl(23) & cpu_eiem;
- if (!eirr_val || !i--)
+ if (!eirr_val)
break;
- mtctl(eirr_val, 23); /* reset bits we are going to process */
+ if (eirr_val & EIEM_MASK(TIMER_IRQ))
+ set_eiem(0);
-#ifdef DEBUG_IRQ
- if (eirr_val != (1UL << MAX_CPU_IRQ))
- printk(KERN_DEBUG "do_cpu_irq_mask 0x%x & 0x%x\n", eirr_val, cpu_eiem);
-#endif
+ mtctl(eirr_val, 23); /* reset bits we are going to process */
/* Work our way from MSb to LSb...same order we alloc EIRs */
for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) {
- if (!(bit & eirr_val & cpu_eiem))
+ if (!(bit & eirr_val))
continue;
/* clear bit in mask - can exit loop sooner */
@@ -315,6 +282,7 @@ void do_cpu_irq_mask(struct pt_regs *regs)
}
}
set_eiem(cpu_eiem);
+ irq_exit();
}
diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c
index f8bacd79a631..b3ad0a505b87 100644
--- a/arch/parisc/kernel/perf.c
+++ b/arch/parisc/kernel/perf.c
@@ -42,7 +42,6 @@
* on every box.
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/miscdevice.h>
@@ -157,16 +156,16 @@ static struct rdr_tbl_ent perf_rdr_tbl_U[] = {
* this array.
*/
static uint64_t perf_bitmasks[] = {
- 0x0000000000000000, /* first dbl word must be zero */
- 0xfdffe00000000000, /* RDR0 bitmask */
- 0x003f000000000000, /* RDR1 bitmask */
- 0x00ffffffffffffff, /* RDR20-RDR21 bitmask (152 bits) */
- 0xffffffffffffffff,
- 0xfffffffc00000000,
- 0xffffffffffffffff, /* RDR22-RDR23 bitmask (233 bits) */
- 0xffffffffffffffff,
- 0xfffffffffffffffc,
- 0xff00000000000000
+ 0x0000000000000000ul, /* first dbl word must be zero */
+ 0xfdffe00000000000ul, /* RDR0 bitmask */
+ 0x003f000000000000ul, /* RDR1 bitmask */
+ 0x00fffffffffffffful, /* RDR20-RDR21 bitmask (152 bits) */
+ 0xfffffffffffffffful,
+ 0xfffffffc00000000ul,
+ 0xfffffffffffffffful, /* RDR22-RDR23 bitmask (233 bits) */
+ 0xfffffffffffffffful,
+ 0xfffffffffffffffcul,
+ 0xff00000000000000ul
};
/*
@@ -174,16 +173,16 @@ static uint64_t perf_bitmasks[] = {
* somethings have changed slightly.
*/
static uint64_t perf_bitmasks_piranha[] = {
- 0x0000000000000000, /* first dbl word must be zero */
- 0xfdffe00000000000, /* RDR0 bitmask */
- 0x003f000000000000, /* RDR1 bitmask */
- 0x00ffffffffffffff, /* RDR20-RDR21 bitmask (158 bits) */
- 0xffffffffffffffff,
- 0xfffffffc00000000,
- 0xffffffffffffffff, /* RDR22-RDR23 bitmask (210 bits) */
- 0xffffffffffffffff,
- 0xffffffffffffffff,
- 0xfffc000000000000
+ 0x0000000000000000ul, /* first dbl word must be zero */
+ 0xfdffe00000000000ul, /* RDR0 bitmask */
+ 0x003f000000000000ul, /* RDR1 bitmask */
+ 0x00fffffffffffffful, /* RDR20-RDR21 bitmask (158 bits) */
+ 0xfffffffffffffffful,
+ 0xfffffffc00000000ul,
+ 0xfffffffffffffffful, /* RDR22-RDR23 bitmask (210 bits) */
+ 0xfffffffffffffffful,
+ 0xfffffffffffffffful,
+ 0xfffc000000000000ul
};
static uint64_t *bitmask_array; /* array of bitmasks to use */
@@ -194,8 +193,8 @@ static uint64_t *bitmask_array; /* array of bitmasks to use */
static int perf_config(uint32_t *image_ptr);
static int perf_release(struct inode *inode, struct file *file);
static int perf_open(struct inode *inode, struct file *file);
-static ssize_t perf_read(struct file *file, char *buf, size_t cnt, loff_t *ppos);
-static ssize_t perf_write(struct file *file, const char *buf, size_t count,
+static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos);
+static ssize_t perf_write(struct file *file, const char __user *buf, size_t count,
loff_t *ppos);
static int perf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg);
@@ -287,7 +286,7 @@ static int perf_release(struct inode *inode, struct file *file)
/*
* Read does nothing for this driver
*/
-static ssize_t perf_read(struct file *file, char *buf, size_t cnt, loff_t *ppos)
+static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
{
return 0;
}
@@ -299,7 +298,7 @@ static ssize_t perf_read(struct file *file, char *buf, size_t cnt, loff_t *ppos)
* called on the processor that the download should happen
* on.
*/
-static ssize_t perf_write(struct file *file, const char *buf, size_t count,
+static ssize_t perf_write(struct file *file, const char __user *buf, size_t count,
loff_t *ppos)
{
int err;
@@ -460,7 +459,7 @@ static int perf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
/* copy out the Counters */
- if (copy_to_user((void *)arg, raddr,
+ if (copy_to_user((void __user *)arg, raddr,
sizeof (raddr)) != 0) {
return -EFAULT;
}
@@ -607,7 +606,7 @@ static int perf_stop_counters(uint32_t *raddr)
* all of dword 22 and 58 bits (plus 6 don't care bits) of
* dword 23.
*/
- userbuf[21] &= 0xfffffffffffffc00; /* 0 to last 10 bits */
+ userbuf[21] &= 0xfffffffffffffc00ul; /* 0 to last 10 bits */
userbuf[22] = 0;
userbuf[23] = 0;
@@ -802,8 +801,8 @@ static int perf_write_image(uint64_t *memaddr)
proc_hpa = cpu_device->hpa;
/* Merge intrigue bits into Runway STATUS 0 */
- tmp64 = __raw_readq(proc_hpa + RUNWAY_STATUS) & 0xffecffffffffffff;
- __raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000), proc_hpa + RUNWAY_STATUS);
+ tmp64 = __raw_readq(proc_hpa + RUNWAY_STATUS) & 0xffecfffffffffffful;
+ __raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul), proc_hpa + RUNWAY_STATUS);
/* Write RUNWAY DEBUG registers */
for (i = 0; i < 8; i++) {
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 320fca55fa1a..d2d247a78a75 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -251,7 +251,7 @@ int
sys_clone(unsigned long clone_flags, unsigned long usp,
struct pt_regs *regs)
{
- int *user_tid = (int *)regs->gr[26];
+ int __user *user_tid = (int __user *)regs->gr[26];
/* usp must be word aligned. This also prevents users from
* passing in the value 1 (which is the signal for a special
@@ -357,12 +357,12 @@ asmlinkage int sys_execve(struct pt_regs *regs)
int error;
char *filename;
- filename = getname((char *) regs->gr[26]);
+ filename = getname((const char __user *) regs->gr[26]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, (char **) regs->gr[25],
- (char **) regs->gr[24], regs);
+ error = do_execve(filename, (char __user **) regs->gr[25],
+ (char __user **) regs->gr[24], regs);
if (error == 0) {
task_lock(current);
current->ptrace &= ~PT_DTRACE;
diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S
index 8b8ee543ae10..8dd5defb7316 100644
--- a/arch/parisc/kernel/real2.S
+++ b/arch/parisc/kernel/real2.S
@@ -81,8 +81,7 @@ real32_call_asm:
rsm PSW_SM_W, %r0 /* go narrow */
#endif
- ldil L%PA(ric_ret), %r2
- ldo R%PA(ric_ret)(%r2), %r2
+ load32 PA(ric_ret), %r2
bv 0(%r31)
nop
ric_ret:
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
index f3267597085b..40fc427b5d54 100644
--- a/arch/parisc/kernel/setup.c
+++ b/arch/parisc/kernel/setup.c
@@ -199,7 +199,7 @@ static void __init parisc_proc_mkdir(void)
case pcxl2:
if (NULL == proc_gsc_root)
{
- proc_gsc_root = proc_mkdir("bus/gsc", 0);
+ proc_gsc_root = proc_mkdir("bus/gsc", NULL);
}
break;
case pcxt_:
@@ -210,13 +210,13 @@ static void __init parisc_proc_mkdir(void)
case pcxw2:
if (NULL == proc_runway_root)
{
- proc_runway_root = proc_mkdir("bus/runway", 0);
+ proc_runway_root = proc_mkdir("bus/runway", NULL);
}
break;
case mako:
if (NULL == proc_mckinley_root)
{
- proc_mckinley_root = proc_mkdir("bus/mckinley", 0);
+ proc_mckinley_root = proc_mkdir("bus/mckinley", NULL);
}
break;
default:
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 4a0a8adbc79d..218ce66290dd 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -69,7 +69,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall);
#endif
asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs)
+sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
{
sigset_t saveset, newset;
#ifdef __LP64__
@@ -79,7 +79,7 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs)
/* XXX: Don't preclude handling different sized sigset_t's. */
if (sigsetsize != sizeof(compat_sigset_t))
return -EINVAL;
- if (copy_from_user(&newset32, (compat_sigset_t *)unewset, sizeof(newset32)))
+ if (copy_from_user(&newset32, (compat_sigset_t __user *)unewset, sizeof(newset32)))
return -EFAULT;
sigset_32to64(&newset,&newset32);
@@ -125,7 +125,7 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs)
#define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */
static long
-restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
+restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
{
long err = 0;
@@ -143,14 +143,14 @@ restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
void
sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
{
- struct rt_sigframe *frame;
+ struct rt_sigframe __user *frame;
struct siginfo si;
sigset_t set;
unsigned long usp = (regs->gr[30] & ~(0x01UL));
unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE;
#ifdef __LP64__
compat_sigset_t compat_set;
- struct compat_rt_sigframe * compat_frame;
+ struct compat_rt_sigframe __user * compat_frame;
if(personality(current->personality) == PER_LINUX32)
sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
@@ -158,12 +158,12 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
/* Unwind the user stack to get the rt_sigframe structure. */
- frame = (struct rt_sigframe *)
+ frame = (struct rt_sigframe __user *)
(usp - sigframe_size);
DBG(2,"sys_rt_sigreturn: frame is %p\n", frame);
#ifdef __LP64__
- compat_frame = (struct compat_rt_sigframe *)frame;
+ compat_frame = (struct compat_rt_sigframe __user *)frame;
if(personality(current->personality) == PER_LINUX32){
DBG(2,"sys_rt_sigreturn: ELF32 process.\n");
@@ -238,7 +238,7 @@ give_sigsegv:
* Set up a signal frame.
*/
-static inline void *
+static inline void __user *
get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
{
/*FIXME: ELF32 vs. ELF64 has different frame_size, but since we
@@ -251,11 +251,11 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
sp = current->sas_ss_sp; /* Stacks grow up! */
DBG(1,"get_sigframe: Returning sp = %#lx\n", (unsigned long)sp);
- return (void *) sp; /* Stacks grow up. Fun. */
+ return (void __user *) sp; /* Stacks grow up. Fun. */
}
static long
-setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, int in_syscall)
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, int in_syscall)
{
unsigned long flags = 0;
@@ -292,14 +292,14 @@ static long
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs, int in_syscall)
{
- struct rt_sigframe *frame;
+ struct rt_sigframe __user *frame;
unsigned long rp, usp;
unsigned long haddr, sigframe_size;
struct siginfo si;
int err = 0;
#ifdef __LP64__
compat_int_t compat_val;
- struct compat_rt_sigframe * compat_frame;
+ struct compat_rt_sigframe __user * compat_frame;
compat_sigset_t compat_set;
#endif
@@ -313,7 +313,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
#ifdef __LP64__
- compat_frame = (struct compat_rt_sigframe *)frame;
+ compat_frame = (struct compat_rt_sigframe __user *)frame;
if(personality(current->personality) == PER_LINUX32) {
DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info);
@@ -396,7 +396,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
#endif
if (haddr & PA_PLABEL_FDESC) {
Elf32_Fdesc fdesc;
- Elf32_Fdesc *ufdesc = (Elf32_Fdesc *)A(haddr & ~3);
+ Elf32_Fdesc __user *ufdesc = (Elf32_Fdesc __user *)A(haddr & ~3);
err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc));
@@ -409,7 +409,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
#ifdef __LP64__
} else {
Elf64_Fdesc fdesc;
- Elf64_Fdesc *ufdesc = (Elf64_Fdesc *)A(haddr & ~3);
+ Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3);
err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc));
diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c
index 1c1668b6f02f..0792e20efef3 100644
--- a/arch/parisc/kernel/signal32.c
+++ b/arch/parisc/kernel/signal32.c
@@ -20,7 +20,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/compat.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -65,7 +64,7 @@ sigset_64to32(compat_sigset_t *s32, sigset_t *s64)
}
static int
-put_sigset32(compat_sigset_t *up, sigset_t *set, size_t sz)
+put_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz)
{
compat_sigset_t s;
@@ -76,7 +75,7 @@ put_sigset32(compat_sigset_t *up, sigset_t *set, size_t sz)
}
static int
-get_sigset32(compat_sigset_t *up, sigset_t *set, size_t sz)
+get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz)
{
compat_sigset_t s;
int r;
@@ -90,7 +89,7 @@ get_sigset32(compat_sigset_t *up, sigset_t *set, size_t sz)
return r;
}
-int sys32_rt_sigprocmask(int how, compat_sigset_t *set, compat_sigset_t *oset,
+int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, compat_sigset_t __user *oset,
unsigned int sigsetsize)
{
sigset_t old_set, new_set;
@@ -99,8 +98,8 @@ int sys32_rt_sigprocmask(int how, compat_sigset_t *set, compat_sigset_t *oset,
if (set && get_sigset32(set, &new_set, sigsetsize))
return -EFAULT;
- KERNEL_SYSCALL(ret, sys_rt_sigprocmask, how, set ? &new_set : NULL,
- oset ? &old_set : NULL, sigsetsize);
+ KERNEL_SYSCALL(ret, sys_rt_sigprocmask, how, set ? (sigset_t __user *)&new_set : NULL,
+ oset ? (sigset_t __user *)&old_set : NULL, sigsetsize);
if (!ret && oset && put_sigset32(oset, &old_set, sigsetsize))
return -EFAULT;
@@ -109,12 +108,12 @@ int sys32_rt_sigprocmask(int how, compat_sigset_t *set, compat_sigset_t *oset,
}
-int sys32_rt_sigpending(compat_sigset_t *uset, unsigned int sigsetsize)
+int sys32_rt_sigpending(compat_sigset_t __user *uset, unsigned int sigsetsize)
{
int ret;
sigset_t set;
- KERNEL_SYSCALL(ret, sys_rt_sigpending, &set, sigsetsize);
+ KERNEL_SYSCALL(ret, sys_rt_sigpending, (sigset_t __user *)&set, sigsetsize);
if (!ret && put_sigset32(uset, &set, sigsetsize))
return -EFAULT;
@@ -123,7 +122,7 @@ int sys32_rt_sigpending(compat_sigset_t *uset, unsigned int sigsetsize)
}
long
-sys32_rt_sigaction(int sig, const struct sigaction32 *act, struct sigaction32 *oact,
+sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, struct sigaction32 __user *oact,
size_t sigsetsize)
{
struct k_sigaction32 new_sa32, old_sa32;
@@ -151,7 +150,7 @@ sys32_rt_sigaction(int sig, const struct sigaction32 *act, struct sigaction32 *o
}
int
-do_sigaltstack32 (const compat_stack_t *uss32, compat_stack_t *uoss32, unsigned long sp)
+do_sigaltstack32 (const compat_stack_t __user *uss32, compat_stack_t __user *uoss32, unsigned long sp)
{
compat_stack_t ss32, oss32;
stack_t ss, oss;
@@ -162,7 +161,7 @@ do_sigaltstack32 (const compat_stack_t *uss32, compat_stack_t *uoss32, unsigned
if (copy_from_user(&ss32, uss32, sizeof ss32))
return -EFAULT;
- ss.ss_sp = (void *)(unsigned long)ss32.ss_sp;
+ ss.ss_sp = (void __user *)(unsigned long)ss32.ss_sp;
ss.ss_flags = ss32.ss_flags;
ss.ss_size = ss32.ss_size;
@@ -172,7 +171,7 @@ do_sigaltstack32 (const compat_stack_t *uss32, compat_stack_t *uoss32, unsigned
if (uoss32)
ossp = &oss;
- KERNEL_SYSCALL(ret, do_sigaltstack, ssp, ossp, sp);
+ KERNEL_SYSCALL(ret, do_sigaltstack, (const stack_t __user *)ssp, (stack_t __user *)ossp, sp);
if (!ret && uoss32) {
oss32.ss_sp = (unsigned int)(unsigned long)oss.ss_sp;
@@ -186,7 +185,7 @@ do_sigaltstack32 (const compat_stack_t *uss32, compat_stack_t *uoss32, unsigned
}
long
-restore_sigcontext32(struct compat_sigcontext *sc, struct compat_regfile * rf,
+restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
struct pt_regs *regs)
{
long err = 0;
@@ -265,7 +264,7 @@ restore_sigcontext32(struct compat_sigcontext *sc, struct compat_regfile * rf,
* truncate for a 32-bit userspace.
*/
long
-setup_sigcontext32(struct compat_sigcontext *sc, struct compat_regfile * rf,
+setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
struct pt_regs *regs, int in_syscall)
{
compat_int_t flags = 0;
diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h
index 9c29b63d9e4a..4d1569e717cc 100644
--- a/arch/parisc/kernel/signal32.h
+++ b/arch/parisc/kernel/signal32.h
@@ -31,13 +31,13 @@ struct k_sigaction32 {
void sigset_32to64(sigset_t *s64, compat_sigset_t *s32);
void sigset_64to32(compat_sigset_t *s32, sigset_t *s64);
-int do_sigaltstack32 (const compat_stack_t *uss32,
- compat_stack_t *uoss32, unsigned long sp);
-long restore_sigcontext32(struct compat_sigcontext *sc,
- struct compat_regfile *rf,
+int do_sigaltstack32 (const compat_stack_t __user *uss32,
+ compat_stack_t __user *uoss32, unsigned long sp);
+long restore_sigcontext32(struct compat_sigcontext __user *sc,
+ struct compat_regfile __user *rf,
struct pt_regs *regs);
-long setup_sigcontext32(struct compat_sigcontext *sc,
- struct compat_regfile *rf,
+long setup_sigcontext32(struct compat_sigcontext __user *sc,
+ struct compat_regfile __user *rf,
struct pt_regs *regs, int in_syscall);
#endif
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index 96ad250edfa5..7958cd8c8bf8 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -32,7 +32,7 @@
#include <linux/smp_lock.h>
#include <linux/syscalls.h>
-int sys_pipe(int *fildes)
+int sys_pipe(int __user *fildes)
{
int fd[2];
int error;
@@ -161,7 +161,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
}
}
-long sys_shmat_wrapper(int shmid, char *shmaddr, int shmflag)
+long sys_shmat_wrapper(int shmid, char __user *shmaddr, int shmflag)
{
unsigned long raddr;
int r;
@@ -174,8 +174,8 @@ long sys_shmat_wrapper(int shmid, char *shmaddr, int shmflag)
/* Fucking broken ABI */
-#ifdef CONFIG_PARISC64
-asmlinkage long parisc_truncate64(const char * path,
+#ifdef CONFIG_64BIT
+asmlinkage long parisc_truncate64(const char __user * path,
unsigned int high, unsigned int low)
{
return sys_truncate(path, (long)high << 32 | low);
@@ -189,7 +189,7 @@ asmlinkage long parisc_ftruncate64(unsigned int fd,
/* stubs for the benefit of the syscall_table since truncate64 and truncate
* are identical on LP64 */
-asmlinkage long sys_truncate64(const char * path, unsigned long length)
+asmlinkage long sys_truncate64(const char __user * path, unsigned long length)
{
return sys_truncate(path, length);
}
@@ -203,7 +203,7 @@ asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg
}
#else
-asmlinkage long parisc_truncate64(const char * path,
+asmlinkage long parisc_truncate64(const char __user * path,
unsigned int high, unsigned int low)
{
return sys_truncate64(path, (loff_t)high << 32 | low);
@@ -216,13 +216,13 @@ asmlinkage long parisc_ftruncate64(unsigned int fd,
}
#endif
-asmlinkage ssize_t parisc_pread64(unsigned int fd, char *buf, size_t count,
+asmlinkage ssize_t parisc_pread64(unsigned int fd, char __user *buf, size_t count,
unsigned int high, unsigned int low)
{
return sys_pread64(fd, buf, count, (loff_t)high << 32 | low);
}
-asmlinkage ssize_t parisc_pwrite64(unsigned int fd, const char *buf,
+asmlinkage ssize_t parisc_pwrite64(unsigned int fd, const char __user *buf,
size_t count, unsigned int high, unsigned int low)
{
return sys_pwrite64(fd, buf, count, (loff_t)high << 32 | low);
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index e4e6bfcaa711..ed58d1a5d825 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -74,7 +74,7 @@ asmlinkage int sys32_execve(struct pt_regs *regs)
char *filename;
DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26]));
- filename = getname((char *) regs->gr[26]);
+ filename = getname((const char __user *) regs->gr[26]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
@@ -111,13 +111,13 @@ struct __sysctl_args32 {
u32 __unused[4];
};
-asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
+asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
{
struct __sysctl_args32 tmp;
int error;
unsigned int oldlen32;
size_t oldlen, *oldlenp = NULL;
- unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
+ unsigned long addr = (((long __force)&args->__unused[0]) + 7) & ~7;
extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
void *newval, size_t newlen);
@@ -159,7 +159,7 @@ asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
error = -EFAULT;
}
}
- if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)))
+ if (copy_to_user(&args->__unused[0], tmp.__unused, sizeof(tmp.__unused)))
error = -EFAULT;
}
return error;
@@ -168,19 +168,19 @@ asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
#endif /* CONFIG_SYSCTL */
asmlinkage long sys32_sched_rr_get_interval(pid_t pid,
- struct compat_timespec *interval)
+ struct compat_timespec __user *interval)
{
struct timespec t;
int ret;
-
- KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, &t);
+
+ KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, (struct timespec __user *)&t);
if (put_compat_timespec(&t, interval))
return -EFAULT;
return ret;
}
static int
-put_compat_timeval(struct compat_timeval *u, struct timeval *t)
+put_compat_timeval(struct compat_timeval __user *u, struct timeval *t)
{
struct compat_timeval t32;
t32.tv_sec = t->tv_sec;
@@ -188,7 +188,7 @@ put_compat_timeval(struct compat_timeval *u, struct timeval *t)
return copy_to_user(u, &t32, sizeof t32);
}
-static inline long get_ts32(struct timespec *o, struct compat_timeval *i)
+static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
{
long usec;
@@ -201,7 +201,7 @@ static inline long get_ts32(struct timespec *o, struct compat_timeval *i)
}
asmlinkage int
-sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
+sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
{
extern void do_gettimeofday(struct timeval *tv);
@@ -220,7 +220,7 @@ sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
}
asmlinkage
-int sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
+int sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
{
struct timespec kts;
struct timezone ktz;
@@ -237,7 +237,7 @@ int sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
}
-int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
+int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
{
int err;
@@ -294,24 +294,24 @@ struct old_linux32_dirent {
};
struct getdents32_callback {
- struct linux32_dirent * current_dir;
- struct linux32_dirent * previous;
+ struct linux32_dirent __user * current_dir;
+ struct linux32_dirent __user * previous;
int count;
int error;
};
struct readdir32_callback {
- struct old_linux32_dirent * dirent;
+ struct old_linux32_dirent __user * dirent;
int count;
};
#define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
static int
filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
unsigned int d_type)
{
- struct linux32_dirent * dirent;
+ struct linux32_dirent __user * dirent;
struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4);
@@ -327,17 +327,17 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
put_user(reclen, &dirent->d_reclen);
copy_to_user(dirent->d_name, name, namlen);
put_user(0, dirent->d_name + namlen);
- dirent = (struct linux32_dirent *)((char *)dirent + reclen);
+ dirent = ((void __user *)dirent) + reclen;
buf->current_dir = dirent;
buf->count -= reclen;
return 0;
}
asmlinkage long
-sys32_getdents (unsigned int fd, void * dirent, unsigned int count)
+sys32_getdents (unsigned int fd, void __user * dirent, unsigned int count)
{
struct file * file;
- struct linux32_dirent * lastdirent;
+ struct linux32_dirent __user * lastdirent;
struct getdents32_callback buf;
int error;
@@ -346,7 +346,7 @@ sys32_getdents (unsigned int fd, void * dirent, unsigned int count)
if (!file)
goto out;
- buf.current_dir = (struct linux32_dirent *) dirent;
+ buf.current_dir = (struct linux32_dirent __user *) dirent;
buf.previous = NULL;
buf.count = count;
buf.error = 0;
@@ -372,7 +372,7 @@ fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t
unsigned int d_type)
{
struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
- struct old_linux32_dirent * dirent;
+ struct old_linux32_dirent __user * dirent;
if (buf->count)
return -EINVAL;
@@ -387,7 +387,7 @@ fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t
}
asmlinkage long
-sys32_readdir (unsigned int fd, void * dirent, unsigned int count)
+sys32_readdir (unsigned int fd, void __user * dirent, unsigned int count)
{
int error;
struct file * file;
@@ -477,7 +477,7 @@ struct msgbuf32 {
};
asmlinkage long sys32_msgsnd(int msqid,
- struct msgbuf32 *umsgp32,
+ struct msgbuf32 __user *umsgp32,
size_t msgsz, int msgflg)
{
struct msgbuf *mb;
@@ -494,14 +494,14 @@ asmlinkage long sys32_msgsnd(int msqid,
if (err)
err = -EFAULT;
else
- KERNEL_SYSCALL(err, sys_msgsnd, msqid, mb, msgsz, msgflg);
+ KERNEL_SYSCALL(err, sys_msgsnd, msqid, (struct msgbuf __user *)mb, msgsz, msgflg);
kfree(mb);
return err;
}
asmlinkage long sys32_msgrcv(int msqid,
- struct msgbuf32 *umsgp32,
+ struct msgbuf32 __user *umsgp32,
size_t msgsz, long msgtyp, int msgflg)
{
struct msgbuf *mb;
@@ -511,7 +511,7 @@ asmlinkage long sys32_msgrcv(int msqid,
if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
return -ENOMEM;
- KERNEL_SYSCALL(err, sys_msgrcv, msqid, mb, msgsz, msgtyp, msgflg);
+ KERNEL_SYSCALL(err, sys_msgrcv, msqid, (struct msgbuf __user *)mb, msgsz, msgtyp, msgflg);
if (err >= 0) {
len = err;
@@ -528,7 +528,7 @@ asmlinkage long sys32_msgrcv(int msqid,
return err;
}
-asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count)
+asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count)
{
mm_segment_t old_fs = get_fs();
int ret;
@@ -538,7 +538,7 @@ asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 c
return -EFAULT;
set_fs(KERNEL_DS);
- ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
+ ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
set_fs(old_fs);
if (offset && put_user(of, offset))
@@ -547,9 +547,7 @@ asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 c
return ret;
}
-typedef long __kernel_loff_t32; /* move this to asm/posix_types.h? */
-
-asmlinkage int sys32_sendfile64(int out_fd, int in_fd, __kernel_loff_t32 *offset, s32 count)
+asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count)
{
mm_segment_t old_fs = get_fs();
int ret;
@@ -559,7 +557,7 @@ asmlinkage int sys32_sendfile64(int out_fd, int in_fd, __kernel_loff_t32 *offset
return -EFAULT;
set_fs(KERNEL_DS);
- ret = sys_sendfile64(out_fd, in_fd, offset ? &lof : NULL, count);
+ ret = sys_sendfile64(out_fd, in_fd, offset ? (loff_t __user *)&lof : NULL, count);
set_fs(old_fs);
if (offset && put_user(lof, offset))
@@ -598,7 +596,7 @@ struct timex32 {
int :32; int :32; int :32; int :32;
};
-asmlinkage long sys32_adjtimex(struct timex32 *txc_p32)
+asmlinkage long sys32_adjtimex(struct timex32 __user *txc_p32)
{
struct timex txc;
struct timex32 t32;
@@ -647,7 +645,7 @@ struct sysinfo32 {
* damage, I decided to just duplicate the code from sys_sysinfo here.
*/
-asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
+asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info)
{
struct sysinfo val;
int err;
@@ -714,7 +712,7 @@ asmlinkage long sys32_semctl(int semid, int semnum, int cmd, union semun arg)
return sys_semctl (semid, semnum, cmd, arg);
}
-long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char *buf,
+long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf,
size_t len)
{
return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low,
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 69a253fe2e8d..32b56595cf51 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -242,7 +242,7 @@ void handle_gdb_break(struct pt_regs *regs, int wot)
struct siginfo si;
si.si_code = wot;
- si.si_addr = (void *) (regs->iaoq[0] & ~3);
+ si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
si.si_signo = SIGTRAP;
si.si_errno = 0;
force_sig_info(SIGTRAP, &si, current);
@@ -263,7 +263,7 @@ void handle_break(unsigned iir, struct pt_regs *regs)
show_regs(regs);
#endif
si.si_code = TRAP_BRKPT;
- si.si_addr = (void *) (regs->iaoq[0] & ~3);
+ si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
si.si_signo = SIGTRAP;
force_sig_info(SIGTRAP, &si, current);
break;
@@ -281,7 +281,7 @@ void handle_break(unsigned iir, struct pt_regs *regs)
#endif
si.si_signo = SIGTRAP;
si.si_code = TRAP_BRKPT;
- si.si_addr = (void *) (regs->iaoq[0] & ~3);
+ si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
force_sig_info(SIGTRAP, &si, current);
return;
}
@@ -569,7 +569,7 @@ void handle_interruption(int code, struct pt_regs *regs)
give_sigill:
si.si_signo = SIGILL;
si.si_errno = 0;
- si.si_addr = (void *) regs->iaoq[0];
+ si.si_addr = (void __user *) regs->iaoq[0];
force_sig_info(SIGILL, &si, current);
return;
@@ -577,7 +577,7 @@ void handle_interruption(int code, struct pt_regs *regs)
/* Overflow Trap, let the userland signal handler do the cleanup */
si.si_signo = SIGFPE;
si.si_code = FPE_INTOVF;
- si.si_addr = (void *) regs->iaoq[0];
+ si.si_addr = (void __user *) regs->iaoq[0];
force_sig_info(SIGFPE, &si, current);
return;
@@ -699,9 +699,9 @@ void handle_interruption(int code, struct pt_regs *regs)
si.si_signo = SIGSEGV;
si.si_errno = 0;
if (code == 7)
- si.si_addr = (void *) regs->iaoq[0];
+ si.si_addr = (void __user *) regs->iaoq[0];
else
- si.si_addr = (void *) regs->ior;
+ si.si_addr = (void __user *) regs->ior;
force_sig_info(SIGSEGV, &si, current);
return;
@@ -721,7 +721,7 @@ void handle_interruption(int code, struct pt_regs *regs)
si.si_signo = SIGBUS;
si.si_code = BUS_OBJERR;
si.si_errno = 0;
- si.si_addr = (void *) regs->ior;
+ si.si_addr = (void __user *) regs->ior;
force_sig_info(SIGBUS, &si, current);
return;
}
@@ -745,7 +745,7 @@ void handle_interruption(int code, struct pt_regs *regs)
si.si_signo = SIGSEGV;
si.si_errno = 0;
si.si_code = SEGV_MAPERR;
- si.si_addr = (void *) regs->ior;
+ si.si_addr = (void __user *) regs->ior;
force_sig_info(SIGSEGV, &si, current);
return;
}
diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c
index 3eda1dadc379..62eea35bcd69 100644
--- a/arch/parisc/kernel/unaligned.c
+++ b/arch/parisc/kernel/unaligned.c
@@ -744,7 +744,7 @@ void handle_unaligned(struct pt_regs *regs)
si.si_signo = SIGSEGV;
si.si_errno = 0;
si.si_code = SEGV_MAPERR;
- si.si_addr = (void *)regs->ior;
+ si.si_addr = (void __user *)regs->ior;
force_sig_info(SIGSEGV, &si, current);
}
else
@@ -754,7 +754,7 @@ force_sigbus:
si.si_signo = SIGBUS;
si.si_errno = 0;
si.si_code = BUS_ADRALN;
- si.si_addr = (void *)regs->ior;
+ si.si_addr = (void __user *)regs->ior;
force_sig_info(SIGBUS, &si, current);
}
diff --git a/arch/parisc/lib/checksum.c b/arch/parisc/lib/checksum.c
index 9866c93f1e6f..8a1e08068e7d 100644
--- a/arch/parisc/lib/checksum.c
+++ b/arch/parisc/lib/checksum.c
@@ -131,9 +131,9 @@ EXPORT_SYMBOL(csum_partial_copy_nocheck);
* Copy from userspace and compute checksum. If we catch an exception
* then zero the rest of the buffer.
*/
-unsigned int csum_partial_copy_from_user (const unsigned char *src, unsigned char *dst,
- int len, unsigned int sum,
- int *err_ptr)
+unsigned int csum_partial_copy_from_user(const unsigned char __user *src,
+ unsigned char *dst, int len,
+ unsigned int sum, int *err_ptr)
{
int missing;
diff --git a/arch/parisc/math-emu/driver.c b/arch/parisc/math-emu/driver.c
index e202c240f06f..09ef4136c693 100644
--- a/arch/parisc/math-emu/driver.c
+++ b/arch/parisc/math-emu/driver.c
@@ -27,7 +27,6 @@
* Copyright (C) 2001 Hewlett-Packard <bame@debian.org>
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include "float.h"
#include "math-emu.h"
@@ -120,7 +119,7 @@ handle_fpe(struct pt_regs *regs)
si.si_signo = signalcode >> 24;
si.si_errno = 0;
si.si_code = signalcode & 0xffffff;
- si.si_addr = (void *) regs->iaoq[0];
+ si.si_addr = (void __user *) regs->iaoq[0];
force_sig_info(si.si_signo, &si, current);
return -1;
}
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c
index fd1c77280b35..eaa701479f5f 100644
--- a/arch/parisc/mm/fault.c
+++ b/arch/parisc/mm/fault.c
@@ -225,7 +225,7 @@ bad_area:
si.si_signo = SIGSEGV;
si.si_errno = 0;
si.si_code = SEGV_MAPERR;
- si.si_addr = (void *) address;
+ si.si_addr = (void __user *) address;
force_sig_info(SIGSEGV, &si, current);
return;
}
diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c
index fb625b49b831..17f02aa95271 100644
--- a/drivers/block/as-iosched.c
+++ b/drivers/block/as-iosched.c
@@ -1463,35 +1463,36 @@ static void as_add_request(struct as_data *ad, struct as_rq *arq)
arq->state = AS_RQ_QUEUED;
}
-/*
- * requeue the request. The request has not been completed, nor is it a
- * new request, so don't touch accounting.
- */
-static void as_requeue_request(request_queue_t *q, struct request *rq)
+static void as_deactivate_request(request_queue_t *q, struct request *rq)
{
struct as_data *ad = q->elevator->elevator_data;
struct as_rq *arq = RQ_DATA(rq);
if (arq) {
- if (arq->state != AS_RQ_REMOVED) {
- printk("arq->state %d\n", arq->state);
- WARN_ON(1);
+ if (arq->state == AS_RQ_REMOVED) {
+ arq->state = AS_RQ_DISPATCHED;
+ if (arq->io_context && arq->io_context->aic)
+ atomic_inc(&arq->io_context->aic->nr_dispatched);
}
-
- arq->state = AS_RQ_DISPATCHED;
- if (arq->io_context && arq->io_context->aic)
- atomic_inc(&arq->io_context->aic->nr_dispatched);
} else
WARN_ON(blk_fs_request(rq)
&& (!(rq->flags & (REQ_HARDBARRIER|REQ_SOFTBARRIER))) );
- list_add(&rq->queuelist, ad->dispatch);
-
/* Stop anticipating - let this request get through */
as_antic_stop(ad);
}
/*
+ * requeue the request. The request has not been completed, nor is it a
+ * new request, so don't touch accounting.
+ */
+static void as_requeue_request(request_queue_t *q, struct request *rq)
+{
+ as_deactivate_request(q, rq);
+ list_add(&rq->queuelist, &q->queue_head);
+}
+
+/*
* Account a request that is inserted directly onto the dispatch queue.
* arq->io_context->aic->nr_dispatched should not need to be incremented
* because only new requests should come through here: requeues go through
@@ -2080,6 +2081,7 @@ static struct elevator_type iosched_as = {
.elevator_add_req_fn = as_insert_request,
.elevator_remove_req_fn = as_remove_request,
.elevator_requeue_req_fn = as_requeue_request,
+ .elevator_deactivate_req_fn = as_deactivate_request,
.elevator_queue_empty_fn = as_queue_empty,
.elevator_completed_req_fn = as_completed_request,
.elevator_former_req_fn = as_former_request,
diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c
index 4234508565d6..d9aaa42500d0 100644
--- a/drivers/block/cfq-iosched.c
+++ b/drivers/block/cfq-iosched.c
@@ -607,10 +607,7 @@ out:
return NULL;
}
-/*
- * make sure the service time gets corrected on reissue of this request
- */
-static void cfq_requeue_request(request_queue_t *q, struct request *rq)
+static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
{
struct cfq_rq *crq = RQ_DATA(rq);
@@ -627,6 +624,14 @@ static void cfq_requeue_request(request_queue_t *q, struct request *rq)
cfqq->cfqd->rq_in_driver--;
}
}
+}
+
+/*
+ * make sure the service time gets corrected on reissue of this request
+ */
+static void cfq_requeue_request(request_queue_t *q, struct request *rq)
+{
+ cfq_deactivate_request(q, rq);
list_add(&rq->queuelist, &q->queue_head);
}
@@ -1804,6 +1809,7 @@ static struct elevator_type iosched_cfq = {
.elevator_add_req_fn = cfq_insert_request,
.elevator_remove_req_fn = cfq_remove_request,
.elevator_requeue_req_fn = cfq_requeue_request,
+ .elevator_deactivate_req_fn = cfq_deactivate_request,
.elevator_queue_empty_fn = cfq_queue_empty,
.elevator_completed_req_fn = cfq_completed_request,
.elevator_former_req_fn = cfq_former_request,
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
index 241fdbcb29bc..85c72dd3dfee 100644
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -255,8 +255,16 @@ void elv_merge_requests(request_queue_t *q, struct request *rq,
e->ops->elevator_merge_req_fn(q, rq, next);
}
-void elv_requeue_request(request_queue_t *q, struct request *rq)
+/*
+ * For careful internal use by the block layer. Essentially the same as
+ * a requeue in that it tells the io scheduler that this request is not
+ * active in the driver or hardware anymore, but we don't want the request
+ * added back to the scheduler. Function is not exported.
+ */
+void elv_deactivate_request(request_queue_t *q, struct request *rq)
{
+ elevator_t *e = q->elevator;
+
/*
* it already went through dequeue, we need to decrement the
* in_flight count again
@@ -264,6 +272,24 @@ void elv_requeue_request(request_queue_t *q, struct request *rq)
if (blk_account_rq(rq))
q->in_flight--;
+ rq->flags &= ~REQ_STARTED;
+
+ if (e->ops->elevator_deactivate_req_fn)
+ e->ops->elevator_deactivate_req_fn(q, rq);
+}
+
+void elv_requeue_request(request_queue_t *q, struct request *rq)
+{
+ elv_deactivate_request(q, rq);
+
+ /*
+ * if this is the flush, requeue the original instead and drop the flush
+ */
+ if (rq->flags & REQ_BAR_FLUSH) {
+ clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags);
+ rq = rq->end_io_data;
+ }
+
/*
* if iosched has an explicit requeue hook, then use that. otherwise
* just put the request at the front of the queue
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 28977a7bad16..0135ec79dc83 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -356,6 +356,7 @@ static void blk_pre_flush_end_io(struct request *flush_rq)
else {
q->end_flush_fn(q, flush_rq);
clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags);
+ q->request_fn(q);
}
}
@@ -366,15 +367,9 @@ static void blk_post_flush_end_io(struct request *flush_rq)
rq->flags |= REQ_BAR_POSTFLUSH;
- /*
- * called from end_that_request_last(), so we know that the queue
- * lock is held
- */
- spin_unlock(q->queue_lock);
q->end_flush_fn(q, flush_rq);
- spin_lock(q->queue_lock);
-
clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags);
+ q->request_fn(q);
}
struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq)
@@ -383,9 +378,12 @@ struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq)
BUG_ON(!blk_barrier_rq(rq));
+ if (test_and_set_bit(QUEUE_FLAG_FLUSH, &q->queue_flags))
+ return NULL;
+
rq_init(q, flush_rq);
flush_rq->elevator_private = NULL;
- flush_rq->flags = 0;
+ flush_rq->flags = REQ_BAR_FLUSH;
flush_rq->rq_disk = rq->rq_disk;
flush_rq->rl = NULL;
@@ -395,11 +393,10 @@ struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq)
*/
if (!q->prepare_flush_fn(q, flush_rq)) {
rq->flags |= REQ_BAR_PREFLUSH | REQ_BAR_POSTFLUSH;
+ clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags);
return rq;
}
- set_bit(QUEUE_FLAG_FLUSH, &q->queue_flags);
-
/*
* some drivers dequeue requests right away, some only after io
* completion. make sure the request is dequeued.
@@ -407,6 +404,8 @@ struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq)
if (!list_empty(&rq->queuelist))
blkdev_dequeue_request(rq);
+ elv_deactivate_request(q, rq);
+
flush_rq->end_io_data = rq;
flush_rq->end_io = blk_pre_flush_end_io;
@@ -422,7 +421,7 @@ static void blk_start_post_flush(request_queue_t *q, struct request *rq)
rq_init(q, flush_rq);
flush_rq->elevator_private = NULL;
- flush_rq->flags = 0;
+ flush_rq->flags = REQ_BAR_FLUSH;
flush_rq->rq_disk = rq->rq_disk;
flush_rq->rl = NULL;
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 913f49e56a93..c42d7e6ac1c5 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -63,7 +63,7 @@ MODULE_DEVICE_TABLE(usb, bfusb_table);
#define BFUSB_MAX_BLOCK_SIZE 256
-#define BFUSB_BLOCK_TIMEOUT (HZ * 3)
+#define BFUSB_BLOCK_TIMEOUT 3000
#define BFUSB_TX_PROCESS 1
#define BFUSB_TX_WAKEUP 2
@@ -582,7 +582,7 @@ static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int
pipe = usb_sndctrlpipe(bfusb->udev, 0);
if (usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
- 0, 1, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT) < 0) {
+ 0, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT) < 0) {
BT_ERR("Can't change to loading configuration");
return -EBUSY;
}
@@ -623,7 +623,7 @@ static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int
pipe = usb_sndctrlpipe(bfusb->udev, 0);
if ((err = usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
- 0, 2, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0) {
+ 0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
BT_ERR("Can't change to running configuration");
goto error;
}
@@ -641,7 +641,7 @@ error:
pipe = usb_sndctrlpipe(bfusb->udev, 0);
usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
- 0, 0, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+ 0, 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
return err;
}
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index 42bce3eea236..7106c15d7a30 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -227,7 +227,7 @@ static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd, unsigned cha
if (usb_control_msg(usb_pcwd->udev, usb_sndctrlpipe(usb_pcwd->udev, 0),
HID_REQ_SET_REPORT, HID_DT_REPORT,
0x0200, usb_pcwd->interface_number, buf, sizeof(buf),
- HZ) != sizeof(buf)) {
+ 1000) != sizeof(buf)) {
dbg("usb_pcwd_send_command: error in usb_control_msg for cmd 0x%x 0x%x 0x%x\n", cmd, *msb, *lsb);
}
/* wait till the usb card processed the command,
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 36b90f85968c..c256feebd1bd 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -712,12 +712,13 @@ static void idedisk_end_flush(request_queue_t *q, struct request *flush_rq)
blk_queue_issue_flush_fn(drive->queue, NULL);
good_sectors = 0;
} else if (flush_rq->errors) {
- sector = ide_get_error_location(drive, flush_rq->buffer);
- if ((sector >= rq->hard_sector) &&
- (sector < rq->hard_sector + rq->hard_nr_sectors))
- good_sectors = sector - rq->hard_sector;
- else
- good_sectors = 0;
+ good_sectors = 0;
+ if (blk_barrier_preflush(rq)) {
+ sector = ide_get_error_location(drive,flush_rq->buffer);
+ if ((sector >= rq->hard_sector) &&
+ (sector < rq->hard_sector + rq->hard_nr_sectors))
+ good_sectors = sector - rq->hard_sector;
+ }
}
if (flush_rq->errors)
@@ -729,14 +730,10 @@ static void idedisk_end_flush(request_queue_t *q, struct request *flush_rq)
bad_sectors = rq->hard_nr_sectors - good_sectors;
- spin_lock(&ide_lock);
-
if (good_sectors)
__ide_end_request(drive, rq, 1, good_sectors);
if (bad_sectors)
__ide_end_request(drive, rq, 0, bad_sectors);
-
- spin_unlock(&ide_lock);
}
static int idedisk_prepare_flush(request_queue_t *q, struct request *rq)
@@ -1150,9 +1147,6 @@ static void idedisk_setup (ide_drive_t *drive)
barrier = 0;
}
- if (!strncmp(drive->name, "hdc", 3))
- barrier = 1;
-
printk(KERN_INFO "%s: cache flushes %ssupported\n",
drive->name, barrier ? "" : "not ");
if (barrier) {
diff --git a/drivers/media/dvb/b2c2/b2c2-usb-core.c b/drivers/media/dvb/b2c2/b2c2-usb-core.c
index 6cc0502f43a4..aa5c0f11e5cc 100644
--- a/drivers/media/dvb/b2c2/b2c2-usb-core.c
+++ b/drivers/media/dvb/b2c2/b2c2-usb-core.c
@@ -194,7 +194,7 @@ static u32 b2c2_usb_read_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI)
0,
&val,
sizeof(u32),
- B2C2_WAIT_FOR_OPERATION_RDW * HZ);
+ B2C2_WAIT_FOR_OPERATION_RDW * 1000);
if (len != sizeof(u32)) {
err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI);
@@ -220,7 +220,7 @@ static int b2c2_usb_write_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI, u32 val
0,
&val,
sizeof(u32),
- B2C2_WAIT_FOR_OPERATION_RDW * HZ);
+ B2C2_WAIT_FOR_OPERATION_RDW * 1000);
if (len != sizeof(u32)) {
err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI);
@@ -270,7 +270,7 @@ static int b2c2_usb_v8_memory_req(struct usb_b2c2_usb *b2c2,
wIndex,
pbBuffer,
buflen,
- nWaitTime * HZ);
+ nWaitTime * 1000);
return len == buflen ? 0 : -EIO;
}
@@ -312,7 +312,7 @@ static int b2c2_usb_i2c_req(struct usb_b2c2_usb *b2c2,
wIndex,
buf,
buflen,
- nWaitTime * HZ);
+ nWaitTime * 1000);
return len == buflen ? 0 : -EIO;
}
@@ -334,7 +334,7 @@ int static b2c2_usb_utility_req(struct usb_b2c2_usb *b2c2, int set,
wIndex,
pvBuffer,
buflen,
- nWaitTime * HZ);
+ nWaitTime * 1000);
return len == buflen ? 0 : -EIO;
}
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 644d9241c10d..2a5be36253fe 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -212,7 +212,7 @@ static int cinergyt2_command (struct cinergyt2 *cinergyt2,
int ret;
ret = usb_bulk_msg(cinergyt2->udev, usb_sndbulkpipe(cinergyt2->udev, 1),
- send_buf, send_buf_len, &actual_len, HZ);
+ send_buf, send_buf_len, &actual_len, 1000);
if (ret)
dprintk(1, "usb_bulk_msg (send) failed, err %i\n", ret);
@@ -221,7 +221,7 @@ static int cinergyt2_command (struct cinergyt2 *cinergyt2,
recv_buf = &dummy;
ret = usb_bulk_msg(cinergyt2->udev, usb_rcvbulkpipe(cinergyt2->udev, 1),
- recv_buf, recv_buf_len, &actual_len, HZ);
+ recv_buf, recv_buf_len, &actual_len, 1000);
if (ret)
dprintk(1, "usb_bulk_msg (read) failed, err %i\n", ret);
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c b/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
index 972548a0c8c4..708ec7370142 100644
--- a/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
@@ -19,7 +19,7 @@
static int dibusb_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
{
return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
- 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ);
+ 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
}
int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev)
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb.h b/drivers/media/dvb/dibusb/dvb-dibusb.h
index 914a010a13b2..47be677a3db8 100644
--- a/drivers/media/dvb/dibusb/dvb-dibusb.h
+++ b/drivers/media/dvb/dibusb/dvb-dibusb.h
@@ -236,7 +236,7 @@ void dibusb_pid_list_exit(struct usb_dibusb *dib);
int dibusb_ctrl_pid(struct usb_dibusb *dib, struct dvb_demux_feed *dvbdmxfeed , int onoff);
/* i2c and transfer stuff */
-#define DIBUSB_I2C_TIMEOUT HZ*5
+#define DIBUSB_I2C_TIMEOUT 5000
/*
* protocol of all dibusb related devices
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 5ea692d464e0..2c5d1bd9aa50 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -162,7 +162,7 @@ static int ttusb_cmd(struct ttusb *ttusb,
return -EAGAIN;
err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe,
- (u8 *) data, len, &actual_len, HZ);
+ (u8 *) data, len, &actual_len, 1000);
if (err != 0) {
dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n",
__FUNCTION__, err);
@@ -177,7 +177,7 @@ static int ttusb_cmd(struct ttusb *ttusb,
}
err = usb_bulk_msg(ttusb->dev, ttusb->bulk_in_pipe,
- ttusb->last_result, 32, &actual_len, HZ);
+ ttusb->last_result, 32, &actual_len, 1000);
if (err != 0) {
printk("%s: failed, receive error %d\n", __FUNCTION__,
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index f85069f8b219..6f29185bf2f3 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -208,7 +208,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
}
result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
- COMMAND_PACKET_SIZE + 4, &actual_len, HZ);
+ COMMAND_PACKET_SIZE + 4, &actual_len, 1000);
if (result) {
printk("%s: command bulk message failed: error %d\n",
@@ -219,7 +219,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
}
result = usb_bulk_msg(dec->udev, dec->result_pipe, b,
- COMMAND_PACKET_SIZE + 4, &actual_len, HZ);
+ COMMAND_PACKET_SIZE + 4, &actual_len, 1000);
if (result) {
printk("%s: result bulk message failed: error %d\n",
@@ -1205,12 +1205,12 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
if (j >= ARM_PACKET_SIZE) {
result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
ARM_PACKET_SIZE, &actual_len,
- HZ / 10);
+ 100);
j = 0;
} else if (size < COMMAND_PACKET_SIZE) {
result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
j - COMMAND_PACKET_SIZE + size,
- &actual_len, HZ / 10);
+ &actual_len, 100);
}
}
diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
index 0bf9349db870..337ceeb50c5a 100644
--- a/drivers/media/video/cpia_usb.c
+++ b/drivers/media/video/cpia_usb.c
@@ -308,7 +308,7 @@ static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_
packet[1] + (packet[0] << 8),
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
packet[2] + (packet[3] << 8),
- packet[4] + (packet[5] << 8), buf, size, HZ);
+ packet[4] + (packet[5] << 8), buf, size, 1000);
}
/****************************************************************************
@@ -325,7 +325,7 @@ static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size)
packet[1] + (packet[0] << 8),
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
packet[2] + (packet[3] << 8),
- packet[4] + (packet[5] << 8), buf, size, HZ);
+ packet[4] + (packet[5] << 8), buf, size, 1000);
}
static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data)
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 9e93080d2a13..fd0e49e393d7 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1308,7 +1308,7 @@ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_interf
IU_REQ_GET_CLASS_DESC,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, intf->altsetting->desc.bInterfaceNumber, desc,
- sizeof(*desc), msecs_to_jiffies(500));
+ sizeof(*desc), 500);
IRDA_DEBUG(1, "%s(), ret=%d\n", __FUNCTION__, ret);
if (ret < sizeof(*desc)) {
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 648a7134ba77..fe4e043237a7 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -208,7 +208,7 @@ static int write_reg(struct stir_cb *stir, __u16 reg, __u8 value)
REQ_WRITE_SINGLE,
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE,
value, reg, NULL, 0,
- msecs_to_jiffies(CTRL_TIMEOUT));
+ CTRL_TIMEOUT);
}
/* Send control message to read multiple registers */
@@ -221,7 +221,7 @@ static inline int read_reg(struct stir_cb *stir, __u16 reg,
REQ_READ_REG,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, reg, data, count,
- msecs_to_jiffies(CTRL_TIMEOUT));
+ CTRL_TIMEOUT);
}
static inline int isfir(u32 speed)
@@ -740,7 +740,7 @@ static void stir_send(struct stir_cb *stir, struct sk_buff *skb)
if (usb_bulk_msg(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1),
stir->io_buf, wraplen,
- NULL, msecs_to_jiffies(TRANSMIT_TIMEOUT)))
+ NULL, TRANSMIT_TIMEOUT))
stir->stats.tx_errors++;
}
diff --git a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c
index d16724dbe890..ea9ebc7f2c24 100644
--- a/drivers/parisc/eisa_eeprom.c
+++ b/drivers/parisc/eisa_eeprom.c
@@ -19,7 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
index 17960846935e..3c3dbc59051a 100644
--- a/drivers/parisc/gsc.c
+++ b/drivers/parisc/gsc.c
@@ -38,14 +38,14 @@
int gsc_alloc_irq(struct gsc_irq *i)
{
- int irq = txn_alloc_irq();
+ int irq = txn_alloc_irq(GSC_EIM_WIDTH);
if (irq < 0) {
printk("cannot get irq\n");
return irq;
}
i->txn_addr = txn_alloc_addr(irq);
- i->txn_data = txn_alloc_data(irq, GSC_EIM_WIDTH);
+ i->txn_data = txn_alloc_data(irq);
i->irq = irq;
return irq;
@@ -64,7 +64,7 @@ int gsc_claim_irq(struct gsc_irq *i, int irq)
}
i->txn_addr = txn_alloc_addr(irq);
- i->txn_data = txn_alloc_data(irq, GSC_EIM_WIDTH);
+ i->txn_data = txn_alloc_data(irq);
i->irq = irq;
return irq;
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
index 8bda8bb50815..e869c6020370 100644
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -16,7 +16,6 @@
**
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/mm.h>
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index cabb91fff0d9..42efe218867a 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -38,7 +38,7 @@ static struct pcmcia_irqs irqs[] = {
static void sharpsl_pcmcia_init_reset(void)
{
- reset_scoop();
+ reset_scoop(&corgiscoop_device.dev);
keep_vs = NO_KEEP_VS;
keep_rd = 0;
}
@@ -79,8 +79,8 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
}
/* Enable interrupt */
- write_scoop_reg(SCOOP_IMR, 0x00C0);
- write_scoop_reg(SCOOP_MCR, 0x0101);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, 0x00C0);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, 0x0101);
keep_vs = NO_KEEP_VS;
skt->irq = CORGI_IRQ_GPIO_CF_IRQ;
@@ -102,30 +102,30 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
{
unsigned short cpr, csr;
- cpr = read_scoop_reg(SCOOP_CPR);
+ cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR);
- write_scoop_reg(SCOOP_IRM, 0x00FF);
- write_scoop_reg(SCOOP_ISR, 0x0000);
- write_scoop_reg(SCOOP_IRM, 0x0000);
- csr = read_scoop_reg(SCOOP_CSR);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x00FF);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_ISR, 0x0000);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x0000);
+ csr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CSR);
if (csr & 0x0004) {
/* card eject */
- write_scoop_reg(SCOOP_CDR, 0x0000);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000);
keep_vs = NO_KEEP_VS;
}
else if (!(keep_vs & NO_KEEP_VS)) {
/* keep vs1,vs2 */
- write_scoop_reg(SCOOP_CDR, 0x0000);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000);
csr |= keep_vs;
}
else if (cpr & 0x0003) {
/* power on */
- write_scoop_reg(SCOOP_CDR, 0x0000);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000);
keep_vs = (csr & 0x00C0);
}
else {
/* card detect */
- write_scoop_reg(SCOOP_CDR, 0x0002);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0002);
}
state->detect = (csr & 0x0004) ? 0 : 1;
@@ -166,10 +166,10 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
local_irq_save(flags);
- nmcr = (mcr = read_scoop_reg(SCOOP_MCR)) & ~0x0010;
- ncpr = (cpr = read_scoop_reg(SCOOP_CPR)) & ~0x0083;
- nccr = (ccr = read_scoop_reg(SCOOP_CCR)) & ~0x0080;
- nimr = (imr = read_scoop_reg(SCOOP_IMR)) & ~0x003E;
+ nmcr = (mcr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR)) & ~0x0010;
+ ncpr = (cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR)) & ~0x0083;
+ nccr = (ccr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR)) & ~0x0080;
+ nimr = (imr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR)) & ~0x003E;
ncpr |= (state->Vcc == 33) ? 0x0001 :
(state->Vcc == 50) ? 0x0002 : 0;
@@ -193,13 +193,13 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
}
if (mcr != nmcr)
- write_scoop_reg(SCOOP_MCR, nmcr);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, nmcr);
if (cpr != ncpr)
- write_scoop_reg(SCOOP_CPR, ncpr);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR, ncpr);
if (ccr != nccr)
- write_scoop_reg(SCOOP_CCR, nccr);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR, nccr);
if (imr != nimr)
- write_scoop_reg(SCOOP_IMR, nimr);
+ write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, nimr);
local_irq_restore(flags);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index e8405375877f..da63045c165d 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -697,7 +697,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
int sense_valid = 0;
int sense_deferred = 0;
- if (blk_complete_barrier_rq(q, req, good_bytes << 9))
+ if (blk_complete_barrier_rq(q, req, good_bytes >> 9))
return;
/*
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index fe8a079b00fb..0fb36703292f 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -745,10 +745,21 @@ static void sd_end_flush(request_queue_t *q, struct request *flush_rq)
struct scsi_cmnd *cmd = rq->special;
unsigned int bytes = rq->hard_nr_sectors << 9;
- if (!flush_rq->errors)
+ if (!flush_rq->errors) {
+ spin_unlock(q->queue_lock);
scsi_io_completion(cmd, bytes, 0);
- else
+ spin_lock(q->queue_lock);
+ } else if (blk_barrier_postflush(rq)) {
+ spin_unlock(q->queue_lock);
scsi_io_completion(cmd, 0, bytes);
+ spin_lock(q->queue_lock);
+ } else {
+ /*
+ * force journal abort of barriers
+ */
+ end_that_request_first(rq, -EOPNOTSUPP, rq->hard_nr_sectors);
+ end_that_request_last(rq);
+ }
}
static int sd_prepare_flush(request_queue_t *q, struct request *rq)
@@ -758,7 +769,8 @@ static int sd_prepare_flush(request_queue_t *q, struct request *rq)
if (sdkp->WCE) {
memset(rq->cmd, 0, sizeof(rq->cmd));
- rq->flags = REQ_BLOCK_PC | REQ_SOFTBARRIER;
+ rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
+ rq->timeout = SD_TIMEOUT;
rq->cmd[0] = SYNCHRONIZE_CACHE;
return 1;
}
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index c888efa1d0f2..0f0c7e1690dc 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -729,6 +729,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
status2 = serial_in(up, UART_IIR) >> 5;
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_outp(up, UART_LCR, 0);
DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2);
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index e99ffdd81cce..df737ae8b314 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -1759,7 +1759,7 @@ static void __devexit pciserial_remove_one(struct pci_dev *dev)
}
}
-static int pciserial_suspend_one(struct pci_dev *dev, u32 state)
+static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
{
struct serial_private *priv = pci_get_drvdata(dev);
@@ -1769,6 +1769,8 @@ static int pciserial_suspend_one(struct pci_dev *dev, u32 state)
for (i = 0; i < priv->nr; i++)
serial8250_suspend_port(priv->line[i]);
}
+ pci_save_state(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
return 0;
}
@@ -1776,10 +1778,18 @@ static int pciserial_resume_one(struct pci_dev *dev)
{
struct serial_private *priv = pci_get_drvdata(dev);
+ pci_set_power_state(dev, PCI_D0);
+ pci_restore_state(dev);
+
if (priv) {
int i;
/*
+ * The device may have been disabled. Re-enable it.
+ */
+ pci_enable_device(dev);
+
+ /*
* Ensure that the board is correctly configured.
*/
if (priv->quirk->init)
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index e22a84223afb..c8287fd121a4 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -56,6 +56,8 @@ source "drivers/usb/media/Kconfig"
source "drivers/usb/net/Kconfig"
+source "drivers/usb/mon/Kconfig"
+
comment "USB port drivers"
depends on USB
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index aa790f1a3ef1..f250c8a7dd75 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -6,6 +6,8 @@
obj-$(CONFIG_USB) += core/
+obj-$(CONFIG_USB_MON) += mon/
+
obj-$(CONFIG_USB_EHCI_HCD) += host/
obj-$(CONFIG_USB_OHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI_HCD) += host/
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 76b45b1d6609..233f9229badb 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -58,8 +58,8 @@ static const char speedtch_driver_name[] = "speedtch";
#define SPEEDTOUCH_PRODUCTID 0x4061
/* Timeout in jiffies */
-#define CTRL_TIMEOUT (2*HZ)
-#define DATA_TIMEOUT (2*HZ)
+#define CTRL_TIMEOUT 2000
+#define DATA_TIMEOUT 2000
#define OFFSET_7 0 /* size 1 */
#define OFFSET_b 1 /* size 8 */
@@ -474,7 +474,7 @@ static void speedtch_upload_firmware(struct speedtch_instance_data *instance,
/* URB 7 */
if (dl_512_first) { /* some modems need a read before writing the firmware */
ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
- buffer, 0x200, &actual_length, 2 * HZ);
+ buffer, 0x200, &actual_length, 2000);
if (ret < 0 && ret != -ETIMEDOUT)
dbg("speedtch_upload_firmware: read BLOCK0 from modem failed (%d)!", ret);
@@ -766,7 +766,7 @@ static int speedtch_usb_probe(struct usb_interface *intf,
/* First check whether the modem already seems to be alive */
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- 0x12, 0xc0, 0x07, 0x00, buf7, SIZE_7, HZ / 2);
+ 0x12, 0xc0, 0x07, 0x00, buf7, SIZE_7, 500);
if (ret == SIZE_7) {
dbg("firmware appears to be already loaded");
diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c
index e5b6194bbb4b..f432b7d5b235 100644
--- a/drivers/usb/class/audio.c
+++ b/drivers/usb/class/audio.c
@@ -1561,7 +1561,7 @@ static int set_format_in(struct usb_audiodev *as)
if (fmt->attributes & 0x02) {
data[0] = 1;
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
- PITCH_CONTROL << 8, ep, data, 1, HZ)) < 0) {
+ PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
ret, dev->devnum, u->interface, ep, d->srate);
return -1;
@@ -1573,13 +1573,13 @@ static int set_format_in(struct usb_audiodev *as)
data[1] = d->srate >> 8;
data[2] = d->srate >> 16;
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
- SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+ SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
printk(KERN_ERR "usbaudio: failure (error %d) to set input sampling frequency device %d interface %u endpoint 0x%x to %u\n",
ret, dev->devnum, u->interface, ep, d->srate);
return -1;
}
if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
- SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+ SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
printk(KERN_ERR "usbaudio: failure (error %d) to get input sampling frequency device %d interface %u endpoint 0x%x\n",
ret, dev->devnum, u->interface, ep);
return -1;
@@ -1657,7 +1657,7 @@ static int set_format_out(struct usb_audiodev *as)
if (fmt->attributes & 0x02) {
data[0] = 1;
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
- PITCH_CONTROL << 8, ep, data, 1, HZ)) < 0) {
+ PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
ret, dev->devnum, u->interface, ep, d->srate);
return -1;
@@ -1669,13 +1669,13 @@ static int set_format_out(struct usb_audiodev *as)
data[1] = d->srate >> 8;
data[2] = d->srate >> 16;
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
- SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+ SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
printk(KERN_ERR "usbaudio: failure (error %d) to set output sampling frequency device %d interface %u endpoint 0x%x to %u\n",
ret, dev->devnum, u->interface, ep, d->srate);
return -1;
}
if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
- SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+ SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
printk(KERN_ERR "usbaudio: failure (error %d) to get output sampling frequency device %d interface %u endpoint 0x%x\n",
ret, dev->devnum, u->interface, ep);
return -1;
@@ -1754,7 +1754,7 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
data[0] = v1;
data[1] = v1 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+ (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
goto err;
if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
return 0;
@@ -1762,7 +1762,7 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
data[1] = v2 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
- ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+ ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
goto err;
return 0;
@@ -1771,14 +1771,14 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
data[0] = v1;
data[1] = v1 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+ (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
goto err;
if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
return 0;
data[0] = v2;
data[1] = v2 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+ (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
goto err;
return 0;
@@ -1787,13 +1787,13 @@ static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
case TREBLE_CONTROL:
data[0] = v1 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
+ (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, 1000) < 0)
goto err;
if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
return 0;
data[0] = v2 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
+ (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, 1000) < 0)
goto err;
return 0;
@@ -1820,7 +1820,7 @@ static int get_rec_src(struct usb_mixerdev *ms)
if (!ms->ch[i].slctunitid || (mask & (1 << i)))
continue;
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- 0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) {
+ 0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, 1000) < 0) {
err = -EIO;
printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n",
dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
@@ -1851,7 +1851,7 @@ static int set_rec_src(struct usb_mixerdev *ms, int srcmask)
if (!ms->ch[i].slctunitid || (mask & (1 << i)))
continue;
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- 0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) {
+ 0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, 1000) < 0) {
err = -EIO;
printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n",
dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
@@ -1880,7 +1880,7 @@ static int set_rec_src(struct usb_mixerdev *ms, int srcmask)
continue;
buf = ms->ch[j].slctunitid >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- 0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, HZ) < 0) {
+ 0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, 1000) < 0) {
err = -EIO;
printk(KERN_ERR "usbaudio: selector write request device %u if %u unit %u failed\n",
dev->devnum, ms->iface, ms->ch[j].slctunitid & 0xff);
@@ -3136,18 +3136,18 @@ static void prepmixch(struct consmixstate *state)
switch (ch->selector) {
case 0: /* mixer unit request */
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
goto err;
ch->minval = buf[0] | (buf[1] << 8);
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
goto err;
ch->maxval = buf[0] | (buf[1] << 8);
v2 = ch->maxval - ch->minval;
if (!v2)
v2 = 1;
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
goto err;
v1 = buf[0] | (buf[1] << 8);
v3 = v1 - ch->minval;
@@ -3158,7 +3158,7 @@ static void prepmixch(struct consmixstate *state)
if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
- state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
goto err;
v1 = buf[0] | (buf[1] << 8);
v3 = v1 - ch->minval;
@@ -3172,15 +3172,15 @@ static void prepmixch(struct consmixstate *state)
/* various feature unit controls */
case VOLUME_CONTROL:
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
goto err;
ch->minval = buf[0] | (buf[1] << 8);
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
goto err;
ch->maxval = buf[0] | (buf[1] << 8);
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
goto err;
v1 = buf[0] | (buf[1] << 8);
v2 = ch->maxval - ch->minval;
@@ -3193,7 +3193,7 @@ static void prepmixch(struct consmixstate *state)
ch->value = v3;
if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
goto err;
v1 = buf[0] | (buf[1] << 8);
v3 = v1 - ch->minval;
@@ -3208,15 +3208,15 @@ static void prepmixch(struct consmixstate *state)
case MID_CONTROL:
case TREBLE_CONTROL:
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+ (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
goto err;
ch->minval = buf[0] << 8;
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+ (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
goto err;
ch->maxval = buf[0] << 8;
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+ (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
goto err;
v1 = buf[0] << 8;
v2 = ch->maxval - ch->minval;
@@ -3229,7 +3229,7 @@ static void prepmixch(struct consmixstate *state)
ch->value = v3;
if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+ (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
goto err;
v1 = buf[0] << 8;
v3 = v1 - ch->minval;
@@ -3522,7 +3522,7 @@ static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr
printk(KERN_DEBUG "usbaudio: unmuting feature unit %u interface %u\n", ftr[3], state->ctrlif);
data[0] = 0;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- (MUTE_CONTROL << 8) | 0xff, state->ctrlif | (ftr[3] << 8), data, 1, HZ) < 0)
+ (MUTE_CONTROL << 8) | 0xff, state->ctrlif | (ftr[3] << 8), data, 1, 1000) < 0)
printk(KERN_WARNING "usbaudio: failure to unmute feature unit %u interface %u\n", ftr[3], state->ctrlif);
}
#endif
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 761b4d91ceb2..6d1f9b6aecff 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -60,6 +60,7 @@
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
+#include <linux/usb_cdc.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
@@ -89,7 +90,7 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int
int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
request, USB_RT_ACM, value,
acm->control->altsetting[0].desc.bInterfaceNumber,
- buf, len, HZ * 5);
+ buf, len, 5000);
dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
return retval < 0 ? retval : 0;
}
@@ -97,9 +98,12 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int
/* devices aren't required to support these requests.
* the cdc acm descriptor tells whether they do...
*/
-#define acm_set_control(acm, control) acm_ctrl_msg(acm, ACM_REQ_SET_CONTROL, control, NULL, 0)
-#define acm_set_line(acm, line) acm_ctrl_msg(acm, ACM_REQ_SET_LINE, 0, line, sizeof(struct acm_line))
-#define acm_send_break(acm, ms) acm_ctrl_msg(acm, ACM_REQ_SEND_BREAK, ms, NULL, 0)
+#define acm_set_control(acm, control) \
+ acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
+#define acm_set_line(acm, line) \
+ acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
+#define acm_send_break(acm, ms) \
+ acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
/*
* Interrupt handlers for various ACM device responses
@@ -109,7 +113,7 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int
static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs)
{
struct acm *acm = urb->context;
- struct usb_ctrlrequest *dr = urb->transfer_buffer;
+ struct usb_cdc_notification *dr = urb->transfer_buffer;
unsigned char *data;
int newctrl;
int status;
@@ -133,14 +137,14 @@ static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs)
goto exit;
data = (unsigned char *)(dr + 1);
- switch (dr->bRequest) {
+ switch (dr->bNotificationType) {
- case ACM_IRQ_NETWORK:
+ case USB_CDC_NOTIFY_NETWORK_CONNECTION:
dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
break;
- case ACM_IRQ_LINE_STATE:
+ case USB_CDC_NOTIFY_SERIAL_STATE:
newctrl = le16_to_cpu(get_unaligned((__le16 *) data));
@@ -160,8 +164,9 @@ static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs)
break;
default:
- dbg("unknown control event received: request %d index %d len %d data0 %d data1 %d",
- dr->bRequest, dr->wIndex, dr->wLength, data[0], data[1]);
+ dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
+ dr->bNotificationType, dr->wIndex,
+ dr->wLength, data[0], data[1]);
break;
}
exit:
@@ -485,32 +490,34 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_
{
struct acm *acm = tty->driver_data;
struct termios *termios = tty->termios;
- struct acm_line newline;
+ struct usb_cdc_line_coding newline;
int newctrl = acm->ctrlout;
if (!ACM_READY(acm))
return;
- newline.speed = cpu_to_le32p(acm_tty_speed +
+ newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
(termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
- newline.stopbits = termios->c_cflag & CSTOPB ? 2 : 0;
- newline.parity = termios->c_cflag & PARENB ?
+ newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
+ newline.bParityType = termios->c_cflag & PARENB ?
(termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
- newline.databits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
+ newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
- if (!newline.speed) {
- newline.speed = acm->line.speed;
+ if (!newline.dwDTERate) {
+ newline.dwDTERate = acm->line.dwDTERate;
newctrl &= ~ACM_CTRL_DTR;
} else newctrl |= ACM_CTRL_DTR;
if (newctrl != acm->ctrlout)
acm_set_control(acm, acm->ctrlout = newctrl);
- if (memcmp(&acm->line, &newline, sizeof(struct acm_line))) {
- memcpy(&acm->line, &newline, sizeof(struct acm_line));
- dbg("set line: %d %d %d %d", newline.speed, newline.stopbits, newline.parity, newline.databits);
+ if (memcmp(&acm->line, &newline, sizeof newline)) {
+ memcpy(&acm->line, &newline, sizeof newline);
+ dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
+ newline.bCharFormat, newline.bParityType,
+ newline.bDataBits);
acm_set_line(acm, &acm->line);
}
}
@@ -522,7 +529,7 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_
static int acm_probe (struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct union_desc *union_header = NULL;
+ struct usb_cdc_union_desc *union_header = NULL;
char *buffer = intf->altsetting->extra;
int buflen = intf->altsetting->extralen;
struct usb_interface *control_interface;
@@ -573,21 +580,22 @@ static int acm_probe (struct usb_interface *intf,
}
switch (buffer [2]) {
- case CDC_UNION_TYPE: /* we've found it */
+ case USB_CDC_UNION_TYPE: /* we've found it */
if (union_header) {
err("More than one union descriptor, skipping ...");
goto next_desc;
}
- union_header = (struct union_desc *)buffer;
+ union_header = (struct usb_cdc_union_desc *)
+ buffer;
break;
- case CDC_COUNTRY_TYPE: /* maybe somehow export */
+ case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */
break; /* for now we ignore it */
- case CDC_HEADER_TYPE: /* maybe check version */
+ case USB_CDC_HEADER_TYPE: /* maybe check version */
break; /* for now we ignore it */
- case CDC_AC_MANAGEMENT_TYPE:
+ case USB_CDC_ACM_TYPE:
ac_management_function = buffer[3];
break;
- case CDC_CALL_MANAGEMENT_TYPE:
+ case USB_CDC_CALL_MANAGEMENT_TYPE:
call_management_function = buffer[3];
call_interface_num = buffer[4];
if ((call_management_function & 3) != 3)
@@ -750,8 +758,8 @@ skip_normal_probe:
acm_set_control(acm, acm->ctrlout);
- acm->line.speed = cpu_to_le32(9600);
- acm->line.databits = 8;
+ acm->line.dwDTERate = cpu_to_le32(9600);
+ acm->line.bDataBits = 8;
acm_set_line(acm, &acm->line);
usb_driver_claim_interface(&acm_driver, data_interface, acm);
@@ -831,14 +839,20 @@ static struct usb_device_id acm_ids[] = {
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
/* control interfaces with various AT-command sets */
- { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 1) },
- { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 2) },
- { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 3) },
- { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 4) },
- { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 5) },
- { USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 6) },
-
- /* NOTE: COMM/2/0xff is likely MSFT RNDIS ... NOT a modem!! */
+ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
+ USB_CDC_ACM_PROTO_AT_V25TER) },
+ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
+ USB_CDC_ACM_PROTO_AT_PCCA101) },
+ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
+ USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
+ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
+ USB_CDC_ACM_PROTO_AT_GSM) },
+ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
+ USB_CDC_ACM_PROTO_AT_3G ) },
+ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
+ USB_CDC_ACM_PROTO_AT_CDMA) },
+
+ /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */
{ }
};
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index c98a8c2b2a44..9009114e311b 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -27,24 +27,6 @@
#define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
-#define ACM_REQ_COMMAND 0x00
-#define ACM_REQ_RESPONSE 0x01
-#define ACM_REQ_SET_FEATURE 0x02
-#define ACM_REQ_GET_FEATURE 0x03
-#define ACM_REQ_CLEAR_FEATURE 0x04
-
-#define ACM_REQ_SET_LINE 0x20
-#define ACM_REQ_GET_LINE 0x21
-#define ACM_REQ_SET_CONTROL 0x22
-#define ACM_REQ_SEND_BREAK 0x23
-
-/*
- * IRQs.
- */
-
-#define ACM_IRQ_NETWORK 0x00
-#define ACM_IRQ_LINE_STATE 0x20
-
/*
* Output control lines.
*/
@@ -66,17 +48,6 @@
#define ACM_CTRL_OVERRUN 0x40
/*
- * Line speed and caracter encoding.
- */
-
-struct acm_line {
- __le32 speed;
- __u8 stopbits;
- __u8 parity;
- __u8 databits;
-} __attribute__ ((packed));
-
-/*
* Internal driver structures.
*/
@@ -88,7 +59,7 @@ struct acm {
struct urb *ctrlurb, *readurb, *writeurb; /* urbs */
u8 *ctrl_buffer, *read_buffer, *write_buffer; /* buffers of urbs */
dma_addr_t ctrl_dma, read_dma, write_dma; /* dma handles of buffers */
- struct acm_line line; /* line coding (bits, stop, parity) */
+ struct usb_cdc_line_coding line; /* bits, stop, parity */
struct work_struct work; /* work queue entry for line discipline waking up */
struct tasklet_struct bh; /* rx processing */
spinlock_t throttle_lock; /* synchronize throtteling and read callback */
@@ -105,24 +76,6 @@ struct acm {
unsigned int ctrl_caps; /* control capabilities from the class specific header */
};
-/* "Union Functional Descriptor" from CDC spec 5.2.3.X */
-struct union_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
-
- u8 bMasterInterface0;
- u8 bSlaveInterface0;
- /* ... and there could be other slave interfaces */
-} __attribute__ ((packed));
-
-/* class specific descriptor types */
-#define CDC_HEADER_TYPE 0x00
-#define CDC_CALL_MANAGEMENT_TYPE 0x01
-#define CDC_AC_MANAGEMENT_TYPE 0x02
-#define CDC_UNION_TYPE 0x06
-#define CDC_COUNTRY_TYPE 0x07
-
#define CDC_DATA_INTERFACE_TYPE 0x0a
/* constants describing various quirks and errors */
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index d6cfeb8ec631..bba22e97ea0f 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -114,7 +114,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
#define USBLP_MINORS 16
#define USBLP_MINOR_BASE 0
-#define USBLP_WRITE_TIMEOUT (5*HZ) /* 5 seconds */
+#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */
#define USBLP_FIRST_PROTOCOL 1
#define USBLP_LAST_PROTOCOL 3
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 42e9f8466272..837bad132449 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -420,6 +420,9 @@ void usb_destroy_configuration(struct usb_device *dev)
for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
struct usb_host_config *cf = &dev->config[c];
+ if (cf->string)
+ kfree(cf->string);
+
for (i = 0; i < cf->desc.bNumInterfaces; i++) {
if (cf->intf_cache[i])
kref_put(&cf->intf_cache[i]->ref,
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index a6961efc2cf0..c9b0fc8d1a6e 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -362,33 +362,21 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
*/
static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
{
- char *buf;
-
if (start > end)
return start;
- buf = kmalloc(128, GFP_KERNEL);
- if (!buf)
- return start;
- if (dev->descriptor.iManufacturer) {
- if (usb_string(dev, dev->descriptor.iManufacturer, buf, 128) > 0)
- start += sprintf(start, format_string_manufacturer, buf);
- }
+ if (dev->manufacturer)
+ start += sprintf(start, format_string_manufacturer, dev->manufacturer);
if (start > end)
goto out;
- if (dev->descriptor.iProduct) {
- if (usb_string(dev, dev->descriptor.iProduct, buf, 128) > 0)
- start += sprintf(start, format_string_product, buf);
- }
+ if (dev->product)
+ start += sprintf(start, format_string_product, dev->product);
if (start > end)
goto out;
#ifdef ALLOW_SERIAL_NUMBER
- if (dev->descriptor.iSerialNumber) {
- if (usb_string(dev, dev->descriptor.iSerialNumber, buf, 128) > 0)
- start += sprintf(start, format_string_serialnumber, buf);
- }
+ if (dev->serial)
+ start += sprintf(start, format_string_serialnumber, dev->serial);
#endif
out:
- kfree(buf);
return start;
}
@@ -620,6 +608,7 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
/* we may have dropped BKL - need to check for having lost the race */
if (file->private_data) {
kfree(st);
+ st = file->private_data;
goto lost_race;
}
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index c5ecae860728..a047bc392983 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -565,7 +565,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
return -EINVAL;
if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
return -ENOMEM;
- tmo = (ctrl.timeout * HZ + 999) / 1000;
+ tmo = ctrl.timeout;
if (ctrl.bRequestType & 0x80) {
if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) {
free_page((unsigned long)tbuf);
@@ -646,7 +646,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
return -EINVAL;
if (!(tbuf = kmalloc(len1, GFP_KERNEL)))
return -ENOMEM;
- tmo = (bulk.timeout * HZ + 999) / 1000;
+ tmo = bulk.timeout;
if (bulk.ep & 0x80) {
if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
kfree(tbuf);
@@ -673,11 +673,8 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
usb_lock_device(dev);
}
kfree(tbuf);
- if (i < 0) {
- dev_warn(&dev->dev, "usbfs: USBDEVFS_BULK failed "
- "ep 0x%x len %u ret %d\n", bulk.ep, bulk.len, i);
+ if (i < 0)
return i;
- }
return len2;
}
@@ -816,9 +813,11 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
return status;
}
-static int proc_submiturb(struct dev_state *ps, void __user *arg)
+
+static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+ struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
+ void __user *arg)
{
- struct usbdevfs_urb uurb;
struct usbdevfs_iso_packet_desc *isopkt = NULL;
struct usb_host_endpoint *ep;
struct async *as;
@@ -826,42 +825,40 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
unsigned int u, totlen, isofrmlen;
int ret, interval = 0, ifnum = -1;
- if (copy_from_user(&uurb, arg, sizeof(uurb)))
- return -EFAULT;
- if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
+ if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
URB_NO_FSBR|URB_ZERO_PACKET))
return -EINVAL;
- if (!uurb.buffer)
+ if (!uurb->buffer)
return -EINVAL;
- if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
+ if (uurb->signr != 0 && (uurb->signr < SIGRTMIN || uurb->signr > SIGRTMAX))
return -EINVAL;
- if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
- if ((ifnum = findintfep(ps->dev, uurb.endpoint)) < 0)
+ if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
+ if ((ifnum = findintfep(ps->dev, uurb->endpoint)) < 0)
return ifnum;
if ((ret = checkintf(ps, ifnum)))
return ret;
}
- if ((uurb.endpoint & USB_ENDPOINT_DIR_MASK) != 0)
- ep = ps->dev->ep_in [uurb.endpoint & USB_ENDPOINT_NUMBER_MASK];
+ if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0)
+ ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
else
- ep = ps->dev->ep_out [uurb.endpoint & USB_ENDPOINT_NUMBER_MASK];
+ ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
if (!ep)
return -ENOENT;
- switch(uurb.type) {
+ switch(uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL:
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_CONTROL)
return -EINVAL;
/* min 8 byte setup packet, max arbitrary */
- if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE)
+ if (uurb->buffer_length < 8 || uurb->buffer_length > PAGE_SIZE)
return -EINVAL;
if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
return -ENOMEM;
- if (copy_from_user(dr, uurb.buffer, 8)) {
+ if (copy_from_user(dr, uurb->buffer, 8)) {
kfree(dr);
return -EFAULT;
}
- if (uurb.buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
+ if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
kfree(dr);
return -EINVAL;
}
@@ -869,11 +866,11 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
kfree(dr);
return ret;
}
- uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
- uurb.number_of_packets = 0;
- uurb.buffer_length = le16_to_cpup(&dr->wLength);
- uurb.buffer += 8;
- if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) {
+ uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
+ uurb->number_of_packets = 0;
+ uurb->buffer_length = le16_to_cpup(&dr->wLength);
+ uurb->buffer += 8;
+ if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) {
kfree(dr);
return -EFAULT;
}
@@ -886,29 +883,29 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
return -EINVAL;
/* allow single-shot interrupt transfers, at bogus rates */
}
- uurb.number_of_packets = 0;
- if (uurb.buffer_length > MAX_USBFS_BUFFER_SIZE)
+ uurb->number_of_packets = 0;
+ if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
- if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
+ if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
return -EFAULT;
break;
case USBDEVFS_URB_TYPE_ISO:
/* arbitrary limit */
- if (uurb.number_of_packets < 1 || uurb.number_of_packets > 128)
+ if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
return -EINVAL;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_ISOC)
return -EINVAL;
interval = 1 << min (15, ep->desc.bInterval - 1);
- isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets;
+ isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
return -ENOMEM;
- if (copy_from_user(isopkt, &((struct usbdevfs_urb __user *)arg)->iso_frame_desc, isofrmlen)) {
+ if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
kfree(isopkt);
return -EFAULT;
}
- for (totlen = u = 0; u < uurb.number_of_packets; u++) {
+ for (totlen = u = 0; u < uurb->number_of_packets; u++) {
if (isopkt[u].length > 1023) {
kfree(isopkt);
return -EINVAL;
@@ -919,11 +916,11 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
kfree(isopkt);
return -EINVAL;
}
- uurb.buffer_length = totlen;
+ uurb->buffer_length = totlen;
break;
case USBDEVFS_URB_TYPE_INTERRUPT:
- uurb.number_of_packets = 0;
+ uurb->number_of_packets = 0;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_INT)
return -EINVAL;
@@ -931,23 +928,23 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
interval = 1 << min (15, ep->desc.bInterval - 1);
else
interval = ep->desc.bInterval;
- if (uurb.buffer_length > MAX_USBFS_BUFFER_SIZE)
+ if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
- if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
+ if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
return -EFAULT;
break;
default:
return -EINVAL;
}
- if (!(as = alloc_async(uurb.number_of_packets))) {
+ if (!(as = alloc_async(uurb->number_of_packets))) {
if (isopkt)
kfree(isopkt);
if (dr)
kfree(dr);
return -ENOMEM;
}
- if (!(as->urb->transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
+ if (!(as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL))) {
if (isopkt)
kfree(isopkt);
if (dr)
@@ -956,16 +953,16 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
return -ENOMEM;
}
as->urb->dev = ps->dev;
- as->urb->pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
- as->urb->transfer_flags = uurb.flags;
- as->urb->transfer_buffer_length = uurb.buffer_length;
+ as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
+ as->urb->transfer_flags = uurb->flags;
+ as->urb->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char*)dr;
- as->urb->start_frame = uurb.start_frame;
- as->urb->number_of_packets = uurb.number_of_packets;
+ as->urb->start_frame = uurb->start_frame;
+ as->urb->number_of_packets = uurb->number_of_packets;
as->urb->interval = interval;
as->urb->context = as;
as->urb->complete = async_completed;
- for (totlen = u = 0; u < uurb.number_of_packets; u++) {
+ for (totlen = u = 0; u < uurb->number_of_packets; u++) {
as->urb->iso_frame_desc[u].offset = totlen;
as->urb->iso_frame_desc[u].length = isopkt[u].length;
totlen += isopkt[u].length;
@@ -974,15 +971,15 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
kfree(isopkt);
as->ps = ps;
as->userurb = arg;
- if (uurb.endpoint & USB_DIR_IN)
- as->userbuffer = uurb.buffer;
+ if (uurb->endpoint & USB_DIR_IN)
+ as->userbuffer = uurb->buffer;
else
as->userbuffer = NULL;
- as->signr = uurb.signr;
+ as->signr = uurb->signr;
as->ifnum = ifnum;
as->task = current;
- if (!(uurb.endpoint & USB_DIR_IN)) {
- if (copy_from_user(as->urb->transfer_buffer, uurb.buffer, as->urb->transfer_buffer_length)) {
+ if (!(uurb->endpoint & USB_DIR_IN)) {
+ if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
free_async(as);
return -EFAULT;
}
@@ -997,6 +994,16 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
return 0;
}
+static int proc_submiturb(struct dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_urb uurb;
+
+ if (copy_from_user(&uurb, arg, sizeof(uurb)))
+ return -EFAULT;
+
+ return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg);
+}
+
static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
{
struct async *as;
@@ -1008,10 +1015,11 @@ static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
return 0;
}
-static int processcompl(struct async *as)
+static int processcompl(struct async *as, void __user * __user *arg)
{
struct urb *urb = as->urb;
struct usbdevfs_urb __user *userurb = as->userurb;
+ void __user *addr = as->userurb;
unsigned int i;
if (as->userbuffer)
@@ -1034,16 +1042,19 @@ static int processcompl(struct async *as)
&userurb->iso_frame_desc[i].status))
return -EFAULT;
}
+
+ free_async(as);
+
+ if (put_user(addr, (void __user * __user *)arg))
+ return -EFAULT;
return 0;
}
-static int proc_reapurb(struct dev_state *ps, void __user *arg)
+static struct async* reap_as(struct dev_state *ps)
{
DECLARE_WAITQUEUE(wait, current);
struct async *as = NULL;
- void __user *addr;
struct usb_device *dev = ps->dev;
- int ret;
add_wait_queue(&ps->wait, &wait);
for (;;) {
@@ -1058,16 +1069,14 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg)
}
remove_wait_queue(&ps->wait, &wait);
set_current_state(TASK_RUNNING);
- if (as) {
- ret = processcompl(as);
- addr = as->userurb;
- free_async(as);
- if (ret)
- return ret;
- if (put_user(addr, (void __user * __user *)arg))
- return -EFAULT;
- return 0;
- }
+ return as;
+}
+
+static int proc_reapurb(struct dev_state *ps, void __user *arg)
+{
+ struct async *as = reap_as(ps);
+ if (as)
+ return processcompl(as, (void __user * __user *)arg);
if (signal_pending(current))
return -EINTR;
return -EIO;
@@ -1076,21 +1085,107 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg)
static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
{
struct async *as;
- void __user *addr;
- int ret;
if (!(as = async_getcompleted(ps)))
return -EAGAIN;
- ret = processcompl(as);
- addr = as->userurb;
+ return processcompl(as, (void __user * __user *)arg);
+}
+
+#ifdef CONFIG_COMPAT
+
+static int get_urb32(struct usbdevfs_urb *kurb,
+ struct usbdevfs_urb32 __user *uurb)
+{
+ __u32 uptr;
+ if (get_user(kurb->type, &uurb->type) ||
+ __get_user(kurb->endpoint, &uurb->endpoint) ||
+ __get_user(kurb->status, &uurb->status) ||
+ __get_user(kurb->flags, &uurb->flags) ||
+ __get_user(kurb->buffer_length, &uurb->buffer_length) ||
+ __get_user(kurb->actual_length, &uurb->actual_length) ||
+ __get_user(kurb->start_frame, &uurb->start_frame) ||
+ __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
+ __get_user(kurb->error_count, &uurb->error_count) ||
+ __get_user(kurb->signr, &uurb->signr))
+ return -EFAULT;
+
+ if (__get_user(uptr, &uurb->buffer))
+ return -EFAULT;
+ kurb->buffer = compat_ptr(uptr);
+ if (__get_user(uptr, &uurb->buffer))
+ return -EFAULT;
+ kurb->usercontext = compat_ptr(uptr);
+
+ return 0;
+}
+
+static int proc_submiturb_compat(struct dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_urb uurb;
+
+ if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg))
+ return -EFAULT;
+
+ return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb __user *)arg)->iso_frame_desc, arg);
+}
+
+static int processcompl_compat(struct async *as, void __user * __user *arg)
+{
+ struct urb *urb = as->urb;
+ struct usbdevfs_urb32 __user *userurb = as->userurb;
+ void __user *addr = as->userurb;
+ unsigned int i;
+
+ if (as->userbuffer)
+ if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
+ return -EFAULT;
+ if (put_user(urb->status, &userurb->status))
+ return -EFAULT;
+ if (put_user(urb->actual_length, &userurb->actual_length))
+ return -EFAULT;
+ if (put_user(urb->error_count, &userurb->error_count))
+ return -EFAULT;
+
+ if (!(usb_pipeisoc(urb->pipe)))
+ return 0;
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (put_user(urb->iso_frame_desc[i].actual_length,
+ &userurb->iso_frame_desc[i].actual_length))
+ return -EFAULT;
+ if (put_user(urb->iso_frame_desc[i].status,
+ &userurb->iso_frame_desc[i].status))
+ return -EFAULT;
+ }
+
free_async(as);
- if (ret)
- return ret;
- if (put_user(addr, (void __user * __user *)arg))
+ if (put_user((u32)(u64)addr, (u32 __user *)arg))
return -EFAULT;
return 0;
}
+static int proc_reapurb_compat(struct dev_state *ps, void __user *arg)
+{
+ struct async *as = reap_as(ps);
+ if (as)
+ return processcompl_compat(as, (void __user * __user *)arg);
+ if (signal_pending(current))
+ return -EINTR;
+ return -EIO;
+}
+
+static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)
+{
+ struct async *as;
+
+ printk("reapurbnblock\n");
+ if (!(as = async_getcompleted(ps)))
+ return -EAGAIN;
+ printk("reap got as %p\n", as);
+ return processcompl_compat(as, (void __user * __user *)arg);
+}
+
+#endif
+
static int proc_disconnectsignal(struct dev_state *ps, void __user *arg)
{
struct usbdevfs_disconnectsignal ds;
@@ -1302,6 +1397,27 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
inode->i_mtime = CURRENT_TIME;
break;
+#ifdef CONFIG_COMPAT
+
+ case USBDEVFS_SUBMITURB32:
+ snoop(&dev->dev, "%s: SUBMITURB32\n", __FUNCTION__);
+ ret = proc_submiturb_compat(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_REAPURB32:
+ snoop(&dev->dev, "%s: REAPURB32\n", __FUNCTION__);
+ ret = proc_reapurb_compat(ps, p);
+ break;
+
+ case USBDEVFS_REAPURBNDELAY32:
+ snoop(&dev->dev, "%s: REAPURBDELAY32\n", __FUNCTION__);
+ ret = proc_reapurbnonblock_compat(ps, p);
+ break;
+
+#endif
+
case USBDEVFS_DISCARDURB:
snoop(&dev->dev, "%s: DISCARDURB\n", __FUNCTION__);
ret = proc_unlinkurb(ps, p);
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 7b836ae19530..efc6f47fbcef 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -56,11 +56,8 @@
int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
struct hc_driver *driver;
- unsigned long resource, len;
- void __iomem *base;
struct usb_hcd *hcd;
- int retval, region;
- char buf [8], *bufp = buf;
+ int retval;
if (usb_disabled())
return -ENODEV;
@@ -78,122 +75,75 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
pci_name(dev));
retval = -ENODEV;
- goto done;
+ goto err1;
}
-
+
+ hcd = usb_create_hcd (driver, &dev->dev, pci_name(dev));
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto err1;
+ }
+
if (driver->flags & HCD_MEMORY) { // EHCI, OHCI
- region = 0;
- resource = pci_resource_start (dev, 0);
- len = pci_resource_len (dev, 0);
- if (!request_mem_region (resource, len, driver->description)) {
+ hcd->rsrc_start = pci_resource_start (dev, 0);
+ hcd->rsrc_len = pci_resource_len (dev, 0);
+ if (!request_mem_region (hcd->rsrc_start, hcd->rsrc_len,
+ driver->description)) {
dev_dbg (&dev->dev, "controller already in use\n");
retval = -EBUSY;
- goto done;
+ goto err2;
}
- base = ioremap_nocache (resource, len);
- if (base == NULL) {
+ hcd->regs = ioremap_nocache (hcd->rsrc_start, hcd->rsrc_len);
+ if (hcd->regs == NULL) {
dev_dbg (&dev->dev, "error mapping memory\n");
retval = -EFAULT;
-clean_1:
- release_mem_region (resource, len);
- dev_err (&dev->dev, "init %s fail, %d\n",
- pci_name(dev), retval);
- goto done;
+ goto err3;
}
} else { // UHCI
- resource = len = 0;
+ int region;
+
for (region = 0; region < PCI_ROM_RESOURCE; region++) {
- if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
+ if (!(pci_resource_flags (dev, region) &
+ IORESOURCE_IO))
continue;
- resource = pci_resource_start (dev, region);
- len = pci_resource_len (dev, region);
- if (request_region (resource, len,
+ hcd->rsrc_start = pci_resource_start (dev, region);
+ hcd->rsrc_len = pci_resource_len (dev, region);
+ if (request_region (hcd->rsrc_start, hcd->rsrc_len,
driver->description))
break;
}
if (region == PCI_ROM_RESOURCE) {
dev_dbg (&dev->dev, "no i/o regions available\n");
retval = -EBUSY;
- goto done;
+ goto err1;
}
- base = (void __iomem *) resource;
}
- // driver->reset(), later on, will transfer device from
- // control by SMM/BIOS to control by Linux (if needed)
-
- hcd = usb_create_hcd (driver);
- if (hcd == NULL){
- dev_dbg (&dev->dev, "hcd alloc fail\n");
- retval = -ENOMEM;
-clean_2:
- if (driver->flags & HCD_MEMORY) {
- iounmap (base);
- goto clean_1;
- } else {
- release_region (resource, len);
- dev_err (&dev->dev, "init %s fail, %d\n",
- pci_name(dev), retval);
- goto done;
- }
- }
- // hcd zeroed everything
- hcd->regs = base;
- hcd->region = region;
-
- pci_set_drvdata (dev, hcd);
- hcd->self.bus_name = pci_name(dev);
#ifdef CONFIG_PCI_NAMES
hcd->product_desc = dev->pretty_name;
#endif
- hcd->self.controller = &dev->dev;
-
- if ((retval = hcd_buffer_create (hcd)) != 0) {
-clean_3:
- pci_set_drvdata (dev, NULL);
- usb_put_hcd (hcd);
- goto clean_2;
- }
-
- dev_info (hcd->self.controller, "%s\n", hcd->product_desc);
-
- /* till now HC has been in an indeterminate state ... */
- if (driver->reset && (retval = driver->reset (hcd)) < 0) {
- dev_err (hcd->self.controller, "can't reset\n");
- goto clean_3;
- }
pci_set_master (dev);
-#ifndef __sparc__
- sprintf (buf, "%d", dev->irq);
-#else
- bufp = __irq_itoa(dev->irq);
-#endif
- retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ,
- hcd->driver->description, hcd);
- if (retval != 0) {
- dev_err (hcd->self.controller,
- "request interrupt %s failed\n", bufp);
- goto clean_3;
- }
- hcd->irq = dev->irq;
-
- dev_info (hcd->self.controller, "irq %s, %s 0x%lx\n", bufp,
- (driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
- resource);
- usb_register_bus (&hcd->self);
-
- if ((retval = driver->start (hcd)) < 0) {
- dev_err (hcd->self.controller, "init error %d\n", retval);
- usb_hcd_pci_remove (dev);
- }
-
-done:
+ retval = usb_add_hcd (hcd, dev->irq, SA_SHIRQ);
if (retval != 0)
- pci_disable_device (dev);
+ goto err4;
+ return retval;
+
+ err4:
+ if (driver->flags & HCD_MEMORY) {
+ iounmap (hcd->regs);
+ err3:
+ release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
+ } else
+ release_region (hcd->rsrc_start, hcd->rsrc_len);
+ err2:
+ usb_put_hcd (hcd);
+ err1:
+ pci_disable_device (dev);
+ dev_err (&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_probe);
@@ -220,34 +170,15 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
hcd = pci_get_drvdata(dev);
if (!hcd)
return;
- dev_info (hcd->self.controller, "remove, state %x\n", hcd->state);
-
- if (in_interrupt ())
- BUG ();
-
- if (HCD_IS_RUNNING (hcd->state))
- hcd->state = USB_STATE_QUIESCING;
- dev_dbg (hcd->self.controller, "roothub graceful disconnect\n");
- usb_disconnect (&hcd->self.root_hub);
-
- hcd->driver->stop (hcd);
- hcd_buffer_destroy (hcd);
- hcd->state = USB_STATE_HALT;
- pci_set_drvdata(dev, NULL);
-
- free_irq (hcd->irq, hcd);
+ usb_remove_hcd (hcd);
if (hcd->driver->flags & HCD_MEMORY) {
iounmap (hcd->regs);
- release_mem_region (pci_resource_start (dev, 0),
- pci_resource_len (dev, 0));
+ release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
} else {
- release_region (pci_resource_start (dev, hcd->region),
- pci_resource_len (dev, hcd->region));
+ release_region (hcd->rsrc_start, hcd->rsrc_len);
}
-
- usb_deregister_bus (&hcd->self);
-
+ usb_put_hcd (hcd);
pci_disable_device(dev);
}
EXPORT_SYMBOL (usb_hcd_pci_remove);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index b87aa7c06e0c..ae72ce74b7fd 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -46,6 +46,7 @@
#include "usb.h"
#include "hcd.h"
+#include "hub.h"
// #define USB_BANDWIDTH_MESSAGES
@@ -87,6 +88,7 @@
/* host controllers we manage */
LIST_HEAD (usb_bus_list);
+EXPORT_SYMBOL_GPL (usb_bus_list);
/* used when allocating bus numbers */
#define USB_MAXBUS 64
@@ -97,6 +99,7 @@ static struct usb_busmap busmap;
/* used when updating list of hcds */
DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */
+EXPORT_SYMBOL_GPL (usb_bus_list_lock);
/* used when updating hcd data */
static DEFINE_SPINLOCK(hcd_data_lock);
@@ -272,6 +275,10 @@ static int ascii2utf (char *s, u8 *utf, int utfmax)
*utf++ = *s++;
*utf++ = 0;
}
+ if (utfmax > 0) {
+ *utf = *s;
+ ++retval;
+ }
return retval;
}
@@ -296,30 +303,40 @@ static int rh_string (
// language ids
if (id == 0) {
- *data++ = 4; *data++ = 3; /* 4 bytes string data */
- *data++ = 0x09; *data++ = 0x04; /* MSFT-speak for "en-us" */
- return 4;
+ buf[0] = 4; buf[1] = 3; /* 4 bytes string data */
+ buf[2] = 0x09; buf[3] = 0x04; /* MSFT-speak for "en-us" */
+ len = min (len, 4);
+ memcpy (data, buf, len);
+ return len;
// serial number
} else if (id == 1) {
- strcpy (buf, hcd->self.bus_name);
+ strlcpy (buf, hcd->self.bus_name, sizeof buf);
// product description
} else if (id == 2) {
- strcpy (buf, hcd->product_desc);
+ strlcpy (buf, hcd->product_desc, sizeof buf);
// id 3 == vendor description
} else if (id == 3) {
- sprintf (buf, "%s %s %s", system_utsname.sysname,
+ snprintf (buf, sizeof buf, "%s %s %s", system_utsname.sysname,
system_utsname.release, hcd->driver->description);
// unsupported IDs --> "protocol stall"
} else
- return 0;
+ return -EPIPE;
- data [0] = 2 * (strlen (buf) + 1);
- data [1] = 3; /* type == string */
- return 2 + ascii2utf (buf, data + 2, len - 2);
+ switch (len) { /* All cases fall through */
+ default:
+ len = 2 + ascii2utf (buf, data + 2, len - 2);
+ case 2:
+ data [1] = 3; /* type == string */
+ case 1:
+ data [0] = 2 * (strlen (buf) + 1);
+ case 0:
+ ; /* Compiler wants a statement here */
+ }
+ return len;
}
@@ -328,11 +345,14 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
{
struct usb_ctrlrequest *cmd;
u16 typeReq, wValue, wIndex, wLength;
- const u8 *bufp = NULL;
u8 *ubuf = urb->transfer_buffer;
+ u8 tbuf [sizeof (struct usb_hub_descriptor)];
+ const u8 *bufp = tbuf;
int len = 0;
int patch_wakeup = 0;
unsigned long flags;
+ int status = 0;
+ int n;
cmd = (struct usb_ctrlrequest *) urb->setup_packet;
typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
@@ -343,17 +363,16 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
if (wLength > urb->transfer_buffer_length)
goto error;
- /* set up for success */
- urb->status = 0;
- urb->actual_length = wLength;
+ urb->actual_length = 0;
switch (typeReq) {
/* DEVICE REQUESTS */
case DeviceRequest | USB_REQ_GET_STATUS:
- ubuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)
+ tbuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)
| (1 << USB_DEVICE_SELF_POWERED);
- ubuf [1] = 0;
+ tbuf [1] = 0;
+ len = 2;
break;
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
if (wValue == USB_DEVICE_REMOTE_WAKEUP)
@@ -368,7 +387,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
goto error;
break;
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- ubuf [0] = 1;
+ tbuf [0] = 1;
+ len = 1;
/* FALLTHROUGH */
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
break;
@@ -395,16 +415,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
patch_wakeup = 1;
break;
case USB_DT_STRING << 8:
- urb->actual_length = rh_string (
- wValue & 0xff, hcd,
- ubuf, wLength);
+ n = rh_string (wValue & 0xff, hcd, ubuf, wLength);
+ if (n < 0)
+ goto error;
+ urb->actual_length = n;
break;
default:
goto error;
}
break;
case DeviceRequest | USB_REQ_GET_INTERFACE:
- ubuf [0] = 0;
+ tbuf [0] = 0;
+ len = 1;
/* FALLTHROUGH */
case DeviceOutRequest | USB_REQ_SET_INTERFACE:
break;
@@ -420,8 +442,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
case EndpointRequest | USB_REQ_GET_STATUS:
// ENDPOINT_HALT flag
- ubuf [0] = 0;
- ubuf [1] = 0;
+ tbuf [0] = 0;
+ tbuf [1] = 0;
+ len = 2;
/* FALLTHROUGH */
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
case EndpointOutRequest | USB_REQ_SET_FEATURE:
@@ -433,19 +456,30 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
default:
/* non-generic request */
if (HCD_IS_SUSPENDED (hcd->state))
- urb->status = -EAGAIN;
- else
- urb->status = hcd->driver->hub_control (hcd,
+ status = -EAGAIN;
+ else {
+ switch (typeReq) {
+ case GetHubStatus:
+ case GetPortStatus:
+ len = 4;
+ break;
+ case GetHubDescriptor:
+ len = sizeof (struct usb_hub_descriptor);
+ break;
+ }
+ status = hcd->driver->hub_control (hcd,
typeReq, wValue, wIndex,
- ubuf, wLength);
+ tbuf, wLength);
+ }
break;
error:
/* "protocol stall" on error */
- urb->status = -EPIPE;
+ status = -EPIPE;
}
- if (urb->status) {
- urb->actual_length = 0;
- if (urb->status != -EPIPE) {
+
+ if (status) {
+ len = 0;
+ if (status != -EPIPE) {
dev_dbg (hcd->self.controller,
"CTRL: TypeReq=0x%x val=0x%x "
"idx=0x%x len=%d ==> %d\n",
@@ -453,7 +487,7 @@ error:
wLength, urb->status);
}
}
- if (bufp) {
+ if (len) {
if (urb->transfer_buffer_length < len)
len = urb->transfer_buffer_length;
urb->actual_length = len;
@@ -461,13 +495,19 @@ error:
memcpy (ubuf, bufp, len);
/* report whether RH hardware supports remote wakeup */
- if (patch_wakeup)
+ if (patch_wakeup &&
+ len > offsetof (struct usb_config_descriptor,
+ bmAttributes))
((struct usb_config_descriptor *)ubuf)->bmAttributes
|= USB_CONFIG_ATT_WAKEUP;
}
/* any errors get returned through the urb completion */
local_irq_save (flags);
+ spin_lock (&urb->lock);
+ if (urb->status == -EINPROGRESS)
+ urb->status = status;
+ spin_unlock (&urb->lock);
usb_hcd_giveback_urb (hcd, urb, NULL);
local_irq_restore (flags);
return 0;
@@ -747,6 +787,7 @@ int usb_register_bus(struct usb_bus *bus)
up (&usb_bus_list_lock);
usbfs_add_bus (bus);
+ usbmon_notify_bus_add (bus);
dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
return 0;
@@ -774,11 +815,12 @@ void usb_deregister_bus (struct usb_bus *bus)
list_del (&bus->bus_list);
up (&usb_bus_list_lock);
+ usbmon_notify_bus_remove (bus);
usbfs_remove_bus (bus);
clear_bit (bus->busnum, busmap.busmap);
- class_device_unregister(&bus->class_dev);
+ class_device_del(&bus->class_dev);
}
EXPORT_SYMBOL (usb_deregister_bus);
@@ -1049,19 +1091,10 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
struct usb_host_endpoint *ep;
unsigned long flags;
- ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
- [usb_pipeendpoint(urb->pipe)];
- if (!hcd || !ep)
+ if (!hcd)
return -ENODEV;
- /*
- * FIXME: make urb timeouts be generic, keeping the HCD cores
- * as simple as possible.
- */
-
- // NOTE: a generic device/urb monitoring hook would go here.
- // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)
- // It would catch submission paths for all urbs.
+ usbmon_urb_submit(&hcd->self, urb);
/*
* Atomically queue the urb, first to our records, then to the HCD.
@@ -1072,7 +1105,11 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
// FIXME: verify that quiescing hc works right (RH cleans up)
spin_lock_irqsave (&hcd_data_lock, flags);
- if (unlikely (urb->reject))
+ ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
+ [usb_pipeendpoint(urb->pipe)];
+ if (unlikely (!ep))
+ status = -ENOENT;
+ else if (unlikely (urb->reject))
status = -EPERM;
else switch (hcd->state) {
case USB_STATE_RUNNING:
@@ -1088,6 +1125,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
spin_unlock_irqrestore (&hcd_data_lock, flags);
if (status) {
INIT_LIST_HEAD (&urb->urb_list);
+ usbmon_urb_submit_error(&hcd->self, urb, status);
return status;
}
@@ -1104,8 +1142,6 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
* valid and usb_buffer_{sync,unmap}() not be needed, since
* they could clobber root hub response data.
*/
- urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP
- | URB_NO_SETUP_DMA_MAP);
status = rh_urb_enqueue (hcd, urb);
goto done;
}
@@ -1140,6 +1176,7 @@ done:
if (urb->reject)
wake_up (&usb_kill_urb_queue);
usb_put_urb (urb);
+ usbmon_urb_submit_error(&hcd->self, urb, status);
}
return status;
}
@@ -1462,14 +1499,13 @@ static struct usb_operations usb_hcd_operations = {
*/
void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
{
- urb_unlink (urb);
+ int at_root_hub;
- // NOTE: a generic device/urb monitoring hook would go here.
- // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
- // It would catch exit/unlink paths for all urbs.
+ at_root_hub = (urb->dev == hcd->self.root_hub);
+ urb_unlink (urb);
/* lower level hcd code should use *_dma exclusively */
- if (hcd->self.controller->dma_mask) {
+ if (hcd->self.controller->dma_mask && !at_root_hub) {
if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
dma_unmap_single (hcd->self.controller, urb->setup_dma,
@@ -1485,6 +1521,7 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs
: DMA_TO_DEVICE);
}
+ usbmon_urb_complete (&hcd->self, urb);
/* pass ownership to the completion handler */
urb->complete (urb, regs);
atomic_dec (&urb->use_count);
@@ -1499,12 +1536,11 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
/**
* usb_hcd_irq - hook IRQs to HCD framework (bus glue)
* @irq: the IRQ being raised
- * @__hcd: pointer to the HCD whose IRQ is beinng signaled
+ * @__hcd: pointer to the HCD whose IRQ is being signaled
* @r: saved hardware registers
*
- * When registering a USB bus through the HCD framework code, use this
- * to handle interrupts. The PCI glue layer does so automatically; only
- * bus glue for non-PCI system busses will need to use this.
+ * If the controller isn't HALTed, calls the driver's irq handler.
+ * Checks whether the controller is now dead.
*/
irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
{
@@ -1555,6 +1591,8 @@ static void hcd_release (struct usb_bus *bus)
/**
* usb_create_hcd - create and initialize an HCD structure
* @driver: HC driver that will use this hcd
+ * @dev: device for this HC, stored in hcd->self.controller
+ * @bus_name: value to store in hcd->self.bus_name
* Context: !in_interrupt()
*
* Allocate a struct usb_hcd, with extra space at the end for the
@@ -1563,25 +1601,30 @@ static void hcd_release (struct usb_bus *bus)
*
* If memory is unavailable, returns NULL.
*/
-struct usb_hcd *usb_create_hcd (const struct hc_driver *driver)
+struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
+ struct device *dev, char *bus_name)
{
struct usb_hcd *hcd;
hcd = kcalloc(1, sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
- if (!hcd)
+ if (!hcd) {
+ dev_dbg (dev, "hcd alloc failed\n");
return NULL;
+ }
+ dev_set_drvdata(dev, hcd);
usb_bus_init(&hcd->self);
hcd->self.op = &usb_hcd_operations;
hcd->self.hcpriv = hcd;
hcd->self.release = &hcd_release;
+ hcd->self.controller = dev;
+ hcd->self.bus_name = bus_name;
init_timer(&hcd->rh_timer);
hcd->driver = driver;
hcd->product_desc = (driver->product_desc) ? driver->product_desc :
"USB Host Controller";
- hcd->state = USB_STATE_HALT;
return hcd;
}
@@ -1589,6 +1632,153 @@ EXPORT_SYMBOL (usb_create_hcd);
void usb_put_hcd (struct usb_hcd *hcd)
{
+ dev_set_drvdata(hcd->self.controller, NULL);
usb_bus_put(&hcd->self);
}
EXPORT_SYMBOL (usb_put_hcd);
+
+/**
+ * usb_add_hcd - finish generic HCD structure initialization and register
+ * @hcd: the usb_hcd structure to initialize
+ * @irqnum: Interrupt line to allocate
+ * @irqflags: Interrupt type flags
+ *
+ * Finish the remaining parts of generic HCD initialization: allocate the
+ * buffers of consistent memory, register the bus, request the IRQ line,
+ * and call the driver's reset() and start() routines.
+ */
+int usb_add_hcd(struct usb_hcd *hcd,
+ unsigned int irqnum, unsigned long irqflags)
+{
+ int retval;
+
+ dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
+
+ /* till now HC has been in an indeterminate state ... */
+ if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
+ dev_err(hcd->self.controller, "can't reset\n");
+ return retval;
+ }
+
+ if ((retval = hcd_buffer_create(hcd)) != 0) {
+ dev_dbg(hcd->self.controller, "pool alloc failed\n");
+ return retval;
+ }
+
+ if ((retval = usb_register_bus(&hcd->self)) < 0)
+ goto err1;
+
+ if (hcd->driver->irq) {
+ char buf[8], *bufp = buf;
+
+#ifdef __sparc__
+ bufp = __irq_itoa(irqnum);
+#else
+ sprintf(buf, "%d", irqnum);
+#endif
+
+ snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
+ hcd->driver->description, hcd->self.busnum);
+ if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
+ hcd->irq_descr, hcd)) != 0) {
+ dev_err(hcd->self.controller,
+ "request interrupt %s failed\n", bufp);
+ goto err2;
+ }
+ hcd->irq = irqnum;
+ dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp,
+ (hcd->driver->flags & HCD_MEMORY) ?
+ "io mem" : "io base", hcd->rsrc_start);
+ } else {
+ hcd->irq = -1;
+ if (hcd->rsrc_start)
+ dev_info(hcd->self.controller, "%s 0x%08llx\n",
+ (hcd->driver->flags & HCD_MEMORY) ?
+ "io mem" : "io base", hcd->rsrc_start);
+ }
+
+ if ((retval = hcd->driver->start(hcd)) < 0) {
+ dev_err(hcd->self.controller, "startup error %d\n", retval);
+ goto err3;
+ }
+
+ return retval;
+
+ err3:
+ if (hcd->irq >= 0)
+ free_irq(irqnum, hcd);
+ err2:
+ usb_deregister_bus(&hcd->self);
+ err1:
+ hcd_buffer_destroy(hcd);
+ return retval;
+}
+EXPORT_SYMBOL (usb_add_hcd);
+
+/**
+ * usb_remove_hcd - shutdown processing for generic HCDs
+ * @hcd: the usb_hcd structure to remove
+ * Context: !in_interrupt()
+ *
+ * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
+ * invoking the HCD's stop() method.
+ */
+void usb_remove_hcd(struct usb_hcd *hcd)
+{
+ dev_info(hcd->self.controller, "remove, state %x\n", hcd->state);
+
+ if (HCD_IS_RUNNING (hcd->state))
+ hcd->state = USB_STATE_QUIESCING;
+
+ dev_dbg(hcd->self.controller, "roothub graceful disconnect\n");
+ usb_disconnect(&hcd->self.root_hub);
+
+ hcd->driver->stop(hcd);
+ hcd->state = USB_STATE_HALT;
+
+ if (hcd->irq >= 0)
+ free_irq(hcd->irq, hcd);
+ usb_deregister_bus(&hcd->self);
+ hcd_buffer_destroy(hcd);
+}
+EXPORT_SYMBOL (usb_remove_hcd);
+
+/*-------------------------------------------------------------------------*/
+
+#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
+
+struct usb_mon_operations *mon_ops;
+
+/*
+ * The registration is unlocked.
+ * We do it this way because we do not want to lock in hot paths.
+ *
+ * Notice that the code is minimally error-proof. Because usbmon needs
+ * symbols from usbcore, usbcore gets referenced and cannot be unloaded first.
+ */
+
+int usb_mon_register (struct usb_mon_operations *ops)
+{
+
+ if (mon_ops)
+ return -EBUSY;
+
+ mon_ops = ops;
+ mb();
+ return 0;
+}
+EXPORT_SYMBOL_GPL (usb_mon_register);
+
+void usb_mon_deregister (void)
+{
+
+ if (mon_ops == NULL) {
+ printk(KERN_ERR "USB: monitor was not registered\n");
+ return;
+ }
+ mon_ops = NULL;
+ mb();
+}
+EXPORT_SYMBOL_GPL (usb_mon_deregister);
+
+#endif /* CONFIG_USB_MON */
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 64884196cf21..44fac434e19e 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -63,6 +63,7 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
struct usb_bus self; /* hcd is-a bus */
const char *product_desc; /* product/vendor string */
+ char irq_descr[24]; /* driver + bus # */
struct timer_list rh_timer; /* drives root hub */
@@ -75,10 +76,8 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
unsigned remote_wakeup:1;/* sw should use wakeup? */
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
-
-#ifdef CONFIG_PCI
- int region; /* pci region for regs */
-#endif
+ u64 rsrc_start; /* memory/io resource start */
+ u64 rsrc_len; /* memory/io resource length */
#define HCD_BUFFER_POOLS 4
struct dma_pool *pool [HCD_BUFFER_POOLS];
@@ -211,9 +210,12 @@ struct hc_driver {
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
extern void usb_bus_init (struct usb_bus *bus);
-extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver);
+extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
+ struct device *dev, char *bus_name);
extern void usb_put_hcd (struct usb_hcd *hcd);
-
+extern int usb_add_hcd(struct usb_hcd *hcd,
+ unsigned int irqnum, unsigned long irqflags);
+extern void usb_remove_hcd(struct usb_hcd *hcd);
#ifdef CONFIG_PCI
struct pci_dev;
@@ -411,6 +413,66 @@ static inline void usbfs_cleanup(void) { }
/*-------------------------------------------------------------------------*/
+#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
+
+struct usb_mon_operations {
+ void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
+ void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
+ void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
+ /* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
+ void (*bus_add)(struct usb_bus *bus);
+ void (*bus_remove)(struct usb_bus *bus);
+};
+
+extern struct usb_mon_operations *mon_ops;
+
+static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb)
+{
+ if (bus->monitored)
+ (*mon_ops->urb_submit)(bus, urb);
+}
+
+static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
+ int error)
+{
+ if (bus->monitored)
+ (*mon_ops->urb_submit_error)(bus, urb, error);
+}
+
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
+{
+ if (bus->monitored)
+ (*mon_ops->urb_complete)(bus, urb);
+}
+
+static inline void usbmon_notify_bus_add(struct usb_bus *bus)
+{
+ if (mon_ops)
+ (*mon_ops->bus_add)(bus);
+}
+
+static inline void usbmon_notify_bus_remove(struct usb_bus *bus)
+{
+ if (mon_ops)
+ (*mon_ops->bus_remove)(bus);
+}
+
+int usb_mon_register(struct usb_mon_operations *ops);
+void usb_mon_deregister(void);
+
+#else
+
+static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
+static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
+ int error) {}
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
+static inline void usbmon_notify_bus_add(struct usb_bus *bus) {}
+static inline void usbmon_notify_bus_remove(struct usb_bus *bus) {}
+
+#endif /* CONFIG_USB_MON */
+
+/*-------------------------------------------------------------------------*/
+
/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
// bleech -- resurfaced in 2.4.11 or 2.4.12
#define bitmap DeviceRemovable
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index bab10573c3f3..15979aad134d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -74,7 +74,7 @@ module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(old_scheme_first,
"start with the old device initialization scheme");
-static int use_both_schemes = 0;
+static int use_both_schemes = 1;
module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(use_both_schemes,
"try the other device initialization scheme if the "
@@ -108,7 +108,7 @@ static int get_hub_descriptor(struct usb_device *hdev, void *data, int size)
ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
USB_DT_HUB << 8, 0, data, size,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2))
return ret;
}
@@ -121,7 +121,7 @@ static int get_hub_descriptor(struct usb_device *hdev, void *data, int size)
static int clear_hub_feature(struct usb_device *hdev, int feature)
{
return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
- USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ);
+ USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, 1000);
}
/*
@@ -131,7 +131,7 @@ static int clear_port_feature(struct usb_device *hdev, int port1, int feature)
{
return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1,
- NULL, 0, HZ);
+ NULL, 0, 1000);
}
/*
@@ -141,7 +141,7 @@ static int set_port_feature(struct usb_device *hdev, int port1, int feature)
{
return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1,
- NULL, 0, HZ);
+ NULL, 0, 1000);
}
/*
@@ -242,7 +242,7 @@ static void led_work (void *__hub)
}
/* use a short timeout for hub/port status fetches */
-#define USB_STS_TIMEOUT 1
+#define USB_STS_TIMEOUT 1000
#define USB_STS_RETRIES 5
/*
@@ -256,7 +256,7 @@ static int get_hub_status(struct usb_device *hdev,
for (i = 0; i < USB_STS_RETRIES && status == -ETIMEDOUT; i++) {
status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
- data, sizeof(*data), HZ * USB_STS_TIMEOUT);
+ data, sizeof(*data), USB_STS_TIMEOUT);
}
return status;
}
@@ -272,7 +272,7 @@ static int get_port_status(struct usb_device *hdev, int port1,
for (i = 0; i < USB_STS_RETRIES && status == -ETIMEDOUT; i++) {
status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port1,
- data, sizeof(*data), HZ * USB_STS_TIMEOUT);
+ data, sizeof(*data), USB_STS_TIMEOUT);
}
return status;
}
@@ -342,7 +342,7 @@ hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)
{
return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo,
- tt, NULL, 0, HZ);
+ tt, NULL, 0, 1000);
}
/*
@@ -459,6 +459,7 @@ static void hub_activate(struct usb_hub *hub)
int status;
hub->quiescing = 0;
+ hub->activating = 1;
status = usb_submit_urb(hub->urb, GFP_NOIO);
if (status < 0)
dev_err(hub->intfdev, "activate --> %d\n", status);
@@ -466,7 +467,6 @@ static void hub_activate(struct usb_hub *hub)
schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);
/* scan all ports ASAP */
- hub->event_bits[0] = (1UL << (hub->descriptor->bNbrPorts + 1)) - 1;
kick_khubd(hub);
}
@@ -689,7 +689,6 @@ static int hub_configure(struct usb_hub *hub,
hub->indicator [0] = INDICATOR_CYCLE;
hub_power_on(hub);
- hub->change_bits[0] = (1UL << (hub->descriptor->bNbrPorts + 1)) - 2;
hub_activate(hub);
return 0;
@@ -1103,23 +1102,33 @@ static int choose_configuration(struct usb_device *udev)
}
#ifdef DEBUG
-static void show_string(struct usb_device *udev, char *id, int index)
+static void show_string(struct usb_device *udev, char *id, char *string)
+{
+ if (!string)
+ return;
+ dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string);
+}
+
+#else
+static inline void show_string(struct usb_device *udev, char *id, char *string)
+{}
+#endif
+
+static void get_string(struct usb_device *udev, char **string, int index)
{
char *buf;
if (!index)
return;
- if (!(buf = kmalloc(256, GFP_KERNEL)))
+ buf = kmalloc(256, GFP_KERNEL);
+ if (!buf)
return;
if (usb_string(udev, index, buf, 256) > 0)
- dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, buf);
- kfree(buf);
+ *string = buf;
+ else
+ kfree(buf);
}
-#else
-static inline void show_string(struct usb_device *udev, char *id, int index)
-{}
-#endif
#ifdef CONFIG_USB_OTG
#include "otg_whitelist.h"
@@ -1157,22 +1166,20 @@ int usb_new_device(struct usb_device *udev)
goto fail;
}
+ /* read the standard strings and cache them if present */
+ get_string(udev, &udev->product, udev->descriptor.iProduct);
+ get_string(udev, &udev->manufacturer, udev->descriptor.iManufacturer);
+ get_string(udev, &udev->serial, udev->descriptor.iSerialNumber);
+
/* Tell the world! */
dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
"SerialNumber=%d\n",
udev->descriptor.iManufacturer,
udev->descriptor.iProduct,
udev->descriptor.iSerialNumber);
-
- if (udev->descriptor.iProduct)
- show_string(udev, "Product",
- udev->descriptor.iProduct);
- if (udev->descriptor.iManufacturer)
- show_string(udev, "Manufacturer",
- udev->descriptor.iManufacturer);
- if (udev->descriptor.iSerialNumber)
- show_string(udev, "SerialNumber",
- udev->descriptor.iSerialNumber);
+ show_string(udev, "Product", udev->product);
+ show_string(udev, "Manufacturer", udev->manufacturer);
+ show_string(udev, "SerialNumber", udev->serial);
#ifdef CONFIG_USB_OTG
/*
@@ -1214,7 +1221,7 @@ int usb_new_device(struct usb_device *udev)
bus->b_hnp_enable
? USB_DEVICE_B_HNP_ENABLE
: USB_DEVICE_A_ALT_HNP_SUPPORT,
- 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+ 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
if (err < 0) {
/* OTG MESSAGE: report errors here,
* customize to match your product.
@@ -1235,10 +1242,10 @@ int usb_new_device(struct usb_device *udev)
*/
if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
static int __usb_suspend_device (struct usb_device *,
- int port1, u32 state);
+ int port1, pm_message_t state);
err = __usb_suspend_device(udev,
udev->bus->otg_port,
- PM_SUSPEND_MEM);
+ PMSG_SUSPEND);
if (err < 0)
dev_dbg(&udev->dev, "HNP fail, %d\n", err);
}
@@ -1526,7 +1533,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
* Linux (2.6) currently has NO mechanisms to initiate that: no khubd
* timer, no SRP, no requests through sysfs.
*/
-int __usb_suspend_device (struct usb_device *udev, int port1, u32 state)
+int __usb_suspend_device (struct usb_device *udev, int port1, pm_message_t state)
{
int status;
@@ -1624,7 +1631,7 @@ int __usb_suspend_device (struct usb_device *udev, int port1, u32 state)
/**
* usb_suspend_device - suspend a usb device
* @udev: device that's no longer in active use
- * @state: PM_SUSPEND_MEM to suspend
+ * @state: PMSG_SUSPEND to suspend
* Context: must be able to sleep; device not locked
*
* Suspends a USB device that isn't in active use, conserving power.
@@ -1673,7 +1680,7 @@ static int finish_port_resume(struct usb_device *udev)
usb_set_device_state(udev, udev->actconfig
? USB_STATE_CONFIGURED
: USB_STATE_ADDRESS);
- udev->dev.power.power_state = PM_SUSPEND_ON;
+ udev->dev.power.power_state = PMSG_ON;
/* 10.5.4.5 says be sure devices in the tree are still there.
* For now let's assume the device didn't go crazy on resume,
@@ -1874,7 +1881,7 @@ static int remote_wakeup(struct usb_device *udev)
return status;
}
-static int hub_suspend(struct usb_interface *intf, u32 state)
+static int hub_suspend(struct usb_interface *intf, pm_message_t state)
{
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev = hub->hdev;
@@ -1946,7 +1953,7 @@ static int hub_resume(struct usb_interface *intf)
}
up(&udev->serialize);
}
- intf->dev.power.power_state = PM_SUSPEND_ON;
+ intf->dev.power.power_state = PMSG_ON;
hub_activate(hub);
return 0;
@@ -2058,7 +2065,7 @@ static int hub_set_address(struct usb_device *udev)
return -EINVAL;
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
- NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval == 0) {
usb_set_device_state(udev, USB_STATE_ADDRESS);
ep0_reinit(udev);
@@ -2181,24 +2188,35 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = -ENOMEM;
continue;
}
- buf->bMaxPacketSize0 = 0;
/* Use a short timeout the first time through,
* so that recalcitrant full-speed devices with
* 8- or 16-byte ep0-maxpackets won't slow things
* down tremendously by NAKing the unexpectedly
- * early status stage. Also, retry on length 0
- * or stall; some devices are flakey.
+ * early status stage. Also, retry on all errors;
+ * some devices are flakey.
*/
for (j = 0; j < 3; ++j) {
+ buf->bMaxPacketSize0 = 0;
r = usb_control_msg(udev, usb_rcvaddr0pipe(),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
USB_DT_DEVICE << 8, 0,
buf, GET_DESCRIPTOR_BUFSIZE,
- (i ? HZ * USB_CTRL_GET_TIMEOUT : HZ));
- if (r == 0 || r == -EPIPE)
- continue;
- if (r < 0)
+ (i ? USB_CTRL_GET_TIMEOUT : 1000));
+ switch (buf->bMaxPacketSize0) {
+ case 8: case 16: case 32: case 64:
+ if (buf->bDescriptorType ==
+ USB_DT_DEVICE) {
+ r = 0;
+ break;
+ }
+ /* FALL THROUGH */
+ default:
+ if (r == 0)
+ r = -EPROTO;
+ break;
+ }
+ if (r == 0)
break;
}
udev->descriptor.bMaxPacketSize0 =
@@ -2214,10 +2232,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = -ENODEV;
goto fail;
}
- switch (udev->descriptor.bMaxPacketSize0) {
- case 64: case 32: case 16: case 8:
- break;
- default:
+ if (r) {
dev_err(&udev->dev, "device descriptor "
"read/%s, error %d\n",
"64", r);
@@ -2630,7 +2645,7 @@ static void hub_events(void)
for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
connect_change = test_bit(i, hub->change_bits);
if (!test_and_clear_bit(i, hub->event_bits) &&
- !connect_change)
+ !connect_change && !hub->activating)
continue;
ret = hub_port_status(hub, i,
@@ -2638,6 +2653,11 @@ static void hub_events(void)
if (ret < 0)
continue;
+ if (hub->activating && !hdev->children[i-1] &&
+ (portstatus &
+ USB_PORT_STAT_CONNECTION))
+ connect_change = 1;
+
if (portchange & USB_PORT_STAT_C_CONNECTION) {
clear_port_feature(hdev, i,
USB_PORT_FEAT_C_CONNECTION);
@@ -2728,6 +2748,8 @@ static void hub_events(void)
}
}
+ hub->activating = 0;
+
loop:
usb_unlock_device(hdev);
usb_put_intf(intf);
@@ -2952,7 +2974,7 @@ int usb_reset_device(struct usb_device *udev)
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_CONFIGURATION, 0,
udev->actconfig->desc.bConfigurationValue, 0,
- NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
if (ret < 0) {
dev_err(&udev->dev,
"can't restore configuration #%d (error=%d)\n",
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index b8f8a1159007..265ab9d7c744 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -215,6 +215,7 @@ struct usb_hub {
u8 power_budget; /* in 2mA units; or zero */
unsigned quiescing:1;
+ unsigned activating:1;
unsigned has_indicators:1;
enum hub_led_mode indicator[USB_MAXCHILDREN];
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index e0165ae9cfc0..b4624501cd58 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -55,7 +55,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
if (status == 0) {
if (timeout > 0) {
init_timer(&timer);
- timer.expires = jiffies + timeout;
+ timer.expires = jiffies + msecs_to_jiffies(timeout);
timer.data = (unsigned long)urb;
timer.function = timeout_kill;
/* grr. timeout _should_ include submit delays. */
@@ -65,12 +65,18 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
status = urb->status;
/* note: HCDs return ETIMEDOUT for other reasons too */
if (status == -ECONNRESET) {
- dev_warn(&urb->dev->dev,
- "%s timed out on ep%d%s\n",
+ dev_dbg(&urb->dev->dev,
+ "%s timed out on ep%d%s len=%d/%d\n",
current->comm,
usb_pipeendpoint(urb->pipe),
- usb_pipein(urb->pipe) ? "in" : "out");
- status = -ETIMEDOUT;
+ usb_pipein(urb->pipe) ? "in" : "out",
+ urb->actual_length,
+ urb->transfer_buffer_length
+ );
+ if (urb->actual_length > 0)
+ status = 0;
+ else
+ status = -ETIMEDOUT;
}
if (timeout > 0)
del_timer_sync(&timer);
@@ -115,7 +121,7 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
* @index: USB message index value
* @data: pointer to the data to send
* @size: length in bytes of the data to send
- * @timeout: time in jiffies to wait for the message to complete before
+ * @timeout: time in msecs to wait for the message to complete before
* timing out (if 0 the wait is forever)
* Context: !in_interrupt ()
*
@@ -163,7 +169,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
* @data: pointer to the data to send
* @len: length in bytes of the data to send
* @actual_length: pointer to a location to put the actual length transferred in bytes
- * @timeout: time in jiffies to wait for the message to complete before
+ * @timeout: time in msecs to wait for the message to complete before
* timing out (if 0 the wait is forever)
* Context: !in_interrupt ()
*
@@ -196,7 +202,7 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL);
- return usb_start_wait_urb(urb,timeout,actual_length);
+ return usb_start_wait_urb(urb, timeout, actual_length);
}
/*-------------------------------------------------------------------*/
@@ -579,7 +585,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(type << 8) + index, 0, buf, size,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
if (result == 0 || result == -EPIPE)
continue;
if (result > 1 && ((u8 *)buf)[1] != type) {
@@ -624,7 +630,7 @@ int usb_get_string(struct usb_device *dev, unsigned short langid,
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(USB_DT_STRING << 8) + index, langid, buf, size,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
if (!(result == 0 || result == -EPIPE))
break;
}
@@ -834,7 +840,7 @@ int usb_get_status(struct usb_device *dev, int type, int target, void *data)
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status,
- sizeof(*status), HZ * USB_CTRL_GET_TIMEOUT);
+ sizeof(*status), USB_CTRL_GET_TIMEOUT);
*(u16 *)data = *status;
kfree(status);
@@ -879,7 +885,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
USB_ENDPOINT_HALT, endp, NULL, 0,
- HZ * USB_CTRL_SET_TIMEOUT);
+ USB_CTRL_SET_TIMEOUT);
/* don't un-halt or force to DATA0 except on success */
if (result < 0)
@@ -982,6 +988,8 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
dev_dbg (&dev->dev, "unregistering interface %s\n",
interface->dev.bus_id);
usb_remove_sysfs_intf_files(interface);
+ kfree(interface->cur_altsetting->string);
+ interface->cur_altsetting->string = NULL;
device_del (&interface->dev);
}
@@ -1101,7 +1109,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
- alternate, interface, NULL, 0, HZ * 5);
+ alternate, interface, NULL, 0, 5000);
/* 9.4.10 says devices don't need this and are free to STALL the
* request if the interface only has one alternate setting.
@@ -1123,10 +1131,29 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
/* prevent submissions using previous endpoint settings */
usb_disable_interface(dev, iface);
+ /* 9.1.1.5 says:
+ *
+ * Configuring a device or changing an alternate setting
+ * causes all of the status and configuration values
+ * associated with endpoints in the affected interfaces to
+ * be set to their default values. This includes setting
+ * the data toggle of any endpoint using data toggles to
+ * the value DATA0.
+ *
+ * Some devices take this too literally and don't reset the data
+ * toggles if the new altsetting is the same as the old one (the
+ * command isn't "changing" an alternate setting). We will manually
+ * reset the toggles when the new and old altsettings are the same.
+ * Most devices won't need this, but fortunately it doesn't happen
+ * often.
+ */
+ if (iface->cur_altsetting == alt)
+ manual = 1;
iface->cur_altsetting = alt;
/* If the interface only has one altsetting and the device didn't
- * accept the request, we attempt to carry out the equivalent action
+ * accept the request (or whenever the old altsetting is the same
+ * as the new one), we attempt to carry out the equivalent action
* by manually clearing the HALT feature for each endpoint in the
* new altsetting.
*/
@@ -1202,7 +1229,7 @@ int usb_reset_configuration(struct usb_device *dev)
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_CONFIGURATION, 0,
config->desc.bConfigurationValue, 0,
- NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval < 0) {
usb_set_device_state(dev, USB_STATE_ADDRESS);
return retval;
@@ -1337,7 +1364,7 @@ free_interfaces:
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
- NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0)
+ NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0)
goto free_interfaces;
dev->actconfig = cp;
@@ -1386,6 +1413,13 @@ free_interfaces:
}
kfree(new_interfaces);
+ if ((cp->desc.iConfiguration) &&
+ (cp->string == NULL)) {
+ cp->string = kmalloc(256, GFP_KERNEL);
+ if (cp->string)
+ usb_string(dev, cp->desc.iConfiguration, cp->string, 256);
+ }
+
/* Now that all the interfaces are set up, register them
* to trigger binding of drivers to interfaces. probe()
* routines may install different altsettings and may
@@ -1409,6 +1443,13 @@ free_interfaces:
ret);
continue;
}
+ if ((intf->cur_altsetting->desc.iInterface) &&
+ (intf->cur_altsetting->string == NULL)) {
+ intf->cur_altsetting->string = kmalloc(256, GFP_KERNEL);
+ if (intf->cur_altsetting->string)
+ usb_string(dev, intf->cur_altsetting->desc.iInterface,
+ intf->cur_altsetting->string, 256);
+ }
usb_create_sysfs_intf_files (intf);
}
}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index ce71f7af7478..ec9b3bde8ae5 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -46,27 +46,24 @@ usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
usb_actconfig_attr (bmAttributes, 1, "%2x\n")
usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
-#define usb_actconfig_str(name, field) \
-static ssize_t show_##name(struct device *dev, char *buf) \
-{ \
- struct usb_device *udev; \
- struct usb_host_config *actconfig; \
- int len; \
- \
- udev = to_usb_device (dev); \
- actconfig = udev->actconfig; \
- if (!actconfig) \
- return 0; \
- len = usb_string(udev, actconfig->desc.field, buf, PAGE_SIZE); \
- if (len < 0) \
- return 0; \
- buf[len] = '\n'; \
- buf[len+1] = 0; \
- return len+1; \
-} \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+static ssize_t show_configuration_string(struct device *dev, char *buf)
+{
+ struct usb_device *udev;
+ struct usb_host_config *actconfig;
+ int len;
-usb_actconfig_str (configuration, iConfiguration)
+ udev = to_usb_device (dev);
+ actconfig = udev->actconfig;
+ if ((!actconfig) || (!actconfig->string))
+ return 0;
+ len = sprintf(buf, actconfig->string, PAGE_SIZE);
+ if (len < 0)
+ return 0;
+ buf[len] = '\n';
+ buf[len+1] = 0;
+ return len+1;
+}
+static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
/* configuration value is always present, and r/w */
usb_actconfig_show(bConfigurationValue, 1, "%u\n");
@@ -89,14 +86,14 @@ static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
show_bConfigurationValue, set_bConfigurationValue);
/* String fields */
-#define usb_string_attr(name, field) \
+#define usb_string_attr(name) \
static ssize_t show_##name(struct device *dev, char *buf) \
{ \
struct usb_device *udev; \
int len; \
\
udev = to_usb_device (dev); \
- len = usb_string(udev, udev->descriptor.field, buf, PAGE_SIZE); \
+ len = snprintf(buf, 256, "%s", udev->name); \
if (len < 0) \
return 0; \
buf[len] = '\n'; \
@@ -105,9 +102,9 @@ static ssize_t show_##name(struct device *dev, char *buf) \
} \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
-usb_string_attr(product, iProduct);
-usb_string_attr(manufacturer, iManufacturer);
-usb_string_attr(serial, iSerialNumber);
+usb_string_attr(product);
+usb_string_attr(manufacturer);
+usb_string_attr(serial);
static ssize_t
show_speed (struct device *dev, char *buf)
@@ -230,11 +227,11 @@ void usb_create_sysfs_dev_files (struct usb_device *udev)
sysfs_create_group(&dev->kobj, &dev_attr_grp);
- if (udev->descriptor.iManufacturer)
+ if (udev->manufacturer)
device_create_file (dev, &dev_attr_manufacturer);
- if (udev->descriptor.iProduct)
+ if (udev->product)
device_create_file (dev, &dev_attr_product);
- if (udev->descriptor.iSerialNumber)
+ if (udev->serial)
device_create_file (dev, &dev_attr_serial);
device_create_file (dev, &dev_attr_configuration);
}
@@ -272,25 +269,22 @@ usb_intf_attr (bInterfaceClass, "%02x\n")
usb_intf_attr (bInterfaceSubClass, "%02x\n")
usb_intf_attr (bInterfaceProtocol, "%02x\n")
-#define usb_intf_str(name, field) \
-static ssize_t show_##name(struct device *dev, char *buf) \
-{ \
- struct usb_interface *intf; \
- struct usb_device *udev; \
- int len; \
- \
- intf = to_usb_interface (dev); \
- udev = interface_to_usbdev (intf); \
- len = usb_string(udev, intf->cur_altsetting->desc.field, buf, PAGE_SIZE);\
- if (len < 0) \
- return 0; \
- buf[len] = '\n'; \
- buf[len+1] = 0; \
- return len+1; \
-} \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
-
-usb_intf_str (interface, iInterface);
+static ssize_t show_interface_string(struct device *dev, char *buf)
+{
+ struct usb_interface *intf;
+ struct usb_device *udev;
+ int len;
+
+ intf = to_usb_interface (dev);
+ udev = interface_to_usbdev (intf);
+ len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
+ if (len < 0)
+ return 0;
+ buf[len] = '\n';
+ buf[len+1] = 0;
+ return len+1;
+}
+static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);
static struct attribute *intf_attrs[] = {
&dev_attr_bInterfaceNumber.attr,
@@ -309,7 +303,7 @@ void usb_create_sysfs_intf_files (struct usb_interface *intf)
{
sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
- if (intf->cur_altsetting->desc.iInterface)
+ if (intf->cur_altsetting->string)
device_create_file(&intf->dev, &dev_attr_interface);
}
@@ -318,7 +312,7 @@ void usb_remove_sysfs_intf_files (struct usb_interface *intf)
{
sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
- if (intf->cur_altsetting->desc.iInterface)
+ if (intf->cur_altsetting->string)
device_remove_file(&intf->dev, &dev_attr_interface);
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 99268c2e5164..9fd8b495427f 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -647,7 +647,10 @@ static void usb_release_dev(struct device *dev)
usb_destroy_configuration(udev);
usb_bus_put(udev->bus);
- kfree (udev);
+ kfree(udev->product);
+ kfree(udev->manufacturer);
+ kfree(udev->serial);
+ kfree(udev);
}
/**
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index fa34e8a13b61..8b2c34ea98ee 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -87,10 +87,10 @@ config USB_NET2280
default USB_GADGET
config USB_GADGET_PXA2XX
- boolean "PXA 2xx or IXP 4xx"
- depends on ARCH_PXA || ARCH_IXP4XX
+ boolean "PXA 25x or IXP 4xx"
+ depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
help
- Intel's PXA 2xx series XScale ARM-5TE processors include
+ Intel's PXA 25x series XScale ARM-5TE processors include
an integrated full speed USB 1.1 device controller. The
controller in the IXP 4xx series is register-compatible.
@@ -194,7 +194,7 @@ config USB_DUMMY_HCD
config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
depends on ARCH_OMAP
- select ISP1301_OMAP if MACH_OMAP_H2
+ select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
help
Many Texas Instruments OMAP processors have flexible full
speed USB device controllers, with support for up to 30
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 702de0302795..50832010b4ef 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -4,7 +4,7 @@
* Maintainer: Alan Stern <stern@rowland.harvard.edu>
*
* Copyright (C) 2003 David Brownell
- * Copyright (C) 2003, 2004 Alan Stern
+ * Copyright (C) 2003-2005 Alan Stern
*
* 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
@@ -167,7 +167,6 @@ struct dummy {
*/
struct timer_list timer;
u32 port_status;
- unsigned started:1;
unsigned resuming:1;
unsigned long re_timeout;
@@ -1637,7 +1636,6 @@ static int dummy_start (struct usb_hcd *hcd)
* just like more familiar pci-based HCDs.
*/
spin_lock_init (&dum->lock);
-
init_timer (&dum->timer);
dum->timer.function = dummy_timer;
dum->timer.data = (unsigned long) dum;
@@ -1654,25 +1652,25 @@ static int dummy_start (struct usb_hcd *hcd)
/* ...then configured, so khubd sees us. */
if ((retval = hcd_register_root (root, hcd)) != 0) {
- usb_put_dev (root);
-clean:
- hcd->state = USB_STATE_QUIESCING;
- return retval;
+ goto err1;
}
/* only show a low-power port: just 8mA */
hub_set_power_budget (root, 8);
- if ((retval = dummy_register_udc (dum)) != 0) {
- usb_disconnect (&hcd->self.root_hub);
- goto clean;
- }
+ if ((retval = dummy_register_udc (dum)) != 0)
+ goto err2;
/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
device_create_file (dummy_dev(dum), &dev_attr_urbs);
-
- dum->started = 1;
return 0;
+
+ err2:
+ usb_disconnect (&hcd->self.root_hub);
+ err1:
+ usb_put_dev (root);
+ hcd->state = USB_STATE_QUIESCING;
+ return retval;
}
static void dummy_stop (struct usb_hcd *hcd)
@@ -1680,9 +1678,6 @@ static void dummy_stop (struct usb_hcd *hcd)
struct dummy *dum;
dum = hcd_to_dummy (hcd);
- if (!dum->started)
- return;
- dum->started = 0;
device_remove_file (dummy_dev(dum), &dev_attr_urbs);
@@ -1718,71 +1713,33 @@ static const struct hc_driver dummy_hcd = {
.hub_control = dummy_hub_control,
};
-static void dummy_remove (struct device *dev);
-
static int dummy_probe (struct device *dev)
{
struct usb_hcd *hcd;
- struct dummy *dum;
int retval;
dev_info (dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
- hcd = usb_create_hcd (&dummy_hcd);
- if (hcd == NULL) {
- dev_dbg (dev, "hcd_alloc failed\n");
+ hcd = usb_create_hcd (&dummy_hcd, dev, dev->bus_id);
+ if (!hcd)
return -ENOMEM;
- }
+ the_controller = hcd_to_dummy (hcd);
- dev_set_drvdata (dev, hcd);
- dum = hcd_to_dummy (hcd);
- the_controller = dum;
-
- hcd->self.controller = dev;
-
- /* FIXME don't require the pci-based buffer/alloc impls;
- * the "generic dma" implementation still requires them,
- * it's not very generic yet.
- */
- retval = hcd_buffer_create (hcd);
+ retval = usb_add_hcd(hcd, 0, 0);
if (retval != 0) {
- dev_dbg (dev, "pool alloc failed\n");
- goto err1;
+ usb_put_hcd (hcd);
+ the_controller = NULL;
}
-
- hcd->self.bus_name = dev->bus_id;
- usb_register_bus (&hcd->self);
-
- if ((retval = dummy_start (hcd)) < 0)
- dummy_remove (dev);
- return retval;
-
-err1:
- usb_put_hcd (hcd);
- dev_set_drvdata (dev, NULL);
return retval;
}
static void dummy_remove (struct device *dev)
{
struct usb_hcd *hcd;
- struct dummy *dum;
hcd = dev_get_drvdata (dev);
- dum = hcd_to_dummy (hcd);
-
- hcd->state = USB_STATE_QUIESCING;
-
- dev_dbg (dev, "roothub graceful disconnect\n");
- usb_disconnect (&hcd->self.root_hub);
-
- hcd->driver->stop (hcd);
- hcd->state = USB_STATE_HALT;
-
- hcd_buffer_destroy (hcd);
-
- dev_set_drvdata (dev, NULL);
- usb_deregister_bus (&hcd->self);
+ usb_remove_hcd (hcd);
+ usb_put_hcd (hcd);
the_controller = NULL;
}
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 48ec722d3091..8f32b79e41de 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -49,6 +49,7 @@
#include <asm/unaligned.h>
#include <linux/usb_ch9.h>
+#include <linux/usb_cdc.h>
#include <linux/usb_gadget.h>
#include <linux/random.h>
@@ -259,6 +260,9 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define DEV_CONFIG_CDC
+#endif
/*-------------------------------------------------------------------------*/
@@ -432,8 +436,8 @@ control_intf = {
/* status endpoint is optional; this may be patched later */
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = 6, /* ethernet control model */
- .bInterfaceProtocol = 0,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE,
.iInterface = STRING_CONTROL,
};
#endif
@@ -447,46 +451,26 @@ rndis_control_intf = {
.bInterfaceNumber = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = 2, /* abstract control model */
- .bInterfaceProtocol = 0xff, /* vendor specific */
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
+ .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR,
.iInterface = STRING_RNDIS_CONTROL,
};
#endif
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
-struct header_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
-
- u16 bcdCDC;
-} __attribute__ ((packed));
-
-static const struct header_desc header_desc = {
+static const struct usb_cdc_header_desc header_desc = {
.bLength = sizeof header_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = 0,
+ .bDescriptorSubType = USB_CDC_HEADER_TYPE,
.bcdCDC = __constant_cpu_to_le16 (0x0110),
};
-/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */
-struct union_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
-
- u8 bMasterInterface0;
- u8 bSlaveInterface0;
- /* ... and there could be other slave interfaces */
-} __attribute__ ((packed));
-
-static const struct union_desc union_desc = {
+static const struct usb_cdc_union_desc union_desc = {
.bLength = sizeof union_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = 6,
+ .bDescriptorSubType = USB_CDC_UNION_TYPE,
.bMasterInterface0 = 0, /* index of control interface */
.bSlaveInterface0 = 1, /* index of DATA interface */
@@ -496,64 +480,31 @@ static const struct union_desc union_desc = {
#ifdef CONFIG_USB_ETH_RNDIS
-/* "Call Management Descriptor" from CDC spec 5.2.3.3 */
-struct call_mgmt_descriptor {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
-
- u8 bmCapabilities;
- u8 bDataInterface;
-} __attribute__ ((packed));
-
-static const struct call_mgmt_descriptor call_mgmt_descriptor = {
+static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
.bLength = sizeof call_mgmt_descriptor,
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = 0x01,
+ .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
.bmCapabilities = 0x00,
.bDataInterface = 0x01,
};
-
-/* "Abstract Control Management Descriptor" from CDC spec 5.2.3.4 */
-struct acm_descriptor {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
-
- u8 bmCapabilities;
-} __attribute__ ((packed));
-
-static struct acm_descriptor acm_descriptor = {
+static struct usb_cdc_acm_descriptor acm_descriptor = {
.bLength = sizeof acm_descriptor,
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = 0x02,
+ .bDescriptorSubType = USB_CDC_ACM_TYPE,
- .bmCapabilities = 0X00,
+ .bmCapabilities = 0x00,
};
#endif
#ifdef DEV_CONFIG_CDC
-/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
-struct ether_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
-
- u8 iMACAddress;
- u32 bmEthernetStatistics;
- u16 wMaxSegmentSize;
- u16 wNumberMCFilters;
- u8 bNumberPowerFilters;
-} __attribute__ ((packed));
-
-static const struct ether_desc ether_desc = {
+static const struct usb_cdc_ether_desc ether_desc = {
.bLength = sizeof ether_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = 0x0f,
+ .bDescriptorSubType = USB_CDC_ETHERNET_TYPE,
/* this descriptor actually adds value, surprise! */
.iMACAddress = STRING_ETHADDR,
@@ -1242,47 +1193,30 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
/*-------------------------------------------------------------------------*/
-/* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications
- * section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS
- * and RNDIS also defines its own bit-incompatible notifications
- */
-#define CDC_NOTIFY_NETWORK_CONNECTION 0x00 /* required; 6.3.1 */
-#define CDC_NOTIFY_RESPONSE_AVAILABLE 0x01 /* optional; 6.3.2 */
-#define CDC_NOTIFY_SPEED_CHANGE 0x2a /* required; 6.3.8 */
-
#ifdef DEV_CONFIG_CDC
-struct cdc_notification {
- u8 bmRequestType;
- u8 bNotificationType;
- u16 wValue;
- u16 wIndex;
- u16 wLength;
-
- /* SPEED_CHANGE data looks like this */
- u32 data [2];
-};
-
static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
{
- struct cdc_notification *event = req->buf;
- int value = req->status;
- struct eth_dev *dev = ep->driver_data;
+ struct usb_cdc_notification *event = req->buf;
+ int value = req->status;
+ struct eth_dev *dev = ep->driver_data;
/* issue the second notification if host reads the first */
- if (event->bNotificationType == CDC_NOTIFY_NETWORK_CONNECTION
+ if (event->bNotificationType == USB_CDC_NOTIFY_NETWORK_CONNECTION
&& value == 0) {
+ __le32 *data = req->buf + sizeof *event;
+
event->bmRequestType = 0xA1;
- event->bNotificationType = CDC_NOTIFY_SPEED_CHANGE;
+ event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
event->wValue = __constant_cpu_to_le16 (0);
event->wIndex = __constant_cpu_to_le16 (1);
event->wLength = __constant_cpu_to_le16 (8);
/* SPEED_CHANGE data is up/down speeds in bits/sec */
- event->data [0] = event->data [1] =
+ data [0] = data [1] = cpu_to_le32(
(dev->gadget->speed == USB_SPEED_HIGH)
? (13 * 512 * 8 * 1000 * 8)
- : (19 * 64 * 1 * 1000 * 8);
+ : (19 * 64 * 1 * 1000 * 8));
req->length = 16;
value = usb_ep_queue (ep, req, GFP_ATOMIC);
@@ -1300,9 +1234,9 @@ static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
static void issue_start_status (struct eth_dev *dev)
{
- struct usb_request *req;
- struct cdc_notification *event;
- int value;
+ struct usb_request *req;
+ struct usb_cdc_notification *event;
+ int value;
DEBUG (dev, "%s, flush old status first\n", __FUNCTION__);
@@ -1336,7 +1270,7 @@ free_req:
*/
event = req->buf;
event->bmRequestType = 0xA1;
- event->bNotificationType = CDC_NOTIFY_NETWORK_CONNECTION;
+ event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
event->wValue = __constant_cpu_to_le16 (1); /* connected */
event->wIndex = __constant_cpu_to_le16 (1);
event->wLength = 0;
@@ -1364,26 +1298,6 @@ static void eth_setup_complete (struct usb_ep *ep, struct usb_request *req)
req->status, req->actual, req->length);
}
-/* see section 3.8.2 table 10 of the CDC spec for more ethernet
- * requests, mostly for filters (multicast, pm) and statistics
- * section 3.6.2.1 table 4 has ACM requests; RNDIS requires the
- * encapsulated command mechanism.
- */
-#define CDC_SEND_ENCAPSULATED_COMMAND 0x00 /* optional */
-#define CDC_GET_ENCAPSULATED_RESPONSE 0x01 /* optional */
-#define CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 /* optional */
-#define CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41 /* optional */
-#define CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42 /* optional */
-#define CDC_SET_ETHERNET_PACKET_FILTER 0x43 /* required */
-#define CDC_GET_ETHERNET_STATISTIC 0x44 /* optional */
-
-/* table 62; bits in cdc_filter */
-#define CDC_PACKET_TYPE_PROMISCUOUS (1 << 0)
-#define CDC_PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */
-#define CDC_PACKET_TYPE_DIRECTED (1 << 2)
-#define CDC_PACKET_TYPE_BROADCAST (1 << 3)
-#define CDC_PACKET_TYPE_MULTICAST (1 << 4) /* filtered */
-
#ifdef CONFIG_USB_ETH_RNDIS
static void rndis_response_complete (struct usb_ep *ep, struct usb_request *req)
@@ -1393,7 +1307,7 @@ static void rndis_response_complete (struct usb_ep *ep, struct usb_request *req)
"rndis response complete --> %d, %d/%d\n",
req->status, req->actual, req->length);
- /* done sending after CDC_GET_ENCAPSULATED_RESPONSE */
+ /* done sending after USB_CDC_GET_ENCAPSULATED_RESPONSE */
}
static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req)
@@ -1401,7 +1315,7 @@ static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req)
struct eth_dev *dev = ep->driver_data;
int status;
- /* received RNDIS command from CDC_SEND_ENCAPSULATED_COMMAND */
+ /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
spin_lock(&dev->lock);
status = rndis_msg_parser (dev->rndis_config, (u8 *) req->buf);
if (status < 0)
@@ -1426,6 +1340,9 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
struct eth_dev *dev = get_gadget_data (gadget);
struct usb_request *req = dev->req;
int value = -EOPNOTSUPP;
+ u16 wIndex = ctrl->wIndex;
+ u16 wValue = ctrl->wValue;
+ u16 wLength = ctrl->wLength;
/* descriptors just go into the pre-allocated ep0 buffer,
* while config change events may enable network traffic.
@@ -1436,17 +1353,17 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
case USB_REQ_GET_DESCRIPTOR:
if (ctrl->bRequestType != USB_DIR_IN)
break;
- switch (ctrl->wValue >> 8) {
+ switch (wValue >> 8) {
case USB_DT_DEVICE:
- value = min (ctrl->wLength, (u16) sizeof device_desc);
+ value = min (wLength, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value);
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
if (!gadget->is_dualspeed)
break;
- value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
+ value = min (wLength, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value);
break;
@@ -1457,18 +1374,18 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
value = config_buf (gadget->speed, req->buf,
- ctrl->wValue >> 8,
- ctrl->wValue & 0xff,
+ wValue >> 8,
+ wValue & 0xff,
gadget->is_otg);
if (value >= 0)
- value = min (ctrl->wLength, (u16) value);
+ value = min (wLength, (u16) value);
break;
case USB_DT_STRING:
value = usb_gadget_get_string (&stringtab,
- ctrl->wValue & 0xff, req->buf);
+ wValue & 0xff, req->buf);
if (value >= 0)
- value = min (ctrl->wLength, (u16) value);
+ value = min (wLength, (u16) value);
break;
}
break;
@@ -1481,22 +1398,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
else if (gadget->a_alt_hnp_support)
DEBUG (dev, "HNP needs a different root port\n");
spin_lock (&dev->lock);
- value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC);
+ value = eth_set_config (dev, wValue, GFP_ATOMIC);
spin_unlock (&dev->lock);
break;
case USB_REQ_GET_CONFIGURATION:
if (ctrl->bRequestType != USB_DIR_IN)
break;
*(u8 *)req->buf = dev->config;
- value = min (ctrl->wLength, (u16) 1);
+ value = min (wLength, (u16) 1);
break;
case USB_REQ_SET_INTERFACE:
if (ctrl->bRequestType != USB_RECIP_INTERFACE
|| !dev->config
- || ctrl->wIndex > 1)
+ || wIndex > 1)
break;
- if (!dev->cdc && ctrl->wIndex != 0)
+ if (!dev->cdc && wIndex != 0)
break;
spin_lock (&dev->lock);
@@ -1510,9 +1427,9 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
}
#ifdef DEV_CONFIG_CDC
- switch (ctrl->wIndex) {
+ switch (wIndex) {
case 0: /* control/master intf */
- if (ctrl->wValue != 0)
+ if (wValue != 0)
break;
if (dev->status_ep) {
usb_ep_disable (dev->status_ep);
@@ -1521,7 +1438,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = 0;
break;
case 1: /* data intf */
- if (ctrl->wValue > 1)
+ if (wValue > 1)
break;
usb_ep_disable (dev->in_ep);
usb_ep_disable (dev->out_ep);
@@ -1530,7 +1447,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
* the default interface setting ... also, setting
* the non-default interface clears filters etc.
*/
- if (ctrl->wValue == 1) {
+ if (wValue == 1) {
usb_ep_enable (dev->in_ep, dev->in);
usb_ep_enable (dev->out_ep, dev->out);
netif_carrier_on (dev->net);
@@ -1561,36 +1478,36 @@ done_set_intf:
case USB_REQ_GET_INTERFACE:
if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
|| !dev->config
- || ctrl->wIndex > 1)
+ || wIndex > 1)
break;
- if (!(dev->cdc || dev->rndis) && ctrl->wIndex != 0)
+ if (!(dev->cdc || dev->rndis) && wIndex != 0)
break;
/* for CDC, iff carrier is on, data interface is active. */
- if (dev->rndis || ctrl->wIndex != 1)
+ if (dev->rndis || wIndex != 1)
*(u8 *)req->buf = 0;
else
*(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0;
- value = min (ctrl->wLength, (u16) 1);
+ value = min (wLength, (u16) 1);
break;
#ifdef DEV_CONFIG_CDC
- case CDC_SET_ETHERNET_PACKET_FILTER:
+ case USB_CDC_SET_ETHERNET_PACKET_FILTER:
/* see 6.2.30: no data, wIndex = interface,
* wValue = packet filter bitmap
*/
if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
|| !dev->cdc
|| dev->rndis
- || ctrl->wLength != 0
- || ctrl->wIndex > 1)
+ || wLength != 0
+ || wIndex > 1)
break;
- DEBUG (dev, "NOP packet filter %04x\n", ctrl->wValue);
+ DEBUG (dev, "NOP packet filter %04x\n", wValue);
/* NOTE: table 62 has 5 filter bits to reduce traffic,
* and we "must" support multicast and promiscuous.
* this NOP implements a bad filter (always promisc)
*/
- dev->cdc_filter = ctrl->wValue;
+ dev->cdc_filter = wValue;
value = 0;
break;
#endif /* DEV_CONFIG_CDC */
@@ -1599,28 +1516,28 @@ done_set_intf:
/* RNDIS uses the CDC command encapsulation mechanism to implement
* an RPC scheme, with much getting/setting of attributes by OID.
*/
- case CDC_SEND_ENCAPSULATED_COMMAND:
+ case USB_CDC_SEND_ENCAPSULATED_COMMAND:
if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
|| !dev->rndis
- || ctrl->wLength > USB_BUFSIZ
- || ctrl->wValue
+ || wLength > USB_BUFSIZ
+ || wValue
|| rndis_control_intf.bInterfaceNumber
- != ctrl->wIndex)
+ != wIndex)
break;
/* read the request, then process it */
- value = ctrl->wLength;
+ value = wLength;
req->complete = rndis_command_complete;
/* later, rndis_control_ack () sends a notification */
break;
- case CDC_GET_ENCAPSULATED_RESPONSE:
+ case USB_CDC_GET_ENCAPSULATED_RESPONSE:
if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)
== ctrl->bRequestType
&& dev->rndis
- // && ctrl->wLength >= 0x0400
- && !ctrl->wValue
+ // && wLength >= 0x0400
+ && !wValue
&& rndis_control_intf.bInterfaceNumber
- == ctrl->wIndex) {
+ == wIndex) {
u8 *buf;
/* return the result */
@@ -1640,13 +1557,13 @@ done_set_intf:
VDEBUG (dev,
"unknown control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
- ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+ wValue, wIndex, wLength);
}
/* respond with data transfer before status phase? */
if (value >= 0) {
req->length = value;
- req->zero = value < ctrl->wLength
+ req->zero = value < wLength
&& (value % gadget->ep0->maxpacket) == 0;
value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
if (value < 0) {
@@ -1761,10 +1678,16 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags)
#endif
size -= size % dev->out_ep->maxpacket;
- if ((skb = alloc_skb (size, gfp_flags)) == 0) {
+ if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) {
DEBUG (dev, "no rx skb\n");
goto enomem;
}
+
+ /* Some platforms perform better when IP packets are aligned,
+ * but on at least one, checksumming fails otherwise. Note:
+ * this doesn't account for variable-sized RNDIS headers.
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
req->buf = skb->data;
req->length = size;
@@ -1990,7 +1913,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
unsigned long flags;
/* FIXME check dev->cdc_filter to decide whether to send this,
- * instead of acting as if CDC_PACKET_TYPE_PROMISCUOUS were
+ * instead of acting as if USB_CDC_PACKET_TYPE_PROMISCUOUS were
* always set. RNDIS has the same kind of outgoing filter.
*/
@@ -2124,13 +2047,13 @@ static int rndis_control_ack (struct net_device *net)
}
/* Send RNDIS RESPONSE_AVAILABLE notification;
- * CDC_NOTIFY_RESPONSE_AVAILABLE should work too
+ * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too
*/
resp->length = 8;
resp->complete = rndis_control_ack_complete;
- *((u32 *) resp->buf) = __constant_cpu_to_le32 (1);
- *((u32 *) resp->buf + 1) = __constant_cpu_to_le32 (0);
+ *((__le32 *) resp->buf) = __constant_cpu_to_le32 (1);
+ *((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0);
length = usb_ep_queue (dev->status_ep, resp, GFP_ATOMIC);
if (length < 0) {
@@ -2326,6 +2249,8 @@ eth_bind (struct usb_gadget *gadget)
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
} else if (gadget_is_pxa27x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
+ } else if (gadget_is_s3c2410(gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
} else {
/* can't assume CDC works. don't want to default to
* anything less functional on CDC-capable hardware,
@@ -2414,9 +2339,12 @@ autoconf_fail:
"can't run RNDIS on %s\n",
gadget->name);
return -ENODEV;
+#ifdef DEV_CONFIG_CDC
+ /* pxa25x only does CDC subset; often used with RNDIS */
} else if (cdc) {
control_intf.bNumEndpoints = 0;
/* FIXME remove endpoint from descriptor list */
+#endif
}
}
#endif
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e893de9fbe33..40c8d2749140 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -74,6 +74,12 @@
#define gadget_is_pxa27x(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name)
+#else
+#define gadget_is_s3c2410(g) 0
+#endif
+
// CONFIG_USB_GADGET_AT91RM9200
// CONFIG_USB_GADGET_SX2
// CONFIG_USB_GADGET_AU1X00
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index d2997ef3cd6a..50e48b17bc4a 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -1,8 +1,9 @@
/*
- * Driver for the NetChip 2280 USB device controller.
- * Specs and errata are available from <http://www.netchip.com>.
+ * Driver for the PLX NET2280 USB device controller.
+ * Specs and errata are available from <http://www.plxtech.com>.
*
- * NetChip Technology Inc. supported the development of this driver.
+ * PLX Technology Inc. (formerly NetChip Technology) supported the
+ * development of this driver.
*
*
* CODE STATUS HIGHLIGHTS
@@ -23,7 +24,7 @@
/*
* Copyright (C) 2003 David Brownell
- * Copyright (C) 2003 NetChip Technologies
+ * Copyright (C) 2003-2005 PLX Technology, Inc.
*
* 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
@@ -69,8 +70,8 @@
#include <asm/unaligned.h>
-#define DRIVER_DESC "NetChip 2280 USB Peripheral Controller"
-#define DRIVER_VERSION "2004 Jan 14"
+#define DRIVER_DESC "PLX NET2280 USB Peripheral Controller"
+#define DRIVER_VERSION "2005 Feb 03"
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define EP_DONTUSE 13 /* nonzero */
@@ -113,6 +114,16 @@ static ushort fifo_mode = 0;
/* "modprobe net2280 fifo_mode=1" etc */
module_param (fifo_mode, ushort, 0644);
+/* enable_suspend -- When enabled, the driver will respond to
+ * USB suspend requests by powering down the NET2280. Otherwise,
+ * USB suspend requests will be ignored. This is acceptible for
+ * self-powered devices, and helps avoid some quirks.
+ */
+static int enable_suspend = 0;
+
+/* "modprobe net2280 enable_suspend=1" etc */
+module_param (enable_suspend, bool, S_IRUGO);
+
#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
@@ -2561,6 +2572,8 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) {
if (dev->driver->suspend)
dev->driver->suspend (&dev->gadget);
+ if (!enable_suspend)
+ stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
} else {
if (dev->driver->resume)
dev->driver->resume (&dev->gadget);
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index aeb821a5f2c3..b66ea5a6ed79 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -2,7 +2,7 @@
* omap_udc.c -- for OMAP full speed udc; most chips support OTG.
*
* Copyright (C) 2004 Texas Instruments, Inc.
- * Copyright (C) 2004 David Brownell
+ * Copyright (C) 2004-2005 David Brownell
*
* 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
@@ -2046,7 +2046,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
pullup_disable (udc);
}
- if (machine_is_omap_innovator())
+ /* boards that don't have VBUS sensing can't autogate 48MHz;
+ * can't enter deep sleep while a gadget driver is active.
+ */
+ if (machine_is_omap_innovator() || machine_is_omap_osk())
omap_vbus_session(&udc->gadget, 1);
done:
@@ -2064,7 +2067,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
if (!driver || driver != udc->driver)
return -EINVAL;
- if (machine_is_omap_innovator())
+ if (machine_is_omap_innovator() || machine_is_omap_osk())
omap_vbus_session(&udc->gadget, 0);
if (udc->transceiver)
@@ -2157,13 +2160,13 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
}
}
-static char *trx_mode(unsigned m)
+static char *trx_mode(unsigned m, int enabled)
{
switch (m) {
- case 3:
- case 0: return "6wire";
+ case 0: return enabled ? "*6wire" : "unused";
case 1: return "4wire";
case 2: return "3wire";
+ case 3: return "6wire";
default: return "unknown";
}
}
@@ -2171,17 +2174,20 @@ static char *trx_mode(unsigned m)
static int proc_otg_show(struct seq_file *s)
{
u32 tmp;
+ u32 trans;
tmp = OTG_REV_REG;
- seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %08x\n",
- tmp >> 4, tmp & 0xf,
- USB_TRANSCEIVER_CTRL_REG);
+ trans = USB_TRANSCEIVER_CTRL_REG;
+ seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %03x\n",
+ tmp >> 4, tmp & 0xf, trans);
tmp = OTG_SYSCON_1_REG;
seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s,"
FOURBITS "\n", tmp,
- trx_mode(USB2_TRX_MODE(tmp)),
- trx_mode(USB1_TRX_MODE(tmp)),
- trx_mode(USB0_TRX_MODE(tmp)),
+ trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R),
+ trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R),
+ (USB0_TRX_MODE(tmp) == 0)
+ ? "internal"
+ : trx_mode(USB0_TRX_MODE(tmp), 1),
(tmp & OTG_IDLE_EN) ? " !otg" : "",
(tmp & HST_IDLE_EN) ? " !host" : "",
(tmp & DEV_IDLE_EN) ? " !dev" : "",
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 710f7a435f9e..2da469c5c80a 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -943,6 +943,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
UDCCFR = UDCCFR_AREN|UDCCFR_ACM;
done(ep, req, 0);
dev->ep0state = EP0_END_XFER;
+ local_irq_restore (flags);
return 0;
}
if (dev->req_pending)
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index c3d064b09ef1..f70f72bf1be5 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -730,7 +730,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
/* FIXME use these NDIS_PACKET_TYPE_* bitflags to
* filter packets in hard_start_xmit()
- * NDIS_PACKET_TYPE_x == CDC_PACKET_TYPE_x for x in:
+ * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
* PROMISCUOUS, DIRECTED,
* MULTICAST, ALL_MULTICAST, BROADCAST
*/
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 9432b85b8fe2..1e2e1ee95532 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -45,6 +45,7 @@
#include <asm/uaccess.h>
#include <linux/usb_ch9.h>
+#include <linux/usb_cdc.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
@@ -122,80 +123,6 @@ do { \
})
-/* CDC-ACM Defines and Structures */
-
-#define USB_CDC_SUBCLASS_ACM 2
-
-#define USB_CDC_CTRL_PROTO_NONE 0
-#define USB_CDC_CTRL_PROTO_AT 1
-#define USB_CDC_CTRL_PROTO_VENDOR 0xff
-
-#define USB_CDC_SUBTYPE_HEADER 0
-#define USB_CDC_SUBTYPE_CALL_MGMT 1
-#define USB_CDC_SUBTYPE_ACM 2
-#define USB_CDC_SUBTYPE_UNION 6
-
-#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT 0x01
-#define USB_CDC_CALL_MGMT_CAP_DATA_INTF 0x02
-
-#define USB_CDC_REQ_SET_LINE_CODING 0x20
-#define USB_CDC_REQ_GET_LINE_CODING 0x21
-#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
-
-#define USB_CDC_1_STOP_BITS 0
-#define USB_CDC_1_5_STOP_BITS 1
-#define USB_CDC_2_STOP_BITS 2
-
-#define USB_CDC_NO_PARITY 0
-#define USB_CDC_ODD_PARITY 1
-#define USB_CDC_EVEN_PARITY 2
-#define USB_CDC_MARK_PARITY 3
-#define USB_CDC_SPACE_PARITY 4
-
-/* Header Functional Descriptor from CDC spec 5.2.3.1 */
-struct usb_cdc_header_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
- u16 bcdCDC;
-} __attribute__ ((packed));
-
-/* Call Management Descriptor from CDC spec 5.2.3.3 */
-struct usb_cdc_call_mgmt_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
- u8 bmCapabilities;
- u8 bDataInterface;
-} __attribute__ ((packed));
-
-/* Abstract Control Management Descriptor from CDC spec 5.2.3.4 */
-struct usb_cdc_acm_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
- u8 bmCapabilities;
-} __attribute__ ((packed));
-
-/* Union Functional Descriptor from CDC spec 5.2.3.8 */
-struct usb_cdc_union_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
- u8 bMasterInterface0;
- u8 bSlaveInterface0;
- /* ... and there could be other slave interfaces */
-} __attribute__ ((packed));
-
-/* Line Coding Structure from CDC spec 6.2.13 */
-struct usb_cdc_line_coding {
- u32 dwDTERate;
- u8 bCharFormat;
- u8 bParityType;
- u8 bDataBits;
-} __attribute__ ((packed));
-
-
/* Defines */
#define GS_VERSION_STR "v2.0"
@@ -542,7 +469,7 @@ static const struct usb_interface_descriptor gs_control_interface_desc = {
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_COMM,
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
- .bInterfaceProtocol = USB_CDC_CTRL_PROTO_AT,
+ .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER,
.iInterface = GS_CONTROL_STR_ID,
};
@@ -560,29 +487,29 @@ static const struct usb_interface_descriptor gs_data_interface_desc = {
static const struct usb_cdc_header_desc gs_header_desc = {
.bLength = sizeof(gs_header_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_SUBTYPE_HEADER,
+ .bDescriptorSubType = USB_CDC_HEADER_TYPE,
.bcdCDC = __constant_cpu_to_le16(0x0110),
};
-static const struct usb_cdc_call_mgmt_desc gs_call_mgmt_descriptor = {
+static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
.bLength = sizeof(gs_call_mgmt_descriptor),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_SUBTYPE_CALL_MGMT,
+ .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
.bmCapabilities = 0,
.bDataInterface = 1, /* index of data interface */
};
-static struct usb_cdc_acm_desc gs_acm_descriptor = {
+static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
.bLength = sizeof(gs_acm_descriptor),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_SUBTYPE_ACM,
+ .bDescriptorSubType = USB_CDC_ACM_TYPE,
.bmCapabilities = 0,
};
static const struct usb_cdc_union_desc gs_union_desc = {
.bLength = sizeof(gs_union_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_SUBTYPE_UNION,
+ .bDescriptorSubType = USB_CDC_UNION_TYPE,
.bMasterInterface0 = 0, /* index of control interface */
.bSlaveInterface0 = 1, /* index of data interface */
};
@@ -1531,6 +1458,9 @@ static int gs_bind(struct usb_gadget *gadget)
} else if (gadget_is_pxa27x(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0011);
+ } else if (gadget_is_s3c2410(gadget)) {
+ gs_device_desc.bcdDevice =
+ __constant_cpu_to_le16(GS_VERSION_NUM|0x0012);
} else {
printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n",
gadget->name);
@@ -1674,6 +1604,9 @@ static int gs_setup(struct usb_gadget *gadget,
int ret = -EOPNOTSUPP;
struct gs_dev *dev = get_gadget_data(gadget);
struct usb_request *req = dev->dev_ctrl_req;
+ u16 wIndex = ctrl->wIndex;
+ u16 wValue = ctrl->wValue;
+ u16 wLength = ctrl->wLength;
switch (ctrl->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
@@ -1686,15 +1619,15 @@ static int gs_setup(struct usb_gadget *gadget,
default:
printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
- ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
- ctrl->wIndex, ctrl->wLength);
+ ctrl->bRequestType, ctrl->bRequest,
+ wValue, wIndex, wLength);
break;
}
/* respond with data transfer before status phase? */
if (ret >= 0) {
req->length = ret;
- req->zero = ret < ctrl->wLength
+ req->zero = ret < wLength
&& (ret % gadget->ep0->maxpacket) == 0;
ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
if (ret < 0) {
@@ -1715,15 +1648,18 @@ static int gs_setup_standard(struct usb_gadget *gadget,
int ret = -EOPNOTSUPP;
struct gs_dev *dev = get_gadget_data(gadget);
struct usb_request *req = dev->dev_ctrl_req;
+ u16 wIndex = ctrl->wIndex;
+ u16 wValue = ctrl->wValue;
+ u16 wLength = ctrl->wLength;
switch (ctrl->bRequest) {
case USB_REQ_GET_DESCRIPTOR:
if (ctrl->bRequestType != USB_DIR_IN)
break;
- switch (ctrl->wValue >> 8) {
+ switch (wValue >> 8) {
case USB_DT_DEVICE:
- ret = min(ctrl->wLength,
+ ret = min(wLength,
(u16)sizeof(struct usb_device_descriptor));
memcpy(req->buf, &gs_device_desc, ret);
break;
@@ -1732,7 +1668,7 @@ static int gs_setup_standard(struct usb_gadget *gadget,
case USB_DT_DEVICE_QUALIFIER:
if (!gadget->is_dualspeed)
break;
- ret = min(ctrl->wLength,
+ ret = min(wLength,
(u16)sizeof(struct usb_qualifier_descriptor));
memcpy(req->buf, &gs_qualifier_desc, ret);
break;
@@ -1744,18 +1680,18 @@ static int gs_setup_standard(struct usb_gadget *gadget,
#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
ret = gs_build_config_buf(req->buf, gadget->speed,
- ctrl->wValue >> 8, ctrl->wValue & 0xff,
+ wValue >> 8, wValue & 0xff,
gadget->is_otg);
if (ret >= 0)
- ret = min(ctrl->wLength, (u16)ret);
+ ret = min(wLength, (u16)ret);
break;
case USB_DT_STRING:
/* wIndex == language code. */
ret = usb_gadget_get_string(&gs_string_table,
- ctrl->wValue & 0xff, req->buf);
+ wValue & 0xff, req->buf);
if (ret >= 0)
- ret = min(ctrl->wLength, (u16)ret);
+ ret = min(wLength, (u16)ret);
break;
}
break;
@@ -1764,7 +1700,7 @@ static int gs_setup_standard(struct usb_gadget *gadget,
if (ctrl->bRequestType != 0)
break;
spin_lock(&dev->dev_lock);
- ret = gs_set_config(dev, ctrl->wValue);
+ ret = gs_set_config(dev, wValue);
spin_unlock(&dev->dev_lock);
break;
@@ -1772,18 +1708,19 @@ static int gs_setup_standard(struct usb_gadget *gadget,
if (ctrl->bRequestType != USB_DIR_IN)
break;
*(u8 *)req->buf = dev->dev_config;
- ret = min(ctrl->wLength, (u16)1);
+ ret = min(wLength, (u16)1);
break;
case USB_REQ_SET_INTERFACE:
if (ctrl->bRequestType != USB_RECIP_INTERFACE
- || !dev->dev_config || ctrl->wIndex >= GS_MAX_NUM_INTERFACES)
+ || !dev->dev_config
+ || wIndex >= GS_MAX_NUM_INTERFACES)
break;
if (dev->dev_config == GS_BULK_CONFIG_ID
- && ctrl->wIndex != GS_BULK_INTERFACE_ID)
+ && wIndex != GS_BULK_INTERFACE_ID)
break;
/* no alternate interface settings */
- if (ctrl->wValue != 0)
+ if (wValue != 0)
break;
spin_lock(&dev->dev_lock);
/* PXA hardware partially handles SET_INTERFACE;
@@ -1794,7 +1731,7 @@ static int gs_setup_standard(struct usb_gadget *gadget,
goto set_interface_done;
}
if (dev->dev_config != GS_BULK_CONFIG_ID
- && ctrl->wIndex == GS_CONTROL_INTERFACE_ID) {
+ && wIndex == GS_CONTROL_INTERFACE_ID) {
if (dev->dev_notify_ep) {
usb_ep_disable(dev->dev_notify_ep);
usb_ep_enable(dev->dev_notify_ep, dev->dev_notify_ep_desc);
@@ -1814,21 +1751,21 @@ set_interface_done:
if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
|| dev->dev_config == GS_NO_CONFIG_ID)
break;
- if (ctrl->wIndex >= GS_MAX_NUM_INTERFACES
- || (dev->dev_config == GS_BULK_CONFIG_ID
- && ctrl->wIndex != GS_BULK_INTERFACE_ID)) {
+ if (wIndex >= GS_MAX_NUM_INTERFACES
+ || (dev->dev_config == GS_BULK_CONFIG_ID
+ && wIndex != GS_BULK_INTERFACE_ID)) {
ret = -EDOM;
break;
}
/* no alternate interface settings */
*(u8 *)req->buf = 0;
- ret = min(ctrl->wLength, (u16)1);
+ ret = min(wLength, (u16)1);
break;
default:
printk(KERN_ERR "gs_setup: unknown standard request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
- ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
- ctrl->wIndex, ctrl->wLength);
+ ctrl->bRequestType, ctrl->bRequest,
+ wValue, wIndex, wLength);
break;
}
@@ -1842,10 +1779,13 @@ static int gs_setup_class(struct usb_gadget *gadget,
struct gs_dev *dev = get_gadget_data(gadget);
struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
struct usb_request *req = dev->dev_ctrl_req;
+ u16 wIndex = ctrl->wIndex;
+ u16 wValue = ctrl->wValue;
+ u16 wLength = ctrl->wLength;
switch (ctrl->bRequest) {
case USB_CDC_REQ_SET_LINE_CODING:
- ret = min(ctrl->wLength,
+ ret = min(wLength,
(u16)sizeof(struct usb_cdc_line_coding));
if (port) {
spin_lock(&port->port_lock);
@@ -1856,7 +1796,7 @@ static int gs_setup_class(struct usb_gadget *gadget,
case USB_CDC_REQ_GET_LINE_CODING:
port = dev->dev_port[0]; /* ACM only has one port */
- ret = min(ctrl->wLength,
+ ret = min(wLength,
(u16)sizeof(struct usb_cdc_line_coding));
if (port) {
spin_lock(&port->port_lock);
@@ -1871,8 +1811,8 @@ static int gs_setup_class(struct usb_gadget *gadget,
default:
printk(KERN_ERR "gs_setup: unknown class request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
- ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
- ctrl->wIndex, ctrl->wLength);
+ ctrl->bRequestType, ctrl->bRequest,
+ wValue, wIndex, wLength);
break;
}
@@ -2272,7 +2212,7 @@ static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags)
memset(port, 0, sizeof(struct gs_port));
port->port_dev = dev;
port->port_num = i;
- port->port_line_coding.dwDTERate = GS_DEFAULT_DTE_RATE;
+ port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE);
port->port_line_coding.bCharFormat = GS_DEFAULT_CHAR_FORMAT;
port->port_line_coding.bParityType = GS_DEFAULT_PARITY;
port->port_line_coding.bDataBits = GS_DEFAULT_DATA_BITS;
@@ -2324,6 +2264,7 @@ static void gs_free_ports(struct gs_dev *dev)
}
spin_unlock_irqrestore(&port->port_lock, flags);
} else {
+ spin_unlock_irqrestore(&port->port_lock, flags);
kfree(port);
}
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index b128bc8ced6f..98b5c0854201 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1191,6 +1191,8 @@ autoconf_fail:
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
} else if (gadget_is_pxa27x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
+ } else if (gadget_is_s3c2410(gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
} 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/Kconfig b/drivers/usb/host/Kconfig
index 256787e33bde..0b81c960d157 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -7,13 +7,20 @@ config USB_ARCH_HAS_HCD
default y if ARM # SL-811
default PCI
-# many non-PCI hcds implement OHCI
+# many non-PCI SOC chips embed OHCI
config USB_ARCH_HAS_OHCI
boolean
+ # ARM:
default y if SA1111
default y if ARCH_OMAP
default y if ARCH_LH7A404
default y if PXA27x
+ # PPC:
+ default y if STB03xxx
+ default y if PPC_MPC52xx
+ # MIPS:
+ default y if SOC_AU1X00
+ # more:
default PCI
#
@@ -65,7 +72,7 @@ config USB_EHCI_ROOT_HUB_TT
controller is needed. It's safe to say "y" even if your
controller doesn't support this feature.
- This supports the EHCI implementation from ARC International.
+ This supports the EHCI implementation from TransDimension Inc.
config USB_OHCI_HCD
tristate "OHCI HCD support"
@@ -84,6 +91,35 @@ config USB_OHCI_HCD
To compile this driver as a module, choose M here: the
module will be called ohci-hcd.
+config USB_OHCI_HCD_PPC_SOC
+ bool "OHCI support for on-chip PPC USB controller"
+ depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
+ default y
+ select USB_OHCI_BIG_ENDIAN
+ ---help---
+ Enables support for the USB controller on the MPC52xx or
+ STB03xxx processor chip. If unsure, say Y.
+
+config USB_OHCI_HCD_PCI
+ bool "OHCI support for PCI-bus USB controllers"
+ depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
+ default y
+ select USB_OHCI_LITTLE_ENDIAN
+ ---help---
+ Enables support for PCI-bus plug-in USB controller cards.
+ If unsure, say Y.
+
+config USB_OHCI_BIG_ENDIAN
+ bool
+ depends on USB_OHCI_HCD
+ default n
+
+config USB_OHCI_LITTLE_ENDIAN
+ bool
+ depends on USB_OHCI_HCD
+ default n if STB03xxx || PPC_MPC52xx
+ default y
+
config USB_UHCI_HCD
tristate "UHCI HCD (most Intel and VIA) support"
depends on USB && PCI
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 681b7e25b8eb..b0443f3f6cb1 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -191,9 +191,22 @@ static int ehci_halt (struct ehci_hcd *ehci)
return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
}
+/* put TDI/ARC silicon into EHCI mode */
+static void tdi_reset (struct ehci_hcd *ehci)
+{
+ u32 __iomem *reg_ptr;
+ u32 tmp;
+
+ reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
+ tmp = readl (reg_ptr);
+ tmp |= 0x3;
+ writel (tmp, reg_ptr);
+}
+
/* reset a non-running (STS_HALT == 1) controller */
static int ehci_reset (struct ehci_hcd *ehci)
{
+ int retval;
u32 command = readl (&ehci->regs->command);
command |= CMD_RESET;
@@ -201,7 +214,15 @@ static int ehci_reset (struct ehci_hcd *ehci)
writel (command, &ehci->regs->command);
ehci_to_hcd(ehci)->state = USB_STATE_HALT;
ehci->next_statechange = jiffies;
- return handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+ retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+
+ if (retval)
+ return retval;
+
+ if (ehci_is_TDI(ehci))
+ tdi_reset (ehci);
+
+ return retval;
}
/* idle the controller (from running) */
@@ -346,11 +367,20 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
if (hcd->self.controller->bus == &pci_bus_type) {
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
- /* AMD8111 EHCI doesn't work, according to AMD errata */
- if ((pdev->vendor == PCI_VENDOR_ID_AMD)
- && (pdev->device == 0x7463)) {
- ehci_info (ehci, "ignoring AMD8111 (errata)\n");
- return -EIO;
+ switch (pdev->vendor) {
+ case PCI_VENDOR_ID_TDI:
+ if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
+ ehci->is_tdi_rh_tt = 1;
+ tdi_reset (ehci);
+ }
+ break;
+ case PCI_VENDOR_ID_AMD:
+ /* AMD8111 EHCI doesn't work, according to AMD errata */
+ if (pdev->device == 0x7463) {
+ ehci_info (ehci, "ignoring AMD8111 (errata)\n");
+ return -EIO;
+ }
+ break;
}
temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
@@ -380,6 +410,8 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
ehci_err (ehci, "bogus capabilities ... PCI problems!\n");
return -EIO;
}
+ if (ehci_is_TDI(ehci))
+ ehci_reset (ehci);
#endif
/* cache this readonly data; minimize PCI reads */
@@ -481,15 +513,6 @@ static int ehci_start (struct usb_hcd *hcd)
/* help hc dma work well with cachelines */
pci_set_mwi (pdev);
-
- /* chip-specific init */
- switch (pdev->vendor) {
- case PCI_VENDOR_ID_ARC:
- if (pdev->device == PCI_DEVICE_ID_ARC_EHCI)
- ehci->is_arc_rh_tt = 1;
- break;
- }
-
}
#endif
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 8a1c130f9448..5d2271314994 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -178,7 +178,7 @@ static int check_reset_complete (
if (!(port_status & PORT_PE)) {
/* with integrated TT, there's nobody to hand it to! */
- if (ehci_is_ARC(ehci)) {
+ if (ehci_is_TDI(ehci)) {
ehci_dbg (ehci,
"Failed to enable port %d on root hub TT\n",
index+1);
@@ -517,7 +517,7 @@ static int ehci_hub_control (
* transaction translator built in.
*/
if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
- && !ehci_is_ARC(ehci)
+ && !ehci_is_TDI(ehci)
&& PORT_USB11 (temp)) {
ehci_dbg (ehci,
"port %d low speed --> companion\n",
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index b284c4c896af..e9300dbcd229 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -198,7 +198,7 @@ static void qtd_copy_status (
&& urb->dev->tt && !usb_pipeint (urb->pipe)
&& ((token & QTD_STS_MMF) != 0
|| QTD_CERR(token) == 0)
- && (!ehci_is_ARC(ehci)
+ && (!ehci_is_TDI(ehci)
|| urb->dev->tt->hub !=
ehci_to_hcd(ehci)->self.root_hub)) {
#ifdef DEBUG
@@ -714,10 +714,10 @@ qh_make (
info2 |= (EHCI_TUNE_MULT_TT << 30);
info2 |= urb->dev->ttport << 23;
- /* set the address of the TT; for ARC's integrated
+ /* set the address of the TT; for TDI's integrated
* root hub tt, leave it zeroed.
*/
- if (!ehci_is_ARC(ehci)
+ if (!ehci_is_TDI(ehci)
|| urb->dev->tt->hub !=
ehci_to_hcd(ehci)->self.root_hub)
info2 |= urb->dev->tt->hub->devnum << 16;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 3cdfb95c3800..9cbde9568218 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -650,6 +650,7 @@ iso_stream_alloc (int mem_flags)
static void
iso_stream_init (
+ struct ehci_hcd *ehci,
struct ehci_iso_stream *stream,
struct usb_device *dev,
int pipe,
@@ -701,7 +702,10 @@ iso_stream_init (
u32 addr;
addr = dev->ttport << 24;
- addr |= dev->tt->hub->devnum << 16;
+ if (!ehci_is_TDI(ehci)
+ || (dev->tt->hub !=
+ ehci_to_hcd(ehci)->self.root_hub))
+ addr |= dev->tt->hub->devnum << 16;
addr |= epnum << 8;
addr |= dev->devnum;
stream->usecs = HS_USECS_ISO (maxp);
@@ -819,7 +823,7 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
/* dev->ep owns the initial refcount */
ep->hcpriv = stream;
stream->ep = ep;
- iso_stream_init(stream, urb->dev, urb->pipe,
+ iso_stream_init(ehci, stream, urb->dev, urb->pipe,
urb->interval);
}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index e28d19724f56..671fe3810a1a 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -82,7 +82,7 @@ struct ehci_hcd { /* one per controller */
unsigned long next_statechange;
u32 command;
- unsigned is_arc_rh_tt:1; /* ARC roothub with TT */
+ unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */
/* glue to PCI and HCD framework */
struct ehci_caps __iomem *caps;
@@ -599,13 +599,13 @@ struct ehci_fstn {
* needed (mostly in root hub code).
*/
-#define ehci_is_ARC(e) ((e)->is_arc_rh_tt)
+#define ehci_is_TDI(e) ((e)->is_tdi_rh_tt)
/* Returns the speed of a device attached to a port on the root hub. */
static inline unsigned int
ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
{
- if (ehci_is_ARC(ehci)) {
+ if (ehci_is_TDI(ehci)) {
switch ((portsc>>26)&3) {
case 0:
return 0;
@@ -621,7 +621,7 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#else
-#define ehci_is_ARC(e) (0)
+#define ehci_is_TDI(e) (0)
#define ehci_port_speed(ehci, portsc) (1<<USB_PORT_FEAT_HIGHSPEED)
#endif
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index ee8503aa024b..3981bf15c8c7 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -70,19 +70,6 @@ static void au1xxx_stop_hc(struct platform_device *dev)
/*-------------------------------------------------------------------------*/
-
-static irqreturn_t usb_hcd_au1xxx_hcim_irq (int irq, void *__hcd,
- struct pt_regs * r)
-{
- struct usb_hcd *hcd = __hcd;
-
- return usb_hcd_irq(irq, hcd, r);
-}
-
-/*-------------------------------------------------------------------------*/
-
-void usb_hcd_au1xxx_remove (struct usb_hcd *, struct platform_device *);
-
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
@@ -97,90 +84,48 @@ void usb_hcd_au1xxx_remove (struct usb_hcd *, struct platform_device *);
*
*/
int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
- struct usb_hcd **hcd_out,
struct platform_device *dev)
{
int retval;
- struct usb_hcd *hcd = 0;
-
- unsigned int *addr = NULL;
-
- if (!request_mem_region(dev->resource[0].start,
- dev->resource[0].end
- - dev->resource[0].start + 1, hcd_name)) {
- pr_debug("request_mem_region failed");
- return -EBUSY;
- }
-
- au1xxx_start_hc(dev);
-
- addr = ioremap(dev->resource[0].start,
- dev->resource[0].end
- - dev->resource[0].start + 1);
- if (!addr) {
- pr_debug("ioremap failed");
- retval = -ENOMEM;
- goto err1;
- }
+ struct usb_hcd *hcd;
if(dev->resource[1].flags != IORESOURCE_IRQ) {
pr_debug ("resource[1] is not IORESOURCE_IRQ");
- retval = -ENOMEM;
- goto err1;
+ return -ENOMEM;
}
- hcd = usb_create_hcd(driver);
- if (hcd == NULL) {
- pr_debug ("usb_create_hcd failed");
- retval = -ENOMEM;
+ hcd = usb_create_hcd(driver, &dev->dev, "au1xxx");
+ if (!hcd)
+ return -ENOMEM;
+ hcd->rsrc_start = dev->resource[0].start;
+ hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_debug("request_mem_region failed");
+ retval = -EBUSY;
goto err1;
}
- ohci_hcd_init(hcd_to_ohci(hcd));
-
- hcd->irq = dev->resource[1].start;
- hcd->regs = addr;
- hcd->self.controller = &dev->dev;
- retval = hcd_buffer_create (hcd);
- if (retval != 0) {
- pr_debug ("pool alloc fail");
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ pr_debug("ioremap failed");
+ retval = -ENOMEM;
goto err2;
}
- retval = request_irq (hcd->irq, usb_hcd_au1xxx_hcim_irq, SA_INTERRUPT,
- hcd->driver->description, hcd);
- if (retval != 0) {
- pr_debug("request_irq failed");
- retval = -EBUSY;
- goto err3;
- }
-
- pr_debug ("%s (Au1xxx) at 0x%p, irq %d",
- hcd->driver->description, hcd->regs, hcd->irq);
-
- hcd->self.bus_name = "au1xxx";
-
- usb_register_bus (&hcd->self);
+ au1xxx_start_hc(dev);
+ ohci_hcd_init(hcd_to_ohci(hcd));
- if ((retval = driver->start (hcd)) < 0)
- {
- usb_hcd_au1xxx_remove(hcd, dev);
- printk("bad driver->start\n");
+ retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+ if (retval == 0)
return retval;
- }
- *hcd_out = hcd;
- return 0;
-
- err3:
- hcd_buffer_destroy (hcd);
+ au1xxx_stop_hc(dev);
+ iounmap(hcd->regs);
err2:
- usb_put_hcd(hcd);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
- au1xxx_stop_hc(dev);
- release_mem_region(dev->resource[0].start,
- dev->resource[0].end
- - dev->resource[0].start + 1);
+ usb_put_hcd(hcd);
return retval;
}
@@ -200,28 +145,11 @@ int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
*/
void usb_hcd_au1xxx_remove (struct usb_hcd *hcd, struct platform_device *dev)
{
- pr_debug ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
-
- if (in_interrupt ())
- BUG ();
-
- hcd->state = USB_STATE_QUIESCING;
-
- pr_debug ("%s: roothub graceful disconnect", hcd->self.bus_name);
- usb_disconnect (&hcd->self.root_hub);
-
- hcd->driver->stop (hcd);
- hcd->state = USB_STATE_HALT;
-
- free_irq (hcd->irq, hcd);
- hcd_buffer_destroy (hcd);
-
- usb_deregister_bus (&hcd->self);
-
+ usb_remove_hcd(hcd);
au1xxx_stop_hc(dev);
- release_mem_region(dev->resource[0].start,
- dev->resource[0].end
- - dev->resource[0].start + 1);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
}
/*-------------------------------------------------------------------------*/
@@ -257,7 +185,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
* generic hardware linkage
*/
.irq = ohci_irq,
- .flags = HCD_USB11,
+ .flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
@@ -293,7 +221,6 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
static int ohci_hcd_au1xxx_drv_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct usb_hcd *hcd = NULL;
int ret;
pr_debug ("In ohci_hcd_au1xxx_drv_probe");
@@ -301,11 +228,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct device *dev)
if (usb_disabled())
return -ENODEV;
- ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, &hcd, pdev);
-
- if (ret == 0)
- dev_set_drvdata(dev, hcd);
-
+ ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
return ret;
}
@@ -315,7 +238,6 @@ static int ohci_hcd_au1xxx_drv_remove(struct device *dev)
struct usb_hcd *hcd = dev_get_drvdata(dev);
usb_hcd_au1xxx_remove(hcd, pdev);
- dev_set_drvdata(dev, NULL);
return 0;
}
/*TBD*/
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 45053ca193cd..6e3ad024a75a 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -138,7 +138,7 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
ohci_dbg_sw (controller, next, size,
"OHCI %d.%d, %s legacy support registers\n",
0x03 & (temp >> 4), (temp & 0x0f),
- (temp & 0x10) ? "with" : "NO");
+ (temp & 0x0100) ? "with" : "NO");
temp = ohci_readl (controller, &regs->control);
ohci_dbg_sw (controller, next, size,
@@ -328,7 +328,7 @@ static void ohci_dump_td (const struct ohci_hcd *ohci, const char *label,
hc32_to_cpup (ohci, &td->hwCBP) & ~0x0fff,
hc32_to_cpup (ohci, &td->hwBE));
for (i = 0; i < MAXPSW; i++) {
- u16 psw = hc16_to_cpup (ohci, &td->hwPSW [i]);
+ u16 psw = ohci_hwPSW (ohci, td, i);
int cc = (psw >> 12) & 0x0f;
ohci_dbg (ohci, " psw [%d] = %2x, CC=%x %s=%d\n", i,
psw, cc,
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 9db8e18d3fed..179c7583e651 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -148,10 +148,22 @@ static void ohci_stop (struct usb_hcd *hcd);
#include "ohci-q.c"
-/* Some boards don't support per-port power switching */
-static int power_switching = 0;
-module_param (power_switching, bool, 0);
-MODULE_PARM_DESC (power_switching, "true (not default) to switch port power");
+/*
+ * On architectures with edge-triggered interrupts we must never return
+ * IRQ_NONE.
+ */
+#if defined(CONFIG_SA1111) /* ... or other edge-triggered systems */
+#define IRQ_NOTMINE IRQ_HANDLED
+#else
+#define IRQ_NOTMINE IRQ_NONE
+#endif
+
+
+/* Some boards misreport power switching/overcurrent */
+static int distrust_firmware = 1;
+module_param (distrust_firmware, bool, 0);
+MODULE_PARM_DESC (distrust_firmware,
+ "true to distrust firmware power/overcurrent setup");
/* Some boards leave IR set wrongly, since they fail BIOS/SMM handshakes */
static int no_handshake = 0;
@@ -532,8 +544,9 @@ static int ohci_run (struct ohci_hcd *ohci)
// flush the writes
(void) ohci_readl (ohci, &ohci->regs->control);
msleep(temp);
- if (power_switching) {
- unsigned ports = roothub_a (ohci) & RH_A_NDP;
+ temp = roothub_a (ohci);
+ if (!(temp & RH_A_NPS)) {
+ unsigned ports = temp & RH_A_NDP;
/* power down each port */
for (temp = 0; temp < ports; temp++)
@@ -624,21 +637,16 @@ retry:
/* NSC 87560 and maybe others */
temp |= RH_A_NOCP;
temp &= ~(RH_A_POTPGT | RH_A_NPS);
- } else if (power_switching) {
- /* act like most external hubs: use per-port power
- * switching and overcurrent reporting.
- */
- temp &= ~(RH_A_NPS | RH_A_NOCP);
- temp |= RH_A_PSM | RH_A_OCPM;
- } else {
+ ohci_writel (ohci, temp, &ohci->regs->roothub.a);
+ } else if ((ohci->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
/* hub power always on; required for AMD-756 and some
* Mac platforms. ganged overcurrent reporting, if any.
*/
temp |= RH_A_NPS;
+ ohci_writel (ohci, temp, &ohci->regs->roothub.a);
}
- ohci_writel (ohci, temp, &ohci->regs->roothub.a);
ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status);
- ohci_writel (ohci, power_switching ? RH_B_PPCM : 0,
+ ohci_writel (ohci, (temp & RH_A_NPS) ? 0 : RH_B_PPCM,
&ohci->regs->roothub.b);
// flush those writes
(void) ohci_readl (ohci, &ohci->regs->control);
@@ -646,7 +654,7 @@ retry:
spin_unlock_irq (&ohci->lock);
// POTPGT delay is bits 24-31, in 2 ms units.
- mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+ mdelay ((temp >> 23) & 0x1fe);
bus = &ohci_to_hcd(ohci)->self;
ohci_to_hcd(ohci)->state = USB_STATE_RUNNING;
@@ -706,7 +714,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
/* interrupt for some other device? */
} else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) {
- return IRQ_NONE;
+ return IRQ_NOTMINE;
}
if (ints & OHCI_INTR_UE) {
@@ -901,12 +909,17 @@ MODULE_LICENSE ("GPL");
#include "ohci-au1xxx.c"
#endif
+#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
+#include "ohci-ppc-soc.c"
+#endif
+
#if !(defined(CONFIG_PCI) \
|| defined(CONFIG_SA1111) \
|| defined(CONFIG_ARCH_OMAP) \
|| defined (CONFIG_ARCH_LH7A404) \
|| defined (CONFIG_PXA27x) \
|| defined (CONFIG_SOC_AU1X00) \
+ || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
)
#error "missing bus glue for ohci-hcd"
#endif
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index c00324861050..817620d73841 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -53,19 +53,6 @@ static void lh7a404_stop_hc(struct platform_device *dev)
/*-------------------------------------------------------------------------*/
-
-static irqreturn_t usb_hcd_lh7a404_hcim_irq (int irq, void *__hcd,
- struct pt_regs * r)
-{
- struct usb_hcd *hcd = __hcd;
-
- return usb_hcd_irq(irq, hcd, r);
-}
-
-/*-------------------------------------------------------------------------*/
-
-void usb_hcd_lh7a404_remove (struct usb_hcd *, struct platform_device *);
-
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
@@ -80,90 +67,48 @@ void usb_hcd_lh7a404_remove (struct usb_hcd *, struct platform_device *);
*
*/
int usb_hcd_lh7a404_probe (const struct hc_driver *driver,
- struct usb_hcd **hcd_out,
struct platform_device *dev)
{
int retval;
- struct usb_hcd *hcd = 0;
-
- unsigned int *addr = NULL;
+ struct usb_hcd *hcd;
- if (!request_mem_region(dev->resource[0].start,
- dev->resource[0].end
- - dev->resource[0].start + 1, hcd_name)) {
- pr_debug("request_mem_region failed");
- return -EBUSY;
- }
-
-
- lh7a404_start_hc(dev);
-
- addr = ioremap(dev->resource[0].start,
- dev->resource[0].end
- - dev->resource[0].start + 1);
- if (!addr) {
- pr_debug("ioremap failed");
- retval = -ENOMEM;
- goto err1;
+ if (dev->resource[1].flags != IORESOURCE_IRQ) {
+ pr_debug("resource[1] is not IORESOURCE_IRQ");
+ return -ENOMEM;
}
- if(dev->resource[1].flags != IORESOURCE_IRQ){
- pr_debug ("resource[1] is not IORESOURCE_IRQ");
- retval = -ENOMEM;
+ hcd = usb_create_hcd(driver, &dev->dev, "lh7a404");
+ if (!hcd)
+ return -ENOMEM;
+ hcd->rsrc_start = dev->resource[0].start;
+ hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_debug("request_mem_region failed");
+ retval = -EBUSY;
goto err1;
}
-
- hcd = usb_create_hcd (driver);
- if (hcd == NULL){
- pr_debug ("hcd_alloc failed");
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ pr_debug("ioremap failed");
retval = -ENOMEM;
- goto err1;
- }
- ohci_hcd_init(hcd_to_ohci(hcd));
-
- hcd->irq = dev->resource[1].start;
- hcd->regs = addr;
- hcd->self.controller = &dev->dev;
-
- retval = hcd_buffer_create (hcd);
- if (retval != 0) {
- pr_debug ("pool alloc fail");
goto err2;
}
- retval = request_irq (hcd->irq, usb_hcd_lh7a404_hcim_irq, SA_INTERRUPT,
- hcd->driver->description, hcd);
- if (retval != 0) {
- pr_debug("request_irq failed");
- retval = -EBUSY;
- goto err3;
- }
-
- pr_debug ("%s (LH7A404) at 0x%p, irq %d",
- hcd->driver->description, hcd->regs, hcd->irq);
-
- hcd->self.bus_name = "lh7a404";
- usb_register_bus (&hcd->self);
+ lh7a404_start_hc(dev);
+ ohci_hcd_init(hcd_to_ohci(hcd));
- if ((retval = driver->start (hcd)) < 0)
- {
- usb_hcd_lh7a404_remove(hcd, dev);
+ retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+ if (retval == 0)
return retval;
- }
- *hcd_out = hcd;
- return 0;
-
- err3:
- hcd_buffer_destroy (hcd);
+ lh7a404_stop_hc(dev);
+ iounmap(hcd->regs);
err2:
- usb_put_hcd(hcd);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
- lh7a404_stop_hc(dev);
- release_mem_region(dev->resource[0].start,
- dev->resource[0].end
- - dev->resource[0].start + 1);
+ usb_put_hcd(hcd);
return retval;
}
@@ -183,28 +128,11 @@ int usb_hcd_lh7a404_probe (const struct hc_driver *driver,
*/
void usb_hcd_lh7a404_remove (struct usb_hcd *hcd, struct platform_device *dev)
{
- pr_debug ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
-
- if (in_interrupt ())
- BUG ();
-
- hcd->state = USB_STATE_QUIESCING;
-
- pr_debug ("%s: roothub graceful disconnect", hcd->self.bus_name);
- usb_disconnect (&hcd->self.root_hub);
-
- hcd->driver->stop (hcd);
- hcd->state = USB_STATE_HALT;
-
- free_irq (hcd->irq, hcd);
- hcd_buffer_destroy (hcd);
-
- usb_deregister_bus (&hcd->self);
-
+ usb_remove_hcd(hcd);
lh7a404_stop_hc(dev);
- release_mem_region(dev->resource[0].start,
- dev->resource[0].end
- - dev->resource[0].start + 1);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
}
/*-------------------------------------------------------------------------*/
@@ -238,7 +166,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
* generic hardware linkage
*/
.irq = ohci_irq,
- .flags = HCD_USB11,
+ .flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
@@ -274,7 +202,6 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
static int ohci_hcd_lh7a404_drv_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct usb_hcd *hcd = NULL;
int ret;
pr_debug ("In ohci_hcd_lh7a404_drv_probe");
@@ -282,11 +209,7 @@ static int ohci_hcd_lh7a404_drv_probe(struct device *dev)
if (usb_disabled())
return -ENODEV;
- ret = usb_hcd_lh7a404_probe(&ohci_lh7a404_hc_driver, &hcd, pdev);
-
- if (ret == 0)
- dev_set_drvdata(dev, hcd);
-
+ ret = usb_hcd_lh7a404_probe(&ohci_lh7a404_hc_driver, pdev);
return ret;
}
@@ -296,7 +219,6 @@ static int ohci_hcd_lh7a404_drv_remove(struct device *dev)
struct usb_hcd *hcd = dev_get_drvdata(dev);
usb_hcd_lh7a404_remove(hcd, pdev);
- dev_set_drvdata(dev, NULL);
return 0;
}
/*TBD*/
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 2e9c5c07942d..b75a2a611341 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -33,11 +33,27 @@
#error "This file is OMAP bus glue. CONFIG_OMAP must be defined."
#endif
+#ifdef CONFIG_TPS65010
+#include <asm/arch/tps65010.h>
+#else
+
+#define LOW 0
+#define HIGH 1
+
+#define GPIO1 1
+
+static inline int tps65010_set_gpio_out_value(unsigned gpio, unsigned value)
+{
+ return 0;
+}
+
+#endif
+
extern int usb_disabled(void);
extern int ocpi_enable(void);
/*
- * OHCI clock initialization for OMAP-1510 and 1610
+ * OHCI clock initialization for OMAP-1510 and 16xx
*/
static int omap_ohci_clock_power(int on)
{
@@ -78,7 +94,8 @@ static int omap_ohci_clock_power(int on)
}
/*
- * Hardware specific transceiver power on/off
+ * Board specific gang-switched transceiver power on/off.
+ * NOTE: OSK supplies power from DC, not battery.
*/
static int omap_ohci_transceiver_power(int on)
{
@@ -87,17 +104,15 @@ static int omap_ohci_transceiver_power(int on)
fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
| ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
INNOVATOR_FPGA_CAM_USB_CONTROL);
- else if (machine_is_omap_osk()) {
- /* FIXME: GPIO1 -> 1 on the TPS65010 I2C chip */
- }
+ else if (machine_is_omap_osk())
+ tps65010_set_gpio_out_value(GPIO1, LOW);
} else {
if (machine_is_omap_innovator() && cpu_is_omap1510())
fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
& ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
INNOVATOR_FPGA_CAM_USB_CONTROL);
- else if (machine_is_omap_osk()) {
- /* FIXME: GPIO1 -> 0 on the TPS65010 I2C chip */
- }
+ else if (machine_is_omap_osk())
+ tps65010_set_gpio_out_value(GPIO1, HIGH);
}
return 0;
@@ -177,6 +192,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
{
struct omap_usb_config *config = pdev->dev.platform_data;
int need_transceiver = (config->otg != 0);
+ int ret;
dev_dbg(&pdev->dev, "starting USB Controller\n");
@@ -213,21 +229,44 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
}
#endif
- if (machine_is_omap_osk()) {
- omap_request_gpio(9);
- omap_set_gpio_direction(9, 1);
- omap_set_gpio_dataout(9, 1);
- }
-
omap_ohci_clock_power(1);
- omap_ohci_transceiver_power(1);
-
if (cpu_is_omap1510()) {
omap_1510_local_bus_power(1);
omap_1510_local_bus_init();
}
+ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+ /* board-specific power switching and overcurrent support */
+ if (machine_is_omap_osk() || machine_is_omap_innovator()) {
+ u32 rh = roothub_a (ohci);
+
+ /* power switching (ganged by default) */
+ rh &= ~RH_A_NPS;
+
+ /* TPS2045 switch for internal transceiver (port 1) */
+ if (machine_is_omap_osk()) {
+ ohci->power_budget = 250;
+
+ rh &= ~RH_A_NOCP;
+
+ /* gpio9 for overcurrent detction */
+ omap_cfg_reg(W8_1610_GPIO9);
+ omap_request_gpio(9);
+ omap_set_gpio_direction(9, 1 /* IN */);
+
+ /* for paranoia's sake: disable USB.PUEN */
+ omap_cfg_reg(W4_USB_HIGHZ);
+ }
+ ohci_writel(ohci, rh, &ohci->regs->roothub.a);
+ // distrust_firmware = 0;
+ }
+
+ /* FIXME khubd hub requests should manage power switching */
+ omap_ohci_transceiver_power(1);
+
/* board init will have already handled HMC and mux setup.
* any external transceiver should already be initialized
* too, so all configured ports use the right signaling now.
@@ -254,8 +293,6 @@ static void omap_stop_hc(struct platform_device *pdev)
/*-------------------------------------------------------------------------*/
-void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
-
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
@@ -272,7 +309,7 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
struct platform_device *pdev)
{
int retval;
- struct usb_hcd *hcd = 0;
+ struct usb_hcd *hcd;
struct ohci_hcd *ohci;
if (pdev->num_resources != 2) {
@@ -287,68 +324,38 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
return -ENODEV;
}
- if (!request_mem_region(pdev->resource[0].start,
- pdev->resource[0].end - pdev->resource[0].start + 1, hcd_name)) {
- dev_dbg(&pdev->dev, "request_mem_region failed\n");
- return -EBUSY;
- }
+ hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
+ if (!hcd)
+ return -ENOMEM;
+ hcd->rsrc_start = pdev->resource[0].start;
+ hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
- hcd = usb_create_hcd (driver);
- if (hcd == NULL){
- dev_dbg(&pdev->dev, "hcd_alloc failed\n");
- retval = -ENOMEM;
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "request_mem_region failed\n");
+ retval = -EBUSY;
goto err1;
}
- dev_set_drvdata(&pdev->dev, hcd);
+
+ /* FIXME: Cast to pointer from integer of different size!
+ * Needs ioremap */
+ hcd->regs = (void __iomem *) (u32) hcd->rsrc_start;
+
ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci);
- hcd->irq = pdev->resource[1].start;
- hcd->regs = (void *)pdev->resource[0].start;
- hcd->self.controller = &pdev->dev;
-
retval = omap_start_hc(ohci, pdev);
if (retval < 0)
goto err2;
- retval = hcd_buffer_create (hcd);
- if (retval != 0) {
- dev_dbg(&pdev->dev, "pool alloc fail\n");
- goto err2;
- }
-
- retval = request_irq (hcd->irq, usb_hcd_irq,
- SA_INTERRUPT, hcd->driver->description, hcd);
- if (retval != 0) {
- dev_dbg(&pdev->dev, "request_irq failed\n");
- retval = -EBUSY;
- goto err3;
- }
-
- dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);
-
- hcd->self.bus_name = pdev->dev.bus_id;
- usb_register_bus (&hcd->self);
-
- if ((retval = driver->start (hcd)) < 0)
- {
- usb_hcd_omap_remove(hcd, pdev);
+ retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
+ if (retval == 0)
return retval;
- }
- return 0;
-
- err3:
- hcd_buffer_destroy (hcd);
+ omap_stop_hc(pdev);
err2:
- dev_set_drvdata(&pdev->dev, NULL);
- usb_put_hcd(hcd);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
- omap_stop_hc(pdev);
-
- release_mem_region(pdev->resource[0].start,
- pdev->resource[0].end - pdev->resource[0].start + 1);
-
+ usb_put_hcd(hcd);
return retval;
}
@@ -368,31 +375,12 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
*/
void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
{
- dev_info(&pdev->dev, "remove: state %x\n", hcd->state);
-
- if (in_interrupt ())
- BUG ();
-
- hcd->state = USB_STATE_QUIESCING;
-
- dev_dbg(&pdev->dev, "roothub graceful disconnect\n");
- usb_disconnect (&hcd->self.root_hub);
-
- hcd->driver->stop (hcd);
- hcd_buffer_destroy (hcd);
- hcd->state = USB_STATE_HALT;
-
+ usb_remove_hcd(hcd);
if (machine_is_omap_osk())
omap_free_gpio(9);
-
- free_irq (hcd->irq, hcd);
-
- usb_deregister_bus (&hcd->self);
-
omap_stop_hc(pdev);
-
- release_mem_region(pdev->resource[0].start,
- pdev->resource[0].end - pdev->resource[0].start + 1);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
}
/*-------------------------------------------------------------------------*/
@@ -404,9 +392,6 @@ ohci_omap_start (struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret;
- if ((ret = ohci_init(ohci)) < 0)
- return ret;
-
config = hcd->self.controller->platform_data;
if (config->otg || config->rwc)
writel(OHCI_CTRL_RWC, &ohci->regs->control);
@@ -430,7 +415,7 @@ static const struct hc_driver ohci_omap_hc_driver = {
* generic hardware linkage
*/
.irq = ohci_irq,
- .flags = HCD_USB11,
+ .flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
@@ -481,7 +466,6 @@ static int ohci_hcd_omap_drv_remove(struct device *dev)
(void) otg_set_host(ohci->transceiver, 0);
put_device(ohci->transceiver->dev);
}
- dev_set_drvdata(dev, NULL);
return 0;
}
@@ -499,6 +483,8 @@ static int ohci_omap_suspend(struct device *dev, u32 state, u32 level)
struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev));
int status = -EINVAL;
+ if (level != SUSPEND_POWER_DOWN)
+ return 0;
if (state <= dev->power.power_state)
return 0;
@@ -525,6 +511,9 @@ static int ohci_omap_resume(struct device *dev, u32 level)
struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev));
int status = 0;
+ if (level != RESUME_POWER_ON)
+ return 0;
+
switch (dev->power.power_state) {
case 0:
break;
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
new file mode 100644
index 000000000000..17964c39d06a
--- /dev/null
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -0,0 +1,234 @@
+/*
+ * 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 2002 Hewlett-Packard Company
+ * (C) Copyright 2003-2005 MontaVista Software Inc.
+ *
+ * Bus Glue for PPC On-Chip OHCI driver
+ * Tested on Freescale MPC5200 and IBM STB04xxx
+ *
+ * Modified by Dale Farnsworth <dale@farnsworth.org> from ohci-sa1111.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <asm/usb.h>
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_ppc_soc_probe - initialize On-Chip HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
+ struct platform_device *pdev)
+{
+ int retval;
+ struct usb_hcd *hcd;
+ struct ohci_hcd *ohci;
+ struct resource *res;
+ int irq;
+ struct usb_hcd_platform_data *pd = pdev->dev.platform_data;
+
+ pr_debug("initializing PPC-SOC USB Controller\n");
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ pr_debug(__FILE__ ": no irq\n");
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ pr_debug(__FILE__ ": no reg addr\n");
+ return -ENODEV;
+ }
+
+ hcd = usb_create_hcd(driver, &pdev->dev, "PPC-SOC USB");
+ if (!hcd)
+ return -ENOMEM;
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_debug(__FILE__ ": request_mem_region failed\n");
+ retval = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ pr_debug(__FILE__ ": ioremap failed\n");
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+ if (pd->start && (retval = pd->start(pdev)))
+ goto err3;
+
+ ohci = hcd_to_ohci(hcd);
+ ohci->flags |= OHCI_BIG_ENDIAN;
+ ohci_hcd_init(ohci);
+
+ retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+ if (retval == 0)
+ return retval;
+
+ pr_debug("Removing PPC-SOC USB Controller\n");
+ if (pd && pd->stop)
+ pd->stop(pdev);
+ err3:
+ iounmap(hcd->regs);
+ err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+ usb_put_hcd(hcd);
+ return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_ppc_soc_remove - shutdown processing for On-Chip HCDs
+ * @pdev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_ppc_soc_probe(), first invoking
+ * the HCD's stop() method. It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+static void usb_hcd_ppc_soc_remove(struct usb_hcd *hcd,
+ struct platform_device *pdev)
+{
+ struct usb_hcd_platform_data *pd = pdev->dev.platform_data;
+
+ usb_remove_hcd(hcd);
+
+ pr_debug("stopping PPC-SOC USB Controller\n");
+ if (pd && pd->stop)
+ pd->stop(pdev);
+
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_hcd_put(hcd);
+}
+
+static int __devinit
+ohci_ppc_soc_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+ if ((ret = ohci_run(ohci)) < 0) {
+ err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+ ohci_stop(hcd);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct hc_driver ohci_ppc_soc_hc_driver = {
+ .description = hcd_name,
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = ohci_ppc_soc_start,
+ .stop = ohci_stop,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+#ifdef CONFIG_USB_SUSPEND
+ .hub_suspend = ohci_hub_suspend,
+ .hub_resume = ohci_hub_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+static int ohci_hcd_ppc_soc_drv_probe(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ ret = usb_hcd_ppc_soc_probe(&ohci_ppc_soc_hc_driver, pdev);
+ return ret;
+}
+
+static int ohci_hcd_ppc_soc_drv_remove(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+ usb_hcd_ppc_soc_remove(hcd, pdev);
+ return 0;
+}
+
+static struct device_driver ohci_hcd_ppc_soc_driver = {
+ .name = "ppc-soc-ohci",
+ .bus = &platform_bus_type,
+ .probe = ohci_hcd_ppc_soc_drv_probe,
+ .remove = ohci_hcd_ppc_soc_drv_remove,
+#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
+ /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
+ /*.resume = ohci_hcd_ppc_soc_drv_resume,*/
+#endif
+};
+
+static int __init ohci_hcd_ppc_soc_init(void)
+{
+ pr_debug(DRIVER_INFO " (PPC SOC)\n");
+ pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
+ sizeof(struct td));
+
+ return driver_register(&ohci_hcd_ppc_soc_driver);
+}
+
+static void __exit ohci_hcd_ppc_soc_cleanup(void)
+{
+ driver_unregister(&ohci_hcd_ppc_soc_driver);
+}
+
+module_init(ohci_hcd_ppc_soc_init);
+module_exit(ohci_hcd_ppc_soc_cleanup);
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 8283c1aafcf9..6f3464a95779 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -152,8 +152,6 @@ static void pxa27x_stop_hc(struct platform_device *dev)
/*-------------------------------------------------------------------------*/
-void usb_hcd_pxa27x_remove (struct usb_hcd *, struct platform_device *);
-
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
@@ -168,19 +166,33 @@ void usb_hcd_pxa27x_remove (struct usb_hcd *, struct platform_device *);
*
*/
int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
- struct usb_hcd **hcd_out,
struct platform_device *dev)
{
int retval;
- struct usb_hcd *hcd = 0;
+ struct usb_hcd *hcd;
+
+ if (dev->resource[1].flags != IORESOURCE_IRQ) {
+ pr_debug ("resource[1] is not IORESOURCE_IRQ");
+ return -ENOMEM;
+ }
- unsigned int *addr = NULL;
+ hcd = usb_create_hcd (driver, &dev->dev, "pxa27x");
+ if (!hcd)
+ return -ENOMEM;
+ hcd->rsrc_start = dev->resource[0].start;
+ hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
- if (!request_mem_region(dev->resource[0].start,
- dev->resource[0].end
- - dev->resource[0].start + 1, hcd_name)) {
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
pr_debug("request_mem_region failed");
- return -EBUSY;
+ retval = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ pr_debug("ioremap failed");
+ retval = -ENOMEM;
+ goto err2;
}
pxa27x_start_hc(dev);
@@ -198,69 +210,18 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
if (pxa27x_ohci_clear_port_power(3) < 0)
printk(KERN_ERR "Setting port 3 power failed.\n");
- addr = ioremap(dev->resource[0].start,
- dev->resource[0].end - dev->resource[0].start + 1);
- if (!addr) {
- pr_debug("ioremap failed");
- retval = -ENOMEM;
- goto err1;
- }
-
- if(dev->resource[1].flags != IORESOURCE_IRQ){
- pr_debug ("resource[1] is not IORESOURCE_IRQ");
- retval = -ENOMEM;
- goto err1;
- }
-
- hcd = usb_create_hcd (driver);
- if (hcd == NULL){
- pr_debug ("hcd_alloc failed");
- retval = -ENOMEM;
- goto err1;
- }
ohci_hcd_init(hcd_to_ohci(hcd));
- hcd->irq = dev->resource[1].start;
- hcd->regs = addr;
- hcd->self.controller = &dev->dev;
-
- retval = hcd_buffer_create (hcd);
- if (retval != 0) {
- pr_debug ("pool alloc fail");
- goto err2;
- }
-
- retval = request_irq (hcd->irq, usb_hcd_irq, SA_INTERRUPT,
- hcd->driver->description, hcd);
- if (retval != 0) {
- pr_debug("request_irq(%d) failed with retval %d\n",hcd->irq,retval);
- retval = -EBUSY;
- goto err3;
- }
-
- pr_debug ("%s (pxa27x) at 0x%p, irq %d",
- hcd->driver->description, hcd->regs, hcd->irq);
-
- hcd->self.bus_name = "pxa27x";
- usb_register_bus (&hcd->self);
-
- if ((retval = driver->start (hcd)) < 0) {
- usb_hcd_pxa27x_remove(hcd, dev);
+ retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+ if (retval == 0)
return retval;
- }
-
- *hcd_out = hcd;
- return 0;
- err3:
- hcd_buffer_destroy (hcd);
+ pxa27x_stop_hc(dev);
+ iounmap(hcd->regs);
err2:
- usb_put_hcd(hcd);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
- pxa27x_stop_hc(dev);
- release_mem_region(dev->resource[0].start,
- dev->resource[0].end
- - dev->resource[0].start + 1);
+ usb_put_hcd(hcd);
return retval;
}
@@ -280,27 +241,11 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
*/
void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *dev)
{
- pr_debug ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
-
- if (in_interrupt ())
- BUG ();
-
- hcd->state = USB_STATE_QUIESCING;
-
- pr_debug ("%s: roothub graceful disconnect", hcd->self.bus_name);
- usb_disconnect (&hcd->self.root_hub);
-
- hcd->driver->stop (hcd);
- hcd->state = USB_STATE_HALT;
-
- free_irq (hcd->irq, hcd);
- hcd_buffer_destroy (hcd);
-
- usb_deregister_bus (&hcd->self);
-
+ usb_remove_hcd(hcd);
pxa27x_stop_hc(dev);
- release_mem_region(dev->resource[0].start,
- dev->resource[0].end - dev->resource[0].start + 1);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
}
/*-------------------------------------------------------------------------*/
@@ -336,7 +281,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
* generic hardware linkage
*/
.irq = ohci_irq,
- .flags = HCD_USB11,
+ .flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
@@ -372,7 +317,6 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
static int ohci_hcd_pxa27x_drv_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct usb_hcd *hcd = NULL;
int ret;
pr_debug ("In ohci_hcd_pxa27x_drv_probe");
@@ -380,11 +324,7 @@ static int ohci_hcd_pxa27x_drv_probe(struct device *dev)
if (usb_disabled())
return -ENODEV;
- ret = usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, &hcd, pdev);
-
- if (ret == 0)
- dev_set_drvdata(dev, hcd);
-
+ ret = usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, pdev);
return ret;
}
@@ -394,7 +334,6 @@ static int ohci_hcd_pxa27x_drv_remove(struct device *dev)
struct usb_hcd *hcd = dev_get_drvdata(dev);
usb_hcd_pxa27x_remove(hcd, pdev);
- dev_set_drvdata(dev, NULL);
return 0;
}
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index c86815586886..14c2e932dd89 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -547,7 +547,8 @@ td_fill (struct ohci_hcd *ohci, u32 info,
td->hwINFO = cpu_to_hc32 (ohci, info);
if (is_iso) {
td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000);
- td->hwPSW [0] = cpu_to_hc16 (ohci, (data & 0x0FFF) | 0xE000);
+ *ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci,
+ (data & 0x0FFF) | 0xE000);
td->ed->last_iso = info & 0xffff;
} else {
td->hwCBP = cpu_to_hc32 (ohci, data);
@@ -719,10 +720,12 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
/* ISO ... drivers see per-TD length/status */
if (tdINFO & TD_ISO) {
- u16 tdPSW = hc16_to_cpu (ohci, td->hwPSW [0]);
+ u16 tdPSW = ohci_hwPSW (ohci, td, 0);
int dlen = 0;
- /* NOTE: assumes FC in tdINFO == 0 (and MAXPSW == 1) */
+ /* NOTE: assumes FC in tdINFO == 0, and that
+ * only the first of 0..MAXPSW psws is used.
+ */
cc = (tdPSW >> 12) & 0xF;
if (tdINFO & TD_CC) /* hc didn't touch? */
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index eb656a73d2ec..814d2be4ee7b 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -105,34 +105,8 @@ static void dump_hci_status(struct usb_hcd *hcd, const char *label)
}
#endif
-static irqreturn_t usb_hcd_sa1111_hcim_irq (int irq, void *__hcd, struct pt_regs * r)
-{
- struct usb_hcd *hcd = __hcd;
-// unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
-
- //dump_hci_status(hcd, "irq");
-
-#if 0
- /* may work better this way -- need to investigate further */
- if (status & USB_STATUS_NIRQHCIM) {
- //dbg ("not normal HC interrupt; ignoring");
- return;
- }
-#endif
-
- usb_hcd_irq(irq, hcd, r);
-
- /*
- * SA1111 seems to re-assert its interrupt immediately
- * after processing an interrupt. Always return IRQ_HANDLED.
- */
- return IRQ_HANDLED;
-}
-
/*-------------------------------------------------------------------------*/
-void usb_hcd_sa1111_remove (struct usb_hcd *, struct sa1111_dev *);
-
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
@@ -148,68 +122,35 @@ void usb_hcd_sa1111_remove (struct usb_hcd *, struct sa1111_dev *);
* Store this function in the HCD's struct pci_driver as probe().
*/
int usb_hcd_sa1111_probe (const struct hc_driver *driver,
- struct usb_hcd **hcd_out,
struct sa1111_dev *dev)
{
+ struct usb_hcd *hcd;
int retval;
- struct usb_hcd *hcd = 0;
- if (!request_mem_region(dev->res.start,
- dev->res.end - dev->res.start + 1, hcd_name)) {
- dbg("request_mem_region failed");
- return -EBUSY;
- }
-
- sa1111_start_hc(dev);
+ hcd = usb_create_hcd (driver, &dev->dev, "sa1111");
+ if (!hcd)
+ return -ENOMEM;
+ hcd->rsrc_start = dev->res.start;
+ hcd->rsrc_len = dev->res.end - dev->res.start + 1;
- hcd = usb_create_hcd (driver);
- if (hcd == NULL){
- dbg ("hcd_alloc failed");
- retval = -ENOMEM;
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dbg("request_mem_region failed");
+ retval = -EBUSY;
goto err1;
}
- ohci_hcd_init(hcd_to_ohci(hcd));
-
- hcd->irq = dev->irq[1];
hcd->regs = dev->mapbase;
- hcd->self.controller = &dev->dev;
-
- retval = hcd_buffer_create (hcd);
- if (retval != 0) {
- dbg ("pool alloc fail");
- goto err2;
- }
-
- retval = request_irq (hcd->irq, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT,
- hcd->driver->description, hcd);
- if (retval != 0) {
- dbg("request_irq failed");
- retval = -EBUSY;
- goto err3;
- }
- info ("%s (SA-1111) at 0x%p, irq %d\n",
- hcd->driver->description, hcd->regs, hcd->irq);
-
- hcd->self.bus_name = "sa1111";
- usb_register_bus (&hcd->self);
+ sa1111_start_hc(dev);
+ ohci_hcd_init(hcd_to_ohci(hcd));
- if ((retval = driver->start (hcd)) < 0)
- {
- usb_hcd_sa1111_remove(hcd, dev);
+ retval = usb_add_hcd(hcd, dev->irq[1], SA_INTERRUPT);
+ if (retval == 0)
return retval;
- }
- *hcd_out = hcd;
- return 0;
-
- err3:
- hcd_buffer_destroy (hcd);
- err2:
- usb_put_hcd(hcd);
- err1:
sa1111_stop_hc(dev);
- release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+ usb_put_hcd(hcd);
return retval;
}
@@ -229,26 +170,10 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver,
*/
void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
{
- info ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
-
- if (in_interrupt ())
- BUG ();
-
- hcd->state = USB_STATE_QUIESCING;
-
- dbg ("%s: roothub graceful disconnect", hcd->self.bus_name);
- usb_disconnect (&hcd->self.root_hub);
-
- hcd->driver->stop (hcd);
- hcd->state = USB_STATE_HALT;
-
- free_irq (hcd->irq, hcd);
- hcd_buffer_destroy (hcd);
-
- usb_deregister_bus (&hcd->self);
-
+ usb_remove_hcd(hcd);
sa1111_stop_hc(dev);
- release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
}
/*-------------------------------------------------------------------------*/
@@ -281,7 +206,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
* generic hardware linkage
*/
.irq = ohci_irq,
- .flags = HCD_USB11,
+ .flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
@@ -294,11 +219,6 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
.stop = ohci_stop,
/*
- * memory lifecycle (except per-request)
- */
- .hcd_alloc = ohci_hcd_alloc,
-
- /*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ohci_urb_enqueue,
@@ -325,17 +245,12 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev)
{
- struct usb_hcd *hcd = NULL;
int ret;
if (usb_disabled())
return -ENODEV;
- ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &hcd, dev);
-
- if (ret == 0)
- sa1111_set_drvdata(dev, hcd);
-
+ ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev);
return ret;
}
@@ -344,9 +259,6 @@ static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev)
struct usb_hcd *hcd = sa1111_get_drvdata(dev);
usb_hcd_sa1111_remove(hcd, dev);
-
- sa1111_set_drvdata(dev, NULL);
-
return 0;
}
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 437e8b03ed93..94ad4b47f9de 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -111,8 +111,10 @@ struct td {
__hc32 hwNextTD; /* Next TD Pointer */
__hc32 hwBE; /* Memory Buffer End Pointer */
- /* PSW is only for ISO */
-#define MAXPSW 1 /* hardware allows 8 */
+ /* PSW is only for ISO. Only 1 PSW entry is used, but on
+ * big-endian PPC hardware that's the second entry.
+ */
+#define MAXPSW 2
__hc16 hwPSW [MAXPSW];
/* rest are purely for the driver's use */
@@ -183,7 +185,7 @@ struct ohci_hcca {
/*
* OHCI defines u16 frame_no, followed by u16 zero pad.
* Since some processors can't do 16 bit bus accesses,
- * portable access must be a 32 bit byteswapped access.
+ * portable access must be a 32 bits wide.
*/
__hc32 frame_no; /* current frame number */
__hc32 done_head; /* info returned for an interrupt */
@@ -191,8 +193,6 @@ struct ohci_hcca {
u8 what [4]; /* spec only identifies 252 bytes :) */
} __attribute__ ((aligned(256)));
-#define ohci_frame_no(ohci) ((u16)hc32_to_cpup(ohci,&(ohci)->hcca->frame_no))
-
/*
* This is the structure of the OHCI controller's memory mapped I/O region.
* You must use readl() and writel() (in <asm/io.h>) to access these fields!!
@@ -554,6 +554,44 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
/*-------------------------------------------------------------------------*/
+/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
+ * hardware handles 16 bit reads. That creates a different confusion on
+ * some big-endian SOC implementations. Same thing happens with PSW access.
+ */
+
+#ifdef CONFIG_STB03xxx
+#define OHCI_BE_FRAME_NO_SHIFT 16
+#else
+#define OHCI_BE_FRAME_NO_SHIFT 0
+#endif
+
+static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
+{
+ u32 tmp;
+ if (big_endian(ohci)) {
+ tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
+ tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+ } else
+ tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
+
+ return (u16)tmp;
+}
+
+static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
+ const struct td *td, int index)
+{
+ return (__hc16 *)(big_endian(ohci) ?
+ &td->hwPSW[index ^ 1] : &td->hwPSW[index]);
+}
+
+static inline u16 ohci_hwPSW(const struct ohci_hcd *ohci,
+ const struct td *td, int index)
+{
+ return hc16_to_cpup(ohci, ohci_hwPSWp(ohci, td, index));
+}
+
+/*-------------------------------------------------------------------------*/
+
static inline void disable (struct ohci_hcd *ohci)
{
ohci_to_hcd(ohci)->state = USB_STATE_HALT;
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index c932c53ac01d..b40a4039e193 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -90,8 +90,6 @@ static const char hcd_name[] = "sl811-hcd";
/*-------------------------------------------------------------------------*/
-static irqreturn_t sl811h_irq(int irq, void *_hcd, struct pt_regs *regs);
-
static void port_power(struct sl811 *sl811, int is_on)
{
struct usb_hcd *hcd = sl811_to_hcd(sl811);
@@ -645,9 +643,8 @@ static inline u8 checkdone(struct sl811 *sl811)
return irqstat;
}
-static irqreturn_t sl811h_irq(int irq, void *_hcd, struct pt_regs *regs)
+static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs)
{
- struct usb_hcd *hcd = _hcd;
struct sl811 *sl811 = hcd_to_sl811(hcd);
u8 irqstat;
irqreturn_t ret = IRQ_NONE;
@@ -666,7 +663,7 @@ retry:
/* this may no longer be necessary ... */
if (irqstat == 0 && ret == IRQ_NONE) {
irqstat = checkdone(sl811);
- if (irqstat && irq != ~0)
+ if (irqstat /* && irq != ~0 */ )
sl811->stat_lost++;
}
#endif
@@ -760,7 +757,6 @@ retry:
if (sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))
start_transfer(sl811);
ret = IRQ_HANDLED;
- hcd->saw_irq = 1;
if (retries--)
goto retry;
}
@@ -1073,7 +1069,7 @@ sl811h_hub_status_data(struct usb_hcd *hcd, char *buf)
*/
local_irq_save(flags);
if (!timer_pending(&sl811->timer)) {
- if (sl811h_irq(~0, sl811, NULL) != IRQ_NONE)
+ if (sl811h_irq( /* ~0, */ hcd, NULL) != IRQ_NONE)
sl811->stat_lost++;
}
local_irq_restore(flags);
@@ -1592,7 +1588,12 @@ static struct hc_driver sl811h_hc_driver = {
/*
* generic hardware linkage
*/
- .flags = HCD_USB11,
+ .irq = sl811h_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /* Basic lifecycle operations */
+ .start = sl811h_start,
+ .stop = sl811h_stop,
/*
* managing i/o requests and associated device resources
@@ -1620,23 +1621,15 @@ static struct hc_driver sl811h_hc_driver = {
static int __init_or_module
sl811h_remove(struct device *dev)
{
- struct sl811 *sl811 = dev_get_drvdata(dev);
- struct usb_hcd *hcd = sl811_to_hcd(sl811);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct sl811 *sl811 = hcd_to_sl811(hcd);
struct platform_device *pdev;
struct resource *res;
pdev = container_of(dev, struct platform_device, dev);
- if (HCD_IS_RUNNING(hcd->state))
- hcd->state = USB_STATE_QUIESCING;
-
- usb_disconnect(&hcd->self.root_hub);
remove_debug_file(sl811);
- sl811h_stop(hcd);
-
- usb_deregister_bus(&hcd->self);
-
- free_irq(hcd->irq, hcd);
+ usb_remove_hcd(hcd);
iounmap(sl811->data_reg);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1707,18 +1700,13 @@ sl811h_probe(struct device *dev)
}
/* allocate and initialize hcd */
- hcd = usb_create_hcd(&sl811h_hc_driver);
+ hcd = usb_create_hcd(&sl811h_hc_driver, dev, dev->bus_id);
if (!hcd) {
- retval = 0;
+ retval = -ENOMEM;
goto err5;
}
+ hcd->rsrc_start = addr->start;
sl811 = hcd_to_sl811(hcd);
- dev_set_drvdata(dev, sl811);
-
- hcd->self.controller = dev;
- hcd->self.bus_name = dev->bus_id;
- hcd->irq = irq;
- hcd->regs = addr_reg;
spin_lock_init(&sl811->lock);
INIT_LIST_HEAD(&sl811->async);
@@ -1754,28 +1742,13 @@ sl811h_probe(struct device *dev)
/* Cypress docs say the IRQ is IRQT_HIGH ... */
set_irq_type(irq, IRQT_RISING);
#endif
- retval = request_irq(irq, sl811h_irq, SA_INTERRUPT,
- hcd->driver->description, hcd);
+ retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
if (retval != 0)
goto err6;
- INFO("%s, irq %d\n", hcd->product_desc, irq);
-
- retval = usb_register_bus(&hcd->self);
- if (retval < 0)
- goto err7;
-
- retval = sl811h_start(hcd);
- if (retval < 0)
- goto err8;
-
create_debug_file(sl811);
- return 0;
+ return retval;
- err8:
- usb_deregister_bus(&hcd->self);
- err7:
- free_irq(hcd->irq, hcd);
err6:
usb_put_hcd(hcd);
err5:
@@ -1801,14 +1774,15 @@ sl811h_probe(struct device *dev)
static int
sl811h_suspend(struct device *dev, u32 state, u32 phase)
{
- struct sl811 *sl811 = dev_get_drvdata(dev);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct sl811 *sl811 = hcd_to_sl811(hcd);
int retval = 0;
if (phase != SUSPEND_POWER_DOWN)
return retval;
if (state <= PM_SUSPEND_MEM)
- retval = sl811h_hub_suspend(sl811_to_hcd(sl811));
+ retval = sl811h_hub_suspend(hcd);
else
port_power(sl811, 0);
if (retval == 0)
@@ -1819,7 +1793,8 @@ sl811h_suspend(struct device *dev, u32 state, u32 phase)
static int
sl811h_resume(struct device *dev, u32 phase)
{
- struct sl811 *sl811 = dev_get_drvdata(dev);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct sl811 *sl811 = hcd_to_sl811(hcd);
if (phase != RESUME_POWER_ON)
return 0;
@@ -1828,14 +1803,14 @@ sl811h_resume(struct device *dev, u32 phase)
* let's assume it'd only be powered to enable remote wakeup.
*/
if (dev->power.power_state > PM_SUSPEND_MEM
- || !sl811_to_hcd(sl811)->can_wakeup) {
+ || !hcd->can_wakeup) {
sl811->port1 = 0;
port_power(sl811, 1);
return 0;
}
dev->power.power_state = PM_SUSPEND_ON;
- return sl811h_hub_resume(sl811_to_hcd(sl811));
+ return sl811h_hub_resume(hcd);
}
#else
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 397ec79cc1e4..eeb7073a225b 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -17,6 +17,8 @@
#include "uhci-hcd.h"
+static struct dentry *uhci_debugfs_root = NULL;
+
/* Handle REALLY large printk's so we don't overflow buffers */
static inline void lprintk(char *buf)
{
@@ -497,8 +499,6 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
#define MAX_OUTPUT (64 * 1024)
-static struct dentry *uhci_debugfs_root = NULL;
-
struct uhci_debug {
int size;
char *data;
@@ -579,4 +579,9 @@ static struct file_operations uhci_debug_operations = {
.read = uhci_debug_read,
.release = uhci_debug_release,
};
+
+#else /* CONFIG_DEBUG_FS */
+
+#define uhci_debug_operations (* (struct file_operations *) NULL)
+
#endif
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 1e82aa7dc01e..00376bda34bf 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -87,19 +87,9 @@ MODULE_PARM_DESC(debug, "Debug level");
static char *errbuf;
#define ERRBUF_LEN (32 * 1024)
-#include "uhci-hub.c"
-#include "uhci-debug.c"
-
static kmem_cache_t *uhci_up_cachep; /* urb_priv */
static unsigned int uhci_get_current_frame_number(struct uhci_hcd *uhci);
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
-static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
-static void uhci_remove_pending_urbps(struct uhci_hcd *uhci);
-static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs);
-static void uhci_free_pending_qhs(struct uhci_hcd *uhci);
-static void uhci_free_pending_tds(struct uhci_hcd *uhci);
-
static void hc_state_transitions(struct uhci_hcd *uhci);
/* If a transfer is still active after this much time, turn off FSBR */
@@ -111,1424 +101,9 @@ static void hc_state_transitions(struct uhci_hcd *uhci);
/* to make sure it doesn't hog all of the bandwidth */
#define DEPTH_INTERVAL 5
-/*
- * Technically, updating td->status here is a race, but it's not really a
- * problem. The worst that can happen is that we set the IOC bit again
- * generating a spurious interrupt. We could fix this by creating another
- * QH and leaving the IOC bit always set, but then we would have to play
- * games with the FSBR code to make sure we get the correct order in all
- * the cases. I don't think it's worth the effort
- */
-static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
-{
- uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
-}
-
-static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
-{
- uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
-}
-
-static inline void uhci_moveto_complete(struct uhci_hcd *uhci,
- struct urb_priv *urbp)
-{
- list_move_tail(&urbp->urb_list, &uhci->complete_list);
-}
-
-static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
-{
- dma_addr_t dma_handle;
- struct uhci_td *td;
-
- td = dma_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle);
- if (!td)
- return NULL;
-
- td->dma_handle = dma_handle;
-
- td->link = UHCI_PTR_TERM;
- td->buffer = 0;
-
- td->frame = -1;
- td->dev = dev;
-
- INIT_LIST_HEAD(&td->list);
- INIT_LIST_HEAD(&td->remove_list);
- INIT_LIST_HEAD(&td->fl_list);
-
- usb_get_dev(dev);
-
- return td;
-}
-
-static inline void uhci_fill_td(struct uhci_td *td, u32 status,
- u32 token, u32 buffer)
-{
- td->status = cpu_to_le32(status);
- td->token = cpu_to_le32(token);
- td->buffer = cpu_to_le32(buffer);
-}
-
-/*
- * We insert Isochronous URB's directly into the frame list at the beginning
- */
-static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum)
-{
- framenum &= (UHCI_NUMFRAMES - 1);
-
- td->frame = framenum;
-
- /* Is there a TD already mapped there? */
- if (uhci->fl->frame_cpu[framenum]) {
- struct uhci_td *ftd, *ltd;
-
- ftd = uhci->fl->frame_cpu[framenum];
- ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
-
- list_add_tail(&td->fl_list, &ftd->fl_list);
-
- td->link = ltd->link;
- wmb();
- ltd->link = cpu_to_le32(td->dma_handle);
- } else {
- td->link = uhci->fl->frame[framenum];
- wmb();
- uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle);
- uhci->fl->frame_cpu[framenum] = td;
- }
-}
-
-static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
-{
- /* If it's not inserted, don't remove it */
- if (td->frame == -1 && list_empty(&td->fl_list))
- return;
-
- if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
- if (list_empty(&td->fl_list)) {
- uhci->fl->frame[td->frame] = td->link;
- uhci->fl->frame_cpu[td->frame] = NULL;
- } else {
- struct uhci_td *ntd;
-
- ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
- uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
- uhci->fl->frame_cpu[td->frame] = ntd;
- }
- } else {
- struct uhci_td *ptd;
-
- ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list);
- ptd->link = td->link;
- }
-
- wmb();
- td->link = UHCI_PTR_TERM;
-
- list_del_init(&td->fl_list);
- td->frame = -1;
-}
-
-/*
- * Inserts a td list into qh.
- */
-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- struct uhci_td *td;
- __le32 *plink;
-
- /* Ordering isn't important here yet since the QH hasn't been */
- /* inserted into the schedule yet */
- plink = &qh->element;
- list_for_each_entry(td, &urbp->td_list, list) {
- *plink = cpu_to_le32(td->dma_handle) | breadth;
- plink = &td->link;
- }
- *plink = UHCI_PTR_TERM;
-}
-
-static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
-{
- if (!list_empty(&td->list))
- dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
- if (!list_empty(&td->remove_list))
- dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
- if (!list_empty(&td->fl_list))
- dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
-
- if (td->dev)
- usb_put_dev(td->dev);
-
- dma_pool_free(uhci->td_pool, td, td->dma_handle);
-}
-
-static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev)
-{
- dma_addr_t dma_handle;
- struct uhci_qh *qh;
-
- qh = dma_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
- if (!qh)
- return NULL;
-
- qh->dma_handle = dma_handle;
-
- qh->element = UHCI_PTR_TERM;
- qh->link = UHCI_PTR_TERM;
-
- qh->dev = dev;
- qh->urbp = NULL;
-
- INIT_LIST_HEAD(&qh->list);
- INIT_LIST_HEAD(&qh->remove_list);
-
- usb_get_dev(dev);
-
- return qh;
-}
-
-static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
-{
- if (!list_empty(&qh->list))
- dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh);
- if (!list_empty(&qh->remove_list))
- dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
-
- if (qh->dev)
- usb_put_dev(qh->dev);
-
- dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
-}
-
-/*
- * Append this urb's qh after the last qh in skelqh->list
- *
- * Note that urb_priv.queue_list doesn't have a separate queue head;
- * it's a ring with every element "live".
- */
-static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- struct urb_priv *turbp;
- struct uhci_qh *lqh;
-
- /* Grab the last QH */
- lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
-
- /* Point to the next skelqh */
- urbp->qh->link = lqh->link;
- wmb(); /* Ordering is important */
-
- /*
- * Patch QHs for previous endpoint's queued URBs? HC goes
- * here next, not to the next skelqh it now points to.
- *
- * lqh --> td ... --> qh ... --> td --> qh ... --> td
- * | | |
- * v v v
- * +<----------------+-----------------+
- * v
- * newqh --> td ... --> td
- * |
- * v
- * ...
- *
- * The HC could see (and use!) any of these as we write them.
- */
- lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
- if (lqh->urbp) {
- list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list)
- turbp->qh->link = lqh->link;
- }
-
- list_add_tail(&urbp->qh->list, &skelqh->list);
-}
-
-/*
- * Start removal of QH from schedule; it finishes next frame.
- * TDs should be unlinked before this is called.
- */
-static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
-{
- struct uhci_qh *pqh;
- __le32 newlink;
- unsigned int age;
-
- if (!qh)
- return;
-
- /*
- * Only go through the hoops if it's actually linked in
- */
- if (!list_empty(&qh->list)) {
-
- /* If our queue is nonempty, make the next URB the head */
- if (!list_empty(&qh->urbp->queue_list)) {
- struct urb_priv *nurbp;
-
- nurbp = list_entry(qh->urbp->queue_list.next,
- struct urb_priv, queue_list);
- nurbp->queued = 0;
- list_add(&nurbp->qh->list, &qh->list);
- newlink = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
- } else
- newlink = qh->link;
-
- /* Fix up the previous QH's queue to link to either
- * the new head of this queue or the start of the
- * next endpoint's queue. */
- pqh = list_entry(qh->list.prev, struct uhci_qh, list);
- pqh->link = newlink;
- if (pqh->urbp) {
- struct urb_priv *turbp;
-
- list_for_each_entry(turbp, &pqh->urbp->queue_list,
- queue_list)
- turbp->qh->link = newlink;
- }
- wmb();
-
- /* Leave qh->link in case the HC is on the QH now, it will */
- /* continue the rest of the schedule */
- qh->element = UHCI_PTR_TERM;
-
- list_del_init(&qh->list);
- }
-
- list_del_init(&qh->urbp->queue_list);
- qh->urbp = NULL;
-
- age = uhci_get_current_frame_number(uhci);
- if (age != uhci->qh_remove_age) {
- uhci_free_pending_qhs(uhci);
- uhci->qh_remove_age = age;
- }
-
- /* Check to see if the remove list is empty. Set the IOC bit */
- /* to force an interrupt so we can remove the QH */
- if (list_empty(&uhci->qh_remove_list))
- uhci_set_next_interrupt(uhci);
-
- list_add(&qh->remove_list, &uhci->qh_remove_list);
-}
-
-static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- struct uhci_td *td;
-
- list_for_each_entry(td, &urbp->td_list, list) {
- if (toggle)
- td->token |= cpu_to_le32(TD_TOKEN_TOGGLE);
- else
- td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE);
-
- toggle ^= 1;
- }
-
- return toggle;
-}
-
-/* This function will append one URB's QH to another URB's QH. This is for */
-/* queuing interrupt, control or bulk transfers */
-static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb)
-{
- struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
- struct uhci_td *lltd;
-
- eurbp = eurb->hcpriv;
- urbp = urb->hcpriv;
-
- /* Find the first URB in the queue */
- furbp = eurbp;
- if (eurbp->queued) {
- list_for_each_entry(furbp, &eurbp->queue_list, queue_list)
- if (!furbp->queued)
- break;
- }
-
- lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
-
- lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
-
- /* Control transfers always start with toggle 0 */
- if (!usb_pipecontrol(urb->pipe))
- usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe),
- uhci_fixup_toggle(urb,
- uhci_toggle(td_token(lltd)) ^ 1));
-
- /* All qh's in the queue need to link to the next queue */
- urbp->qh->link = eurbp->qh->link;
-
- wmb(); /* Make sure we flush everything */
-
- lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
-
- list_add_tail(&urbp->queue_list, &furbp->queue_list);
-
- urbp->queued = 1;
-}
-
-static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct urb_priv *urbp, *nurbp, *purbp, *turbp;
- struct uhci_td *pltd;
- unsigned int toggle;
-
- urbp = urb->hcpriv;
-
- if (list_empty(&urbp->queue_list))
- return;
-
- nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
-
- /*
- * Fix up the toggle for the following URBs in the queue.
- * Only needed for bulk and interrupt: control and isochronous
- * endpoints don't propagate toggles between messages.
- */
- if (usb_pipebulk(urb->pipe) || usb_pipeint(urb->pipe)) {
- if (!urbp->queued)
- /* We just set the toggle in uhci_unlink_generic */
- toggle = usb_gettoggle(urb->dev,
- usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe));
- else {
- /* If we're in the middle of the queue, grab the */
- /* toggle from the TD previous to us */
- purbp = list_entry(urbp->queue_list.prev,
- struct urb_priv, queue_list);
- pltd = list_entry(purbp->td_list.prev,
- struct uhci_td, list);
- toggle = uhci_toggle(td_token(pltd)) ^ 1;
- }
-
- list_for_each_entry(turbp, &urbp->queue_list, queue_list) {
- if (!turbp->queued)
- break;
- toggle = uhci_fixup_toggle(turbp->urb, toggle);
- }
-
- usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe), toggle);
- }
-
- if (urbp->queued) {
- /* We're somewhere in the middle (or end). The case where
- * we're at the head is handled in uhci_remove_qh(). */
- purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
- queue_list);
-
- pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
- if (nurbp->queued)
- pltd->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
- else
- /* The next URB happens to be the beginning, so */
- /* we're the last, end the chain */
- pltd->link = UHCI_PTR_TERM;
- }
-
- /* urbp->queue_list is handled in uhci_remove_qh() */
-}
-
-static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct urb_priv *urbp;
-
- urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
- if (!urbp)
- return NULL;
-
- memset((void *)urbp, 0, sizeof(*urbp));
-
- urbp->inserttime = jiffies;
- urbp->fsbrtime = jiffies;
- urbp->urb = urb;
-
- INIT_LIST_HEAD(&urbp->td_list);
- INIT_LIST_HEAD(&urbp->queue_list);
- INIT_LIST_HEAD(&urbp->urb_list);
-
- list_add_tail(&urbp->urb_list, &uhci->urb_list);
-
- urb->hcpriv = urbp;
-
- return urbp;
-}
-
-static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
- td->urb = urb;
-
- list_add_tail(&td->list, &urbp->td_list);
-}
-
-static void uhci_remove_td_from_urb(struct uhci_td *td)
-{
- if (list_empty(&td->list))
- return;
-
- list_del_init(&td->list);
-
- td->urb = NULL;
-}
-
-static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct uhci_td *td, *tmp;
- struct urb_priv *urbp;
- unsigned int age;
-
- urbp = (struct urb_priv *)urb->hcpriv;
- if (!urbp)
- return;
-
- if (!list_empty(&urbp->urb_list))
- dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
- "or uhci->remove_list!\n", urb);
-
- age = uhci_get_current_frame_number(uhci);
- if (age != uhci->td_remove_age) {
- uhci_free_pending_tds(uhci);
- uhci->td_remove_age = age;
- }
-
- /* Check to see if the remove list is empty. Set the IOC bit */
- /* to force an interrupt so we can remove the TD's*/
- if (list_empty(&uhci->td_remove_list))
- uhci_set_next_interrupt(uhci);
-
- list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
- uhci_remove_td_from_urb(td);
- uhci_remove_td(uhci, td);
- list_add(&td->remove_list, &uhci->td_remove_list);
- }
-
- urb->hcpriv = NULL;
- kmem_cache_free(uhci_up_cachep, urbp);
-}
-
-static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
- if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) {
- urbp->fsbr = 1;
- if (!uhci->fsbr++ && !uhci->fsbrtimeout)
- uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
- }
-}
-
-static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
- if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) {
- urbp->fsbr = 0;
- if (!--uhci->fsbr)
- uhci->fsbrtimeout = jiffies + FSBR_DELAY;
- }
-}
-
-/*
- * Map status to standard result codes
- *
- * <status> is (td_status(td) & 0xF60000), a.k.a.
- * uhci_status_bits(td_status(td)).
- * Note: <status> does not include the TD_CTRL_NAK bit.
- * <dir_out> is True for output TDs and False for input TDs.
- */
-static int uhci_map_status(int status, int dir_out)
-{
- if (!status)
- return 0;
- if (status & TD_CTRL_BITSTUFF) /* Bitstuff error */
- return -EPROTO;
- if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */
- if (dir_out)
- return -EPROTO;
- else
- return -EILSEQ;
- }
- if (status & TD_CTRL_BABBLE) /* Babble */
- return -EOVERFLOW;
- if (status & TD_CTRL_DBUFERR) /* Buffer error */
- return -ENOSR;
- if (status & TD_CTRL_STALLED) /* Stalled */
- return -EPIPE;
- WARN_ON(status & TD_CTRL_ACTIVE); /* Active */
- return 0;
-}
-
-/*
- * Control transfers
- */
-static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- struct uhci_td *td;
- struct uhci_qh *qh, *skelqh;
- unsigned long destination, status;
- int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
- int len = urb->transfer_buffer_length;
- dma_addr_t data = urb->transfer_dma;
-
- /* The "pipe" thing contains the destination in bits 8--18 */
- destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
-
- /* 3 errors */
- status = TD_CTRL_ACTIVE | uhci_maxerr(3);
- if (urb->dev->speed == USB_SPEED_LOW)
- status |= TD_CTRL_LS;
-
- /*
- * Build the TD for the control request setup packet
- */
- td = uhci_alloc_td(uhci, urb->dev);
- if (!td)
- return -ENOMEM;
-
- uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status, destination | uhci_explen(7),
- urb->setup_dma);
-
- /*
- * If direction is "send", change the packet ID from SETUP (0x2D)
- * to OUT (0xE1). Else change it from SETUP to IN (0x69) and
- * set Short Packet Detect (SPD) for all data packets.
- */
- if (usb_pipeout(urb->pipe))
- destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
- else {
- destination ^= (USB_PID_SETUP ^ USB_PID_IN);
- status |= TD_CTRL_SPD;
- }
-
- /*
- * Build the DATA TD's
- */
- while (len > 0) {
- int pktsze = len;
-
- if (pktsze > maxsze)
- pktsze = maxsze;
-
- td = uhci_alloc_td(uhci, urb->dev);
- if (!td)
- return -ENOMEM;
-
- /* Alternate Data0/1 (start with Data1) */
- destination ^= TD_TOKEN_TOGGLE;
-
- uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1),
- data);
-
- data += pktsze;
- len -= pktsze;
- }
-
- /*
- * Build the final TD for control status
- */
- td = uhci_alloc_td(uhci, urb->dev);
- if (!td)
- return -ENOMEM;
-
- /*
- * It's IN if the pipe is an output pipe or we're not expecting
- * data back.
- */
- destination &= ~TD_TOKEN_PID_MASK;
- if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
- destination |= USB_PID_IN;
- else
- destination |= USB_PID_OUT;
-
- destination |= TD_TOKEN_TOGGLE; /* End in Data1 */
-
- status &= ~TD_CTRL_SPD;
-
- uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status | TD_CTRL_IOC,
- destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);
-
- qh = uhci_alloc_qh(uhci, urb->dev);
- if (!qh)
- return -ENOMEM;
-
- urbp->qh = qh;
- qh->urbp = urbp;
-
- uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
-
- /* Low-speed transfers get a different queue, and won't hog the bus.
- * Also, some devices enumerate better without FSBR; the easiest way
- * to do that is to put URBs on the low-speed queue while the device
- * is in the DEFAULT state. */
- if (urb->dev->speed == USB_SPEED_LOW ||
- urb->dev->state == USB_STATE_DEFAULT)
- skelqh = uhci->skel_ls_control_qh;
- else {
- skelqh = uhci->skel_fs_control_qh;
- uhci_inc_fsbr(uhci, urb);
- }
-
- if (eurb)
- uhci_append_queued_urb(uhci, eurb, urb);
- else
- uhci_insert_qh(uhci, skelqh, urb);
-
- return -EINPROGRESS;
-}
-
-/*
- * If control-IN transfer was short, the status packet wasn't sent.
- * This routine changes the element pointer in the QH to point at the
- * status TD. It's safe to do this even while the QH is live, because
- * the hardware only updates the element pointer following a successful
- * transfer. The inactive TD for the short packet won't cause an update,
- * so the pointer won't get overwritten. The next time the controller
- * sees this QH, it will send the status packet.
- */
-static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- struct uhci_td *td;
-
- urbp->short_control_packet = 1;
-
- td = list_entry(urbp->td_list.prev, struct uhci_td, list);
- urbp->qh->element = cpu_to_le32(td->dma_handle);
-
- return -EINPROGRESS;
-}
-
-
-static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct list_head *tmp, *head;
- struct urb_priv *urbp = urb->hcpriv;
- struct uhci_td *td;
- unsigned int status;
- int ret = 0;
-
- if (list_empty(&urbp->td_list))
- return -EINVAL;
-
- head = &urbp->td_list;
-
- if (urbp->short_control_packet) {
- tmp = head->prev;
- goto status_stage;
- }
-
- tmp = head->next;
- td = list_entry(tmp, struct uhci_td, list);
-
- /* The first TD is the SETUP stage, check the status, but skip */
- /* the count */
- status = uhci_status_bits(td_status(td));
- if (status & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
-
- if (status)
- goto td_error;
-
- urb->actual_length = 0;
-
- /* The rest of the TD's (but the last) are data */
- tmp = tmp->next;
- while (tmp != head && tmp->next != head) {
- unsigned int ctrlstat;
-
- td = list_entry(tmp, struct uhci_td, list);
- tmp = tmp->next;
-
- ctrlstat = td_status(td);
- status = uhci_status_bits(ctrlstat);
- if (status & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
-
- urb->actual_length += uhci_actual_length(ctrlstat);
-
- if (status)
- goto td_error;
-
- /* Check to see if we received a short packet */
- if (uhci_actual_length(ctrlstat) <
- uhci_expected_length(td_token(td))) {
- if (urb->transfer_flags & URB_SHORT_NOT_OK) {
- ret = -EREMOTEIO;
- goto err;
- }
-
- if (uhci_packetid(td_token(td)) == USB_PID_IN)
- return usb_control_retrigger_status(uhci, urb);
- else
- return 0;
- }
- }
-
-status_stage:
- td = list_entry(tmp, struct uhci_td, list);
-
- /* Control status stage */
- status = td_status(td);
-
-#ifdef I_HAVE_BUGGY_APC_BACKUPS
- /* APC BackUPS Pro kludge */
- /* It tries to send all of the descriptor instead of the amount */
- /* we requested */
- if (status & TD_CTRL_IOC && /* IOC is masked out by uhci_status_bits */
- status & TD_CTRL_ACTIVE &&
- status & TD_CTRL_NAK)
- return 0;
-#endif
-
- status = uhci_status_bits(status);
- if (status & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
-
- if (status)
- goto td_error;
-
- return 0;
-
-td_error:
- ret = uhci_map_status(status, uhci_packetout(td_token(td)));
-
-err:
- if ((debug == 1 && ret != -EPIPE) || debug > 1) {
- /* Some debugging code */
- dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
- __FUNCTION__, status);
-
- if (errbuf) {
- /* Print the chain for debugging purposes */
- uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
- lprintk(errbuf);
- }
- }
-
- return ret;
-}
-
-/*
- * Common submit for bulk and interrupt
- */
-static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh)
-{
- struct uhci_td *td;
- struct uhci_qh *qh;
- unsigned long destination, status;
- int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
- int len = urb->transfer_buffer_length;
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- dma_addr_t data = urb->transfer_dma;
-
- if (len < 0)
- return -EINVAL;
-
- /* The "pipe" thing contains the destination in bits 8--18 */
- destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
- status = uhci_maxerr(3) | TD_CTRL_ACTIVE;
- if (urb->dev->speed == USB_SPEED_LOW)
- status |= TD_CTRL_LS;
- if (usb_pipein(urb->pipe))
- status |= TD_CTRL_SPD;
-
- /*
- * Build the DATA TD's
- */
- do { /* Allow zero length packets */
- int pktsze = maxsze;
-
- if (pktsze >= len) {
- pktsze = len;
- if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
- status &= ~TD_CTRL_SPD;
- }
-
- td = uhci_alloc_td(uhci, urb->dev);
- if (!td)
- return -ENOMEM;
-
- uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1) |
- (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
- data);
-
- data += pktsze;
- len -= maxsze;
-
- usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe));
- } while (len > 0);
-
- /*
- * URB_ZERO_PACKET means adding a 0-length packet, if direction
- * is OUT and the transfer_length was an exact multiple of maxsze,
- * hence (len = transfer_length - N * maxsze) == 0
- * however, if transfer_length == 0, the zero packet was already
- * prepared above.
- */
- if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
- !len && urb->transfer_buffer_length) {
- td = uhci_alloc_td(uhci, urb->dev);
- if (!td)
- return -ENOMEM;
-
- uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status, destination | uhci_explen(UHCI_NULL_DATA_SIZE) |
- (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
- data);
-
- usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe));
- }
-
- /* Set the interrupt-on-completion flag on the last packet.
- * A more-or-less typical 4 KB URB (= size of one memory page)
- * will require about 3 ms to transfer; that's a little on the
- * fast side but not enough to justify delaying an interrupt
- * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
- * flag setting. */
- td->status |= cpu_to_le32(TD_CTRL_IOC);
-
- qh = uhci_alloc_qh(uhci, urb->dev);
- if (!qh)
- return -ENOMEM;
-
- urbp->qh = qh;
- qh->urbp = urbp;
-
- /* Always breadth first */
- uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
-
- if (eurb)
- uhci_append_queued_urb(uhci, eurb, urb);
- else
- uhci_insert_qh(uhci, skelqh, urb);
-
- return -EINPROGRESS;
-}
-
-/*
- * Common result for bulk and interrupt
- */
-static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct urb_priv *urbp = urb->hcpriv;
- struct uhci_td *td;
- unsigned int status = 0;
- int ret = 0;
-
- urb->actual_length = 0;
-
- list_for_each_entry(td, &urbp->td_list, list) {
- unsigned int ctrlstat = td_status(td);
-
- status = uhci_status_bits(ctrlstat);
- if (status & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
-
- urb->actual_length += uhci_actual_length(ctrlstat);
-
- if (status)
- goto td_error;
-
- if (uhci_actual_length(ctrlstat) <
- uhci_expected_length(td_token(td))) {
- if (urb->transfer_flags & URB_SHORT_NOT_OK) {
- ret = -EREMOTEIO;
- goto err;
- } else
- return 0;
- }
- }
-
- return 0;
-
-td_error:
- ret = uhci_map_status(status, uhci_packetout(td_token(td)));
-
-err:
- /*
- * Enable this chunk of code if you want to see some more debugging.
- * But be careful, it has the tendancy to starve out khubd and prevent
- * disconnects from happening successfully if you have a slow debug
- * log interface (like a serial console.
- */
-#if 0
- if ((debug == 1 && ret != -EPIPE) || debug > 1) {
- /* Some debugging code */
- dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
- __FUNCTION__, status);
-
- if (errbuf) {
- /* Print the chain for debugging purposes */
- uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
- lprintk(errbuf);
- }
- }
-#endif
- return ret;
-}
-
-static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
-{
- int ret;
-
- /* Can't have low-speed bulk transfers */
- if (urb->dev->speed == USB_SPEED_LOW)
- return -EINVAL;
-
- ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh);
- if (ret == -EINPROGRESS)
- uhci_inc_fsbr(uhci, urb);
-
- return ret;
-}
-
-static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
-{
- /* USB 1.1 interrupt transfers only involve one packet per interval;
- * that's the uhci_submit_common() "breadth first" policy. Drivers
- * can submit urbs of any length, but longer ones might need many
- * intervals to complete.
- */
- return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]);
-}
-
-/*
- * Isochronous transfers
- */
-static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end)
-{
- struct urb *last_urb = NULL;
- struct urb_priv *up;
- int ret = 0;
-
- list_for_each_entry(up, &uhci->urb_list, urb_list) {
- struct urb *u = up->urb;
-
- /* look for pending URB's with identical pipe handle */
- if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
- (u->status == -EINPROGRESS) && (u != urb)) {
- if (!last_urb)
- *start = u->start_frame;
- last_urb = u;
- }
- }
-
- if (last_urb) {
- *end = (last_urb->start_frame + last_urb->number_of_packets *
- last_urb->interval) & (UHCI_NUMFRAMES-1);
- ret = 0;
- } else
- ret = -1; /* no previous urb found */
-
- return ret;
-}
-
-static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb)
-{
- int limits;
- unsigned int start = 0, end = 0;
-
- if (urb->number_of_packets > 900) /* 900? Why? */
- return -EFBIG;
-
- limits = isochronous_find_limits(uhci, urb, &start, &end);
-
- if (urb->transfer_flags & URB_ISO_ASAP) {
- if (limits)
- urb->start_frame =
- (uhci_get_current_frame_number(uhci) +
- 10) & (UHCI_NUMFRAMES - 1);
- else
- urb->start_frame = end;
- } else {
- urb->start_frame &= (UHCI_NUMFRAMES - 1);
- /* FIXME: Sanity check */
- }
-
- return 0;
-}
-
-/*
- * Isochronous transfers
- */
-static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct uhci_td *td;
- int i, ret, frame;
- int status, destination;
-
- status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
- destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
- ret = isochronous_find_start(uhci, urb);
- if (ret)
- return ret;
-
- frame = urb->start_frame;
- for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) {
- if (!urb->iso_frame_desc[i].length)
- continue;
-
- td = uhci_alloc_td(uhci, urb->dev);
- if (!td)
- return -ENOMEM;
-
- uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length - 1),
- urb->transfer_dma + urb->iso_frame_desc[i].offset);
-
- if (i + 1 >= urb->number_of_packets)
- td->status |= cpu_to_le32(TD_CTRL_IOC);
-
- uhci_insert_td_frame_list(uhci, td, frame);
- }
-
- return -EINPROGRESS;
-}
-
-static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct uhci_td *td;
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- int status;
- int i, ret = 0;
-
- urb->actual_length = 0;
-
- i = 0;
- list_for_each_entry(td, &urbp->td_list, list) {
- int actlength;
- unsigned int ctrlstat = td_status(td);
-
- if (ctrlstat & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
-
- actlength = uhci_actual_length(ctrlstat);
- urb->iso_frame_desc[i].actual_length = actlength;
- urb->actual_length += actlength;
-
- status = uhci_map_status(uhci_status_bits(ctrlstat),
- usb_pipeout(urb->pipe));
- urb->iso_frame_desc[i].status = status;
- if (status) {
- urb->error_count++;
- ret = status;
- }
-
- i++;
- }
-
- return ret;
-}
-
-static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct urb_priv *up;
-
- /* We don't match Isoc transfers since they are special */
- if (usb_pipeisoc(urb->pipe))
- return NULL;
-
- list_for_each_entry(up, &uhci->urb_list, urb_list) {
- struct urb *u = up->urb;
-
- if (u->dev == urb->dev && u->status == -EINPROGRESS) {
- /* For control, ignore the direction */
- if (usb_pipecontrol(urb->pipe) &&
- (u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN))
- return u;
- else if (u->pipe == urb->pipe)
- return u;
- }
- }
-
- return NULL;
-}
-
-static int uhci_urb_enqueue(struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
- struct urb *urb, int mem_flags)
-{
- int ret;
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- unsigned long flags;
- struct urb *eurb;
- int bustime;
-
- spin_lock_irqsave(&uhci->schedule_lock, flags);
-
- ret = urb->status;
- if (ret != -EINPROGRESS) /* URB already unlinked! */
- goto out;
-
- eurb = uhci_find_urb_ep(uhci, urb);
-
- if (!uhci_alloc_urb_priv(uhci, urb)) {
- ret = -ENOMEM;
- goto out;
- }
-
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_CONTROL:
- ret = uhci_submit_control(uhci, urb, eurb);
- break;
- case PIPE_INTERRUPT:
- if (!eurb) {
- bustime = usb_check_bandwidth(urb->dev, urb);
- if (bustime < 0)
- ret = bustime;
- else {
- ret = uhci_submit_interrupt(uhci, urb, eurb);
- if (ret == -EINPROGRESS)
- usb_claim_bandwidth(urb->dev, urb, bustime, 0);
- }
- } else { /* inherit from parent */
- urb->bandwidth = eurb->bandwidth;
- ret = uhci_submit_interrupt(uhci, urb, eurb);
- }
- break;
- case PIPE_BULK:
- ret = uhci_submit_bulk(uhci, urb, eurb);
- break;
- case PIPE_ISOCHRONOUS:
- bustime = usb_check_bandwidth(urb->dev, urb);
- if (bustime < 0) {
- ret = bustime;
- break;
- }
-
- ret = uhci_submit_isochronous(uhci, urb);
- if (ret == -EINPROGRESS)
- usb_claim_bandwidth(urb->dev, urb, bustime, 1);
- break;
- }
-
- if (ret != -EINPROGRESS) {
- /* Submit failed, so delete it from the urb_list */
- struct urb_priv *urbp = urb->hcpriv;
-
- list_del_init(&urbp->urb_list);
- uhci_destroy_urb_priv(uhci, urb);
- } else
- ret = 0;
-
-out:
- spin_unlock_irqrestore(&uhci->schedule_lock, flags);
- return ret;
-}
-
-/*
- * Return the result of a transfer
- */
-static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
-{
- int ret = -EINPROGRESS;
- struct urb_priv *urbp;
-
- spin_lock(&urb->lock);
-
- urbp = (struct urb_priv *)urb->hcpriv;
-
- if (urb->status != -EINPROGRESS) /* URB already dequeued */
- goto out;
-
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_CONTROL:
- ret = uhci_result_control(uhci, urb);
- break;
- case PIPE_BULK:
- case PIPE_INTERRUPT:
- ret = uhci_result_common(uhci, urb);
- break;
- case PIPE_ISOCHRONOUS:
- ret = uhci_result_isochronous(uhci, urb);
- break;
- }
-
- if (ret == -EINPROGRESS)
- goto out;
- urb->status = ret;
-
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_CONTROL:
- case PIPE_BULK:
- case PIPE_ISOCHRONOUS:
- /* Release bandwidth for Interrupt or Isoc. transfers */
- if (urb->bandwidth)
- usb_release_bandwidth(urb->dev, urb, 1);
- uhci_unlink_generic(uhci, urb);
- break;
- case PIPE_INTERRUPT:
- /* Release bandwidth for Interrupt or Isoc. transfers */
- /* Make sure we don't release if we have a queued URB */
- if (list_empty(&urbp->queue_list) && urb->bandwidth)
- usb_release_bandwidth(urb->dev, urb, 0);
- else
- /* bandwidth was passed on to queued URB, */
- /* so don't let usb_unlink_urb() release it */
- urb->bandwidth = 0;
- uhci_unlink_generic(uhci, urb);
- break;
- default:
- dev_info(uhci_dev(uhci), "%s: unknown pipe type %d "
- "for urb %p\n",
- __FUNCTION__, usb_pipetype(urb->pipe), urb);
- }
-
- /* Move it from uhci->urb_list to uhci->complete_list */
- uhci_moveto_complete(uhci, urbp);
-
-out:
- spin_unlock(&urb->lock);
-}
-
-static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct list_head *head;
- struct uhci_td *td;
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- int prevactive = 0;
-
- uhci_dec_fsbr(uhci, urb); /* Safe since it checks */
-
- /*
- * Now we need to find out what the last successful toggle was
- * so we can update the local data toggle for the next transfer
- *
- * There are 2 ways the last successful completed TD is found:
- *
- * 1) The TD is NOT active and the actual length < expected length
- * 2) The TD is NOT active and it's the last TD in the chain
- *
- * and a third way the first uncompleted TD is found:
- *
- * 3) The TD is active and the previous TD is NOT active
- *
- * Control and Isochronous ignore the toggle, so this is safe
- * for all types
- *
- * FIXME: The toggle fixups won't be 100% reliable until we
- * change over to using a single queue for each endpoint and
- * stop the queue before unlinking.
- */
- head = &urbp->td_list;
- list_for_each_entry(td, head, list) {
- unsigned int ctrlstat = td_status(td);
-
- if (!(ctrlstat & TD_CTRL_ACTIVE) &&
- (uhci_actual_length(ctrlstat) <
- uhci_expected_length(td_token(td)) ||
- td->list.next == head))
- usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
- uhci_packetout(td_token(td)),
- uhci_toggle(td_token(td)) ^ 1);
- else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive)
- usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
- uhci_packetout(td_token(td)),
- uhci_toggle(td_token(td)));
-
- prevactive = ctrlstat & TD_CTRL_ACTIVE;
- }
-
- uhci_delete_queued_urb(uhci, urb);
-
- /* The interrupt loop will reclaim the QH's */
- uhci_remove_qh(uhci, urbp->qh);
- urbp->qh = NULL;
-}
-
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
-{
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- unsigned long flags;
- struct urb_priv *urbp;
- unsigned int age;
-
- spin_lock_irqsave(&uhci->schedule_lock, flags);
- urbp = urb->hcpriv;
- if (!urbp) /* URB was never linked! */
- goto done;
- list_del_init(&urbp->urb_list);
-
- uhci_unlink_generic(uhci, urb);
-
- age = uhci_get_current_frame_number(uhci);
- if (age != uhci->urb_remove_age) {
- uhci_remove_pending_urbps(uhci);
- uhci->urb_remove_age = age;
- }
-
- /* If we're the first, set the next interrupt bit */
- if (list_empty(&uhci->urb_remove_list))
- uhci_set_next_interrupt(uhci);
- list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
-
-done:
- spin_unlock_irqrestore(&uhci->schedule_lock, flags);
- return 0;
-}
-
-static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- struct list_head *head;
- struct uhci_td *td;
- int count = 0;
-
- uhci_dec_fsbr(uhci, urb);
-
- urbp->fsbr_timeout = 1;
-
- /*
- * Ideally we would want to fix qh->element as well, but it's
- * read/write by the HC, so that can introduce a race. It's not
- * really worth the hassle
- */
-
- head = &urbp->td_list;
- list_for_each_entry(td, head, list) {
- /*
- * Make sure we don't do the last one (since it'll have the
- * TERM bit set) as well as we skip every so many TD's to
- * make sure it doesn't hog the bandwidth
- */
- if (td->list.next != head && (count % DEPTH_INTERVAL) ==
- (DEPTH_INTERVAL - 1))
- td->link |= UHCI_PTR_DEPTH;
-
- count++;
- }
-
- return 0;
-}
-
-/*
- * uhci_get_current_frame_number()
- *
- * returns the current frame number for a USB bus/controller.
- */
-static unsigned int uhci_get_current_frame_number(struct uhci_hcd *uhci)
-{
- return inw(uhci->io_addr + USBFRNUM);
-}
+#include "uhci-hub.c"
+#include "uhci-debug.c"
+#include "uhci-q.c"
static int init_stall_timer(struct usb_hcd *hcd);
@@ -1592,62 +167,6 @@ static int init_stall_timer(struct usb_hcd *hcd)
return 0;
}
-static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
-{
- struct uhci_qh *qh, *tmp;
-
- list_for_each_entry_safe(qh, tmp, &uhci->qh_remove_list, remove_list) {
- list_del_init(&qh->remove_list);
-
- uhci_free_qh(uhci, qh);
- }
-}
-
-static void uhci_free_pending_tds(struct uhci_hcd *uhci)
-{
- struct uhci_td *td, *tmp;
-
- list_for_each_entry_safe(td, tmp, &uhci->td_remove_list, remove_list) {
- list_del_init(&td->remove_list);
-
- uhci_free_td(uhci, td);
- }
-}
-
-static void
-uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
-__releases(uhci->schedule_lock)
-__acquires(uhci->schedule_lock)
-{
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-
- uhci_destroy_urb_priv(uhci, urb);
-
- spin_unlock(&uhci->schedule_lock);
- usb_hcd_giveback_urb(hcd, urb, regs);
- spin_lock(&uhci->schedule_lock);
-}
-
-static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs)
-{
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- struct urb_priv *urbp, *tmp;
-
- list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) {
- struct urb *urb = urbp->urb;
-
- list_del_init(&urbp->urb_list);
- uhci_finish_urb(hcd, urb, regs);
- }
-}
-
-static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
-{
-
- /* Splice the urb_remove_list onto the end of the complete_list */
- list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev);
-}
-
static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
@@ -1866,6 +385,14 @@ static void hc_state_transitions(struct uhci_hcd *uhci)
}
}
+/*
+ * returns the current frame number for a USB bus/controller.
+ */
+static unsigned int uhci_get_current_frame_number(struct uhci_hcd *uhci)
+{
+ return inw(uhci->io_addr + USBFRNUM);
+}
+
static int start_hc(struct uhci_hcd *uhci)
{
unsigned long io_addr = uhci->io_addr;
@@ -1906,7 +433,7 @@ static int start_hc(struct uhci_hcd *uhci)
}
/*
- * De-allocate all resources..
+ * De-allocate all resources
*/
static void release_uhci(struct uhci_hcd *uhci)
{
@@ -1949,7 +476,7 @@ static int uhci_reset(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- uhci->io_addr = (unsigned long) hcd->regs;
+ uhci->io_addr = (unsigned long) hcd->rsrc_start;
/* Kick BIOS off this hardware and reset, so we won't get
* interrupts from any previous setup.
@@ -1984,7 +511,7 @@ static int uhci_start(struct usb_hcd *hcd)
struct usb_device *udev;
struct dentry *dentry;
- io_size = pci_resource_len(to_pci_dev(uhci_dev(uhci)), hcd->region);
+ io_size = (unsigned) hcd->rsrc_len;
dentry = debugfs_create_file(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, &uhci_debug_operations);
if (!dentry) {
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
new file mode 100644
index 000000000000..5a301ff13d84
--- /dev/null
+++ b/drivers/usb/host/uhci-q.c
@@ -0,0 +1,1488 @@
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Alan Stern <stern@rowland.harvard.edu>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
+ */
+
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
+static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
+static void uhci_remove_pending_urbps(struct uhci_hcd *uhci);
+static void uhci_free_pending_qhs(struct uhci_hcd *uhci);
+static void uhci_free_pending_tds(struct uhci_hcd *uhci);
+
+/*
+ * Technically, updating td->status here is a race, but it's not really a
+ * problem. The worst that can happen is that we set the IOC bit again
+ * generating a spurious interrupt. We could fix this by creating another
+ * QH and leaving the IOC bit always set, but then we would have to play
+ * games with the FSBR code to make sure we get the correct order in all
+ * the cases. I don't think it's worth the effort
+ */
+static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
+{
+ uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
+}
+
+static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
+{
+ uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
+}
+
+static inline void uhci_moveto_complete(struct uhci_hcd *uhci,
+ struct urb_priv *urbp)
+{
+ list_move_tail(&urbp->urb_list, &uhci->complete_list);
+}
+
+static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
+{
+ dma_addr_t dma_handle;
+ struct uhci_td *td;
+
+ td = dma_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle);
+ if (!td)
+ return NULL;
+
+ td->dma_handle = dma_handle;
+
+ td->link = UHCI_PTR_TERM;
+ td->buffer = 0;
+
+ td->frame = -1;
+ td->dev = dev;
+
+ INIT_LIST_HEAD(&td->list);
+ INIT_LIST_HEAD(&td->remove_list);
+ INIT_LIST_HEAD(&td->fl_list);
+
+ usb_get_dev(dev);
+
+ return td;
+}
+
+static inline void uhci_fill_td(struct uhci_td *td, u32 status,
+ u32 token, u32 buffer)
+{
+ td->status = cpu_to_le32(status);
+ td->token = cpu_to_le32(token);
+ td->buffer = cpu_to_le32(buffer);
+}
+
+/*
+ * We insert Isochronous URB's directly into the frame list at the beginning
+ */
+static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum)
+{
+ framenum &= (UHCI_NUMFRAMES - 1);
+
+ td->frame = framenum;
+
+ /* Is there a TD already mapped there? */
+ if (uhci->fl->frame_cpu[framenum]) {
+ struct uhci_td *ftd, *ltd;
+
+ ftd = uhci->fl->frame_cpu[framenum];
+ ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
+
+ list_add_tail(&td->fl_list, &ftd->fl_list);
+
+ td->link = ltd->link;
+ wmb();
+ ltd->link = cpu_to_le32(td->dma_handle);
+ } else {
+ td->link = uhci->fl->frame[framenum];
+ wmb();
+ uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle);
+ uhci->fl->frame_cpu[framenum] = td;
+ }
+}
+
+static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
+{
+ /* If it's not inserted, don't remove it */
+ if (td->frame == -1 && list_empty(&td->fl_list))
+ return;
+
+ if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
+ if (list_empty(&td->fl_list)) {
+ uhci->fl->frame[td->frame] = td->link;
+ uhci->fl->frame_cpu[td->frame] = NULL;
+ } else {
+ struct uhci_td *ntd;
+
+ ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
+ uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
+ uhci->fl->frame_cpu[td->frame] = ntd;
+ }
+ } else {
+ struct uhci_td *ptd;
+
+ ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list);
+ ptd->link = td->link;
+ }
+
+ wmb();
+ td->link = UHCI_PTR_TERM;
+
+ list_del_init(&td->fl_list);
+ td->frame = -1;
+}
+
+/*
+ * Inserts a td list into qh.
+ */
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct uhci_td *td;
+ __le32 *plink;
+
+ /* Ordering isn't important here yet since the QH hasn't been */
+ /* inserted into the schedule yet */
+ plink = &qh->element;
+ list_for_each_entry(td, &urbp->td_list, list) {
+ *plink = cpu_to_le32(td->dma_handle) | breadth;
+ plink = &td->link;
+ }
+ *plink = UHCI_PTR_TERM;
+}
+
+static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
+{
+ if (!list_empty(&td->list))
+ dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
+ if (!list_empty(&td->remove_list))
+ dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
+ if (!list_empty(&td->fl_list))
+ dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
+
+ if (td->dev)
+ usb_put_dev(td->dev);
+
+ dma_pool_free(uhci->td_pool, td, td->dma_handle);
+}
+
+static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev)
+{
+ dma_addr_t dma_handle;
+ struct uhci_qh *qh;
+
+ qh = dma_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
+ if (!qh)
+ return NULL;
+
+ qh->dma_handle = dma_handle;
+
+ qh->element = UHCI_PTR_TERM;
+ qh->link = UHCI_PTR_TERM;
+
+ qh->dev = dev;
+ qh->urbp = NULL;
+
+ INIT_LIST_HEAD(&qh->list);
+ INIT_LIST_HEAD(&qh->remove_list);
+
+ usb_get_dev(dev);
+
+ return qh;
+}
+
+static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ if (!list_empty(&qh->list))
+ dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh);
+ if (!list_empty(&qh->remove_list))
+ dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
+
+ if (qh->dev)
+ usb_put_dev(qh->dev);
+
+ dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
+}
+
+/*
+ * Append this urb's qh after the last qh in skelqh->list
+ *
+ * Note that urb_priv.queue_list doesn't have a separate queue head;
+ * it's a ring with every element "live".
+ */
+static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct urb_priv *turbp;
+ struct uhci_qh *lqh;
+
+ /* Grab the last QH */
+ lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
+
+ /* Point to the next skelqh */
+ urbp->qh->link = lqh->link;
+ wmb(); /* Ordering is important */
+
+ /*
+ * Patch QHs for previous endpoint's queued URBs? HC goes
+ * here next, not to the next skelqh it now points to.
+ *
+ * lqh --> td ... --> qh ... --> td --> qh ... --> td
+ * | | |
+ * v v v
+ * +<----------------+-----------------+
+ * v
+ * newqh --> td ... --> td
+ * |
+ * v
+ * ...
+ *
+ * The HC could see (and use!) any of these as we write them.
+ */
+ lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
+ if (lqh->urbp) {
+ list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list)
+ turbp->qh->link = lqh->link;
+ }
+
+ list_add_tail(&urbp->qh->list, &skelqh->list);
+}
+
+/*
+ * Start removal of QH from schedule; it finishes next frame.
+ * TDs should be unlinked before this is called.
+ */
+static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ struct uhci_qh *pqh;
+ __le32 newlink;
+ unsigned int age;
+
+ if (!qh)
+ return;
+
+ /*
+ * Only go through the hoops if it's actually linked in
+ */
+ if (!list_empty(&qh->list)) {
+
+ /* If our queue is nonempty, make the next URB the head */
+ if (!list_empty(&qh->urbp->queue_list)) {
+ struct urb_priv *nurbp;
+
+ nurbp = list_entry(qh->urbp->queue_list.next,
+ struct urb_priv, queue_list);
+ nurbp->queued = 0;
+ list_add(&nurbp->qh->list, &qh->list);
+ newlink = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
+ } else
+ newlink = qh->link;
+
+ /* Fix up the previous QH's queue to link to either
+ * the new head of this queue or the start of the
+ * next endpoint's queue. */
+ pqh = list_entry(qh->list.prev, struct uhci_qh, list);
+ pqh->link = newlink;
+ if (pqh->urbp) {
+ struct urb_priv *turbp;
+
+ list_for_each_entry(turbp, &pqh->urbp->queue_list,
+ queue_list)
+ turbp->qh->link = newlink;
+ }
+ wmb();
+
+ /* Leave qh->link in case the HC is on the QH now, it will */
+ /* continue the rest of the schedule */
+ qh->element = UHCI_PTR_TERM;
+
+ list_del_init(&qh->list);
+ }
+
+ list_del_init(&qh->urbp->queue_list);
+ qh->urbp = NULL;
+
+ age = uhci_get_current_frame_number(uhci);
+ if (age != uhci->qh_remove_age) {
+ uhci_free_pending_qhs(uhci);
+ uhci->qh_remove_age = age;
+ }
+
+ /* Check to see if the remove list is empty. Set the IOC bit */
+ /* to force an interrupt so we can remove the QH */
+ if (list_empty(&uhci->qh_remove_list))
+ uhci_set_next_interrupt(uhci);
+
+ list_add(&qh->remove_list, &uhci->qh_remove_list);
+}
+
+static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct uhci_td *td;
+
+ list_for_each_entry(td, &urbp->td_list, list) {
+ if (toggle)
+ td->token |= cpu_to_le32(TD_TOKEN_TOGGLE);
+ else
+ td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE);
+
+ toggle ^= 1;
+ }
+
+ return toggle;
+}
+
+/* This function will append one URB's QH to another URB's QH. This is for */
+/* queuing interrupt, control or bulk transfers */
+static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb)
+{
+ struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
+ struct uhci_td *lltd;
+
+ eurbp = eurb->hcpriv;
+ urbp = urb->hcpriv;
+
+ /* Find the first URB in the queue */
+ furbp = eurbp;
+ if (eurbp->queued) {
+ list_for_each_entry(furbp, &eurbp->queue_list, queue_list)
+ if (!furbp->queued)
+ break;
+ }
+
+ lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
+
+ lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
+
+ /* Control transfers always start with toggle 0 */
+ if (!usb_pipecontrol(urb->pipe))
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe),
+ uhci_fixup_toggle(urb,
+ uhci_toggle(td_token(lltd)) ^ 1));
+
+ /* All qh's in the queue need to link to the next queue */
+ urbp->qh->link = eurbp->qh->link;
+
+ wmb(); /* Make sure we flush everything */
+
+ lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
+
+ list_add_tail(&urbp->queue_list, &furbp->queue_list);
+
+ urbp->queued = 1;
+}
+
+static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct urb_priv *urbp, *nurbp, *purbp, *turbp;
+ struct uhci_td *pltd;
+ unsigned int toggle;
+
+ urbp = urb->hcpriv;
+
+ if (list_empty(&urbp->queue_list))
+ return;
+
+ nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
+
+ /*
+ * Fix up the toggle for the following URBs in the queue.
+ * Only needed for bulk and interrupt: control and isochronous
+ * endpoints don't propagate toggles between messages.
+ */
+ if (usb_pipebulk(urb->pipe) || usb_pipeint(urb->pipe)) {
+ if (!urbp->queued)
+ /* We just set the toggle in uhci_unlink_generic */
+ toggle = usb_gettoggle(urb->dev,
+ usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe));
+ else {
+ /* If we're in the middle of the queue, grab the */
+ /* toggle from the TD previous to us */
+ purbp = list_entry(urbp->queue_list.prev,
+ struct urb_priv, queue_list);
+ pltd = list_entry(purbp->td_list.prev,
+ struct uhci_td, list);
+ toggle = uhci_toggle(td_token(pltd)) ^ 1;
+ }
+
+ list_for_each_entry(turbp, &urbp->queue_list, queue_list) {
+ if (!turbp->queued)
+ break;
+ toggle = uhci_fixup_toggle(turbp->urb, toggle);
+ }
+
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe), toggle);
+ }
+
+ if (urbp->queued) {
+ /* We're somewhere in the middle (or end). The case where
+ * we're at the head is handled in uhci_remove_qh(). */
+ purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
+ queue_list);
+
+ pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
+ if (nurbp->queued)
+ pltd->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
+ else
+ /* The next URB happens to be the beginning, so */
+ /* we're the last, end the chain */
+ pltd->link = UHCI_PTR_TERM;
+ }
+
+ /* urbp->queue_list is handled in uhci_remove_qh() */
+}
+
+static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct urb_priv *urbp;
+
+ urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
+ if (!urbp)
+ return NULL;
+
+ memset((void *)urbp, 0, sizeof(*urbp));
+
+ urbp->inserttime = jiffies;
+ urbp->fsbrtime = jiffies;
+ urbp->urb = urb;
+
+ INIT_LIST_HEAD(&urbp->td_list);
+ INIT_LIST_HEAD(&urbp->queue_list);
+ INIT_LIST_HEAD(&urbp->urb_list);
+
+ list_add_tail(&urbp->urb_list, &uhci->urb_list);
+
+ urb->hcpriv = urbp;
+
+ return urbp;
+}
+
+static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+ td->urb = urb;
+
+ list_add_tail(&td->list, &urbp->td_list);
+}
+
+static void uhci_remove_td_from_urb(struct uhci_td *td)
+{
+ if (list_empty(&td->list))
+ return;
+
+ list_del_init(&td->list);
+
+ td->urb = NULL;
+}
+
+static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct uhci_td *td, *tmp;
+ struct urb_priv *urbp;
+ unsigned int age;
+
+ urbp = (struct urb_priv *)urb->hcpriv;
+ if (!urbp)
+ return;
+
+ if (!list_empty(&urbp->urb_list))
+ dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
+ "or uhci->remove_list!\n", urb);
+
+ age = uhci_get_current_frame_number(uhci);
+ if (age != uhci->td_remove_age) {
+ uhci_free_pending_tds(uhci);
+ uhci->td_remove_age = age;
+ }
+
+ /* Check to see if the remove list is empty. Set the IOC bit */
+ /* to force an interrupt so we can remove the TD's*/
+ if (list_empty(&uhci->td_remove_list))
+ uhci_set_next_interrupt(uhci);
+
+ list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
+ uhci_remove_td_from_urb(td);
+ uhci_remove_td(uhci, td);
+ list_add(&td->remove_list, &uhci->td_remove_list);
+ }
+
+ urb->hcpriv = NULL;
+ kmem_cache_free(uhci_up_cachep, urbp);
+}
+
+static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+ if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) {
+ urbp->fsbr = 1;
+ if (!uhci->fsbr++ && !uhci->fsbrtimeout)
+ uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
+ }
+}
+
+static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+ if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) {
+ urbp->fsbr = 0;
+ if (!--uhci->fsbr)
+ uhci->fsbrtimeout = jiffies + FSBR_DELAY;
+ }
+}
+
+/*
+ * Map status to standard result codes
+ *
+ * <status> is (td_status(td) & 0xF60000), a.k.a.
+ * uhci_status_bits(td_status(td)).
+ * Note: <status> does not include the TD_CTRL_NAK bit.
+ * <dir_out> is True for output TDs and False for input TDs.
+ */
+static int uhci_map_status(int status, int dir_out)
+{
+ if (!status)
+ return 0;
+ if (status & TD_CTRL_BITSTUFF) /* Bitstuff error */
+ return -EPROTO;
+ if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */
+ if (dir_out)
+ return -EPROTO;
+ else
+ return -EILSEQ;
+ }
+ if (status & TD_CTRL_BABBLE) /* Babble */
+ return -EOVERFLOW;
+ if (status & TD_CTRL_DBUFERR) /* Buffer error */
+ return -ENOSR;
+ if (status & TD_CTRL_STALLED) /* Stalled */
+ return -EPIPE;
+ WARN_ON(status & TD_CTRL_ACTIVE); /* Active */
+ return 0;
+}
+
+/*
+ * Control transfers
+ */
+static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct uhci_td *td;
+ struct uhci_qh *qh, *skelqh;
+ unsigned long destination, status;
+ int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+ int len = urb->transfer_buffer_length;
+ dma_addr_t data = urb->transfer_dma;
+
+ /* The "pipe" thing contains the destination in bits 8--18 */
+ destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+
+ /* 3 errors */
+ status = TD_CTRL_ACTIVE | uhci_maxerr(3);
+ if (urb->dev->speed == USB_SPEED_LOW)
+ status |= TD_CTRL_LS;
+
+ /*
+ * Build the TD for the control request setup packet
+ */
+ td = uhci_alloc_td(uhci, urb->dev);
+ if (!td)
+ return -ENOMEM;
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | uhci_explen(7),
+ urb->setup_dma);
+
+ /*
+ * If direction is "send", change the packet ID from SETUP (0x2D)
+ * to OUT (0xE1). Else change it from SETUP to IN (0x69) and
+ * set Short Packet Detect (SPD) for all data packets.
+ */
+ if (usb_pipeout(urb->pipe))
+ destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
+ else {
+ destination ^= (USB_PID_SETUP ^ USB_PID_IN);
+ status |= TD_CTRL_SPD;
+ }
+
+ /*
+ * Build the DATA TD's
+ */
+ while (len > 0) {
+ int pktsze = len;
+
+ if (pktsze > maxsze)
+ pktsze = maxsze;
+
+ td = uhci_alloc_td(uhci, urb->dev);
+ if (!td)
+ return -ENOMEM;
+
+ /* Alternate Data0/1 (start with Data1) */
+ destination ^= TD_TOKEN_TOGGLE;
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1),
+ data);
+
+ data += pktsze;
+ len -= pktsze;
+ }
+
+ /*
+ * Build the final TD for control status
+ */
+ td = uhci_alloc_td(uhci, urb->dev);
+ if (!td)
+ return -ENOMEM;
+
+ /*
+ * It's IN if the pipe is an output pipe or we're not expecting
+ * data back.
+ */
+ destination &= ~TD_TOKEN_PID_MASK;
+ if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
+ destination |= USB_PID_IN;
+ else
+ destination |= USB_PID_OUT;
+
+ destination |= TD_TOKEN_TOGGLE; /* End in Data1 */
+
+ status &= ~TD_CTRL_SPD;
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status | TD_CTRL_IOC,
+ destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);
+
+ qh = uhci_alloc_qh(uhci, urb->dev);
+ if (!qh)
+ return -ENOMEM;
+
+ urbp->qh = qh;
+ qh->urbp = urbp;
+
+ uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
+
+ /* Low-speed transfers get a different queue, and won't hog the bus.
+ * Also, some devices enumerate better without FSBR; the easiest way
+ * to do that is to put URBs on the low-speed queue while the device
+ * is in the DEFAULT state. */
+ if (urb->dev->speed == USB_SPEED_LOW ||
+ urb->dev->state == USB_STATE_DEFAULT)
+ skelqh = uhci->skel_ls_control_qh;
+ else {
+ skelqh = uhci->skel_fs_control_qh;
+ uhci_inc_fsbr(uhci, urb);
+ }
+
+ if (eurb)
+ uhci_append_queued_urb(uhci, eurb, urb);
+ else
+ uhci_insert_qh(uhci, skelqh, urb);
+
+ return -EINPROGRESS;
+}
+
+/*
+ * If control-IN transfer was short, the status packet wasn't sent.
+ * This routine changes the element pointer in the QH to point at the
+ * status TD. It's safe to do this even while the QH is live, because
+ * the hardware only updates the element pointer following a successful
+ * transfer. The inactive TD for the short packet won't cause an update,
+ * so the pointer won't get overwritten. The next time the controller
+ * sees this QH, it will send the status packet.
+ */
+static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct uhci_td *td;
+
+ urbp->short_control_packet = 1;
+
+ td = list_entry(urbp->td_list.prev, struct uhci_td, list);
+ urbp->qh->element = cpu_to_le32(td->dma_handle);
+
+ return -EINPROGRESS;
+}
+
+
+static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct list_head *tmp, *head;
+ struct urb_priv *urbp = urb->hcpriv;
+ struct uhci_td *td;
+ unsigned int status;
+ int ret = 0;
+
+ if (list_empty(&urbp->td_list))
+ return -EINVAL;
+
+ head = &urbp->td_list;
+
+ if (urbp->short_control_packet) {
+ tmp = head->prev;
+ goto status_stage;
+ }
+
+ tmp = head->next;
+ td = list_entry(tmp, struct uhci_td, list);
+
+ /* The first TD is the SETUP stage, check the status, but skip */
+ /* the count */
+ status = uhci_status_bits(td_status(td));
+ if (status & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
+
+ if (status)
+ goto td_error;
+
+ urb->actual_length = 0;
+
+ /* The rest of the TD's (but the last) are data */
+ tmp = tmp->next;
+ while (tmp != head && tmp->next != head) {
+ unsigned int ctrlstat;
+
+ td = list_entry(tmp, struct uhci_td, list);
+ tmp = tmp->next;
+
+ ctrlstat = td_status(td);
+ status = uhci_status_bits(ctrlstat);
+ if (status & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
+
+ urb->actual_length += uhci_actual_length(ctrlstat);
+
+ if (status)
+ goto td_error;
+
+ /* Check to see if we received a short packet */
+ if (uhci_actual_length(ctrlstat) <
+ uhci_expected_length(td_token(td))) {
+ if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+ ret = -EREMOTEIO;
+ goto err;
+ }
+
+ if (uhci_packetid(td_token(td)) == USB_PID_IN)
+ return usb_control_retrigger_status(uhci, urb);
+ else
+ return 0;
+ }
+ }
+
+status_stage:
+ td = list_entry(tmp, struct uhci_td, list);
+
+ /* Control status stage */
+ status = td_status(td);
+
+#ifdef I_HAVE_BUGGY_APC_BACKUPS
+ /* APC BackUPS Pro kludge */
+ /* It tries to send all of the descriptor instead of the amount */
+ /* we requested */
+ if (status & TD_CTRL_IOC && /* IOC is masked out by uhci_status_bits */
+ status & TD_CTRL_ACTIVE &&
+ status & TD_CTRL_NAK)
+ return 0;
+#endif
+
+ status = uhci_status_bits(status);
+ if (status & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
+
+ if (status)
+ goto td_error;
+
+ return 0;
+
+td_error:
+ ret = uhci_map_status(status, uhci_packetout(td_token(td)));
+
+err:
+ if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+ /* Some debugging code */
+ dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
+ __FUNCTION__, status);
+
+ if (errbuf) {
+ /* Print the chain for debugging purposes */
+ uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+
+ lprintk(errbuf);
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Common submit for bulk and interrupt
+ */
+static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh)
+{
+ struct uhci_td *td;
+ struct uhci_qh *qh;
+ unsigned long destination, status;
+ int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+ int len = urb->transfer_buffer_length;
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ dma_addr_t data = urb->transfer_dma;
+
+ if (len < 0)
+ return -EINVAL;
+
+ /* The "pipe" thing contains the destination in bits 8--18 */
+ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+ status = uhci_maxerr(3) | TD_CTRL_ACTIVE;
+ if (urb->dev->speed == USB_SPEED_LOW)
+ status |= TD_CTRL_LS;
+ if (usb_pipein(urb->pipe))
+ status |= TD_CTRL_SPD;
+
+ /*
+ * Build the DATA TD's
+ */
+ do { /* Allow zero length packets */
+ int pktsze = maxsze;
+
+ if (pktsze >= len) {
+ pktsze = len;
+ if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+ status &= ~TD_CTRL_SPD;
+ }
+
+ td = uhci_alloc_td(uhci, urb->dev);
+ if (!td)
+ return -ENOMEM;
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1) |
+ (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
+ data);
+
+ data += pktsze;
+ len -= maxsze;
+
+ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe));
+ } while (len > 0);
+
+ /*
+ * URB_ZERO_PACKET means adding a 0-length packet, if direction
+ * is OUT and the transfer_length was an exact multiple of maxsze,
+ * hence (len = transfer_length - N * maxsze) == 0
+ * however, if transfer_length == 0, the zero packet was already
+ * prepared above.
+ */
+ if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
+ !len && urb->transfer_buffer_length) {
+ td = uhci_alloc_td(uhci, urb->dev);
+ if (!td)
+ return -ENOMEM;
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | uhci_explen(UHCI_NULL_DATA_SIZE) |
+ (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
+ data);
+
+ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe));
+ }
+
+ /* Set the interrupt-on-completion flag on the last packet.
+ * A more-or-less typical 4 KB URB (= size of one memory page)
+ * will require about 3 ms to transfer; that's a little on the
+ * fast side but not enough to justify delaying an interrupt
+ * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
+ * flag setting. */
+ td->status |= cpu_to_le32(TD_CTRL_IOC);
+
+ qh = uhci_alloc_qh(uhci, urb->dev);
+ if (!qh)
+ return -ENOMEM;
+
+ urbp->qh = qh;
+ qh->urbp = urbp;
+
+ /* Always breadth first */
+ uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
+
+ if (eurb)
+ uhci_append_queued_urb(uhci, eurb, urb);
+ else
+ uhci_insert_qh(uhci, skelqh, urb);
+
+ return -EINPROGRESS;
+}
+
+/*
+ * Common result for bulk and interrupt
+ */
+static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct urb_priv *urbp = urb->hcpriv;
+ struct uhci_td *td;
+ unsigned int status = 0;
+ int ret = 0;
+
+ urb->actual_length = 0;
+
+ list_for_each_entry(td, &urbp->td_list, list) {
+ unsigned int ctrlstat = td_status(td);
+
+ status = uhci_status_bits(ctrlstat);
+ if (status & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
+
+ urb->actual_length += uhci_actual_length(ctrlstat);
+
+ if (status)
+ goto td_error;
+
+ if (uhci_actual_length(ctrlstat) <
+ uhci_expected_length(td_token(td))) {
+ if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+ ret = -EREMOTEIO;
+ goto err;
+ } else
+ return 0;
+ }
+ }
+
+ return 0;
+
+td_error:
+ ret = uhci_map_status(status, uhci_packetout(td_token(td)));
+
+err:
+ /*
+ * Enable this chunk of code if you want to see some more debugging.
+ * But be careful, it has the tendancy to starve out khubd and prevent
+ * disconnects from happening successfully if you have a slow debug
+ * log interface (like a serial console.
+ */
+#if 0
+ if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+ /* Some debugging code */
+ dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
+ __FUNCTION__, status);
+
+ if (errbuf) {
+ /* Print the chain for debugging purposes */
+ uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+
+ lprintk(errbuf);
+ }
+ }
+#endif
+ return ret;
+}
+
+static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+{
+ int ret;
+
+ /* Can't have low-speed bulk transfers */
+ if (urb->dev->speed == USB_SPEED_LOW)
+ return -EINVAL;
+
+ ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh);
+ if (ret == -EINPROGRESS)
+ uhci_inc_fsbr(uhci, urb);
+
+ return ret;
+}
+
+static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+{
+ /* USB 1.1 interrupt transfers only involve one packet per interval;
+ * that's the uhci_submit_common() "breadth first" policy. Drivers
+ * can submit urbs of any length, but longer ones might need many
+ * intervals to complete.
+ */
+ return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]);
+}
+
+/*
+ * Isochronous transfers
+ */
+static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end)
+{
+ struct urb *last_urb = NULL;
+ struct urb_priv *up;
+ int ret = 0;
+
+ list_for_each_entry(up, &uhci->urb_list, urb_list) {
+ struct urb *u = up->urb;
+
+ /* look for pending URB's with identical pipe handle */
+ if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
+ (u->status == -EINPROGRESS) && (u != urb)) {
+ if (!last_urb)
+ *start = u->start_frame;
+ last_urb = u;
+ }
+ }
+
+ if (last_urb) {
+ *end = (last_urb->start_frame + last_urb->number_of_packets *
+ last_urb->interval) & (UHCI_NUMFRAMES-1);
+ ret = 0;
+ } else
+ ret = -1; /* no previous urb found */
+
+ return ret;
+}
+
+static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb)
+{
+ int limits;
+ unsigned int start = 0, end = 0;
+
+ if (urb->number_of_packets > 900) /* 900? Why? */
+ return -EFBIG;
+
+ limits = isochronous_find_limits(uhci, urb, &start, &end);
+
+ if (urb->transfer_flags & URB_ISO_ASAP) {
+ if (limits)
+ urb->start_frame =
+ (uhci_get_current_frame_number(uhci) +
+ 10) & (UHCI_NUMFRAMES - 1);
+ else
+ urb->start_frame = end;
+ } else {
+ urb->start_frame &= (UHCI_NUMFRAMES - 1);
+ /* FIXME: Sanity check */
+ }
+
+ return 0;
+}
+
+/*
+ * Isochronous transfers
+ */
+static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct uhci_td *td;
+ int i, ret, frame;
+ int status, destination;
+
+ status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+ ret = isochronous_find_start(uhci, urb);
+ if (ret)
+ return ret;
+
+ frame = urb->start_frame;
+ for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) {
+ if (!urb->iso_frame_desc[i].length)
+ continue;
+
+ td = uhci_alloc_td(uhci, urb->dev);
+ if (!td)
+ return -ENOMEM;
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length - 1),
+ urb->transfer_dma + urb->iso_frame_desc[i].offset);
+
+ if (i + 1 >= urb->number_of_packets)
+ td->status |= cpu_to_le32(TD_CTRL_IOC);
+
+ uhci_insert_td_frame_list(uhci, td, frame);
+ }
+
+ return -EINPROGRESS;
+}
+
+static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct uhci_td *td;
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ int status;
+ int i, ret = 0;
+
+ urb->actual_length = 0;
+
+ i = 0;
+ list_for_each_entry(td, &urbp->td_list, list) {
+ int actlength;
+ unsigned int ctrlstat = td_status(td);
+
+ if (ctrlstat & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
+
+ actlength = uhci_actual_length(ctrlstat);
+ urb->iso_frame_desc[i].actual_length = actlength;
+ urb->actual_length += actlength;
+
+ status = uhci_map_status(uhci_status_bits(ctrlstat),
+ usb_pipeout(urb->pipe));
+ urb->iso_frame_desc[i].status = status;
+ if (status) {
+ urb->error_count++;
+ ret = status;
+ }
+
+ i++;
+ }
+
+ return ret;
+}
+
+static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct urb_priv *up;
+
+ /* We don't match Isoc transfers since they are special */
+ if (usb_pipeisoc(urb->pipe))
+ return NULL;
+
+ list_for_each_entry(up, &uhci->urb_list, urb_list) {
+ struct urb *u = up->urb;
+
+ if (u->dev == urb->dev && u->status == -EINPROGRESS) {
+ /* For control, ignore the direction */
+ if (usb_pipecontrol(urb->pipe) &&
+ (u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN))
+ return u;
+ else if (u->pipe == urb->pipe)
+ return u;
+ }
+ }
+
+ return NULL;
+}
+
+static int uhci_urb_enqueue(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep,
+ struct urb *urb, int mem_flags)
+{
+ int ret;
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ unsigned long flags;
+ struct urb *eurb;
+ int bustime;
+
+ spin_lock_irqsave(&uhci->schedule_lock, flags);
+
+ ret = urb->status;
+ if (ret != -EINPROGRESS) /* URB already unlinked! */
+ goto out;
+
+ eurb = uhci_find_urb_ep(uhci, urb);
+
+ if (!uhci_alloc_urb_priv(uhci, urb)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ ret = uhci_submit_control(uhci, urb, eurb);
+ break;
+ case PIPE_INTERRUPT:
+ if (!eurb) {
+ bustime = usb_check_bandwidth(urb->dev, urb);
+ if (bustime < 0)
+ ret = bustime;
+ else {
+ ret = uhci_submit_interrupt(uhci, urb, eurb);
+ if (ret == -EINPROGRESS)
+ usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+ }
+ } else { /* inherit from parent */
+ urb->bandwidth = eurb->bandwidth;
+ ret = uhci_submit_interrupt(uhci, urb, eurb);
+ }
+ break;
+ case PIPE_BULK:
+ ret = uhci_submit_bulk(uhci, urb, eurb);
+ break;
+ case PIPE_ISOCHRONOUS:
+ bustime = usb_check_bandwidth(urb->dev, urb);
+ if (bustime < 0) {
+ ret = bustime;
+ break;
+ }
+
+ ret = uhci_submit_isochronous(uhci, urb);
+ if (ret == -EINPROGRESS)
+ usb_claim_bandwidth(urb->dev, urb, bustime, 1);
+ break;
+ }
+
+ if (ret != -EINPROGRESS) {
+ /* Submit failed, so delete it from the urb_list */
+ struct urb_priv *urbp = urb->hcpriv;
+
+ list_del_init(&urbp->urb_list);
+ uhci_destroy_urb_priv(uhci, urb);
+ } else
+ ret = 0;
+
+out:
+ spin_unlock_irqrestore(&uhci->schedule_lock, flags);
+ return ret;
+}
+
+/*
+ * Return the result of a transfer
+ */
+static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
+{
+ int ret = -EINPROGRESS;
+ struct urb_priv *urbp;
+
+ spin_lock(&urb->lock);
+
+ urbp = (struct urb_priv *)urb->hcpriv;
+
+ if (urb->status != -EINPROGRESS) /* URB already dequeued */
+ goto out;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ ret = uhci_result_control(uhci, urb);
+ break;
+ case PIPE_BULK:
+ case PIPE_INTERRUPT:
+ ret = uhci_result_common(uhci, urb);
+ break;
+ case PIPE_ISOCHRONOUS:
+ ret = uhci_result_isochronous(uhci, urb);
+ break;
+ }
+
+ if (ret == -EINPROGRESS)
+ goto out;
+ urb->status = ret;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ case PIPE_ISOCHRONOUS:
+ /* Release bandwidth for Interrupt or Isoc. transfers */
+ if (urb->bandwidth)
+ usb_release_bandwidth(urb->dev, urb, 1);
+ uhci_unlink_generic(uhci, urb);
+ break;
+ case PIPE_INTERRUPT:
+ /* Release bandwidth for Interrupt or Isoc. transfers */
+ /* Make sure we don't release if we have a queued URB */
+ if (list_empty(&urbp->queue_list) && urb->bandwidth)
+ usb_release_bandwidth(urb->dev, urb, 0);
+ else
+ /* bandwidth was passed on to queued URB, */
+ /* so don't let usb_unlink_urb() release it */
+ urb->bandwidth = 0;
+ uhci_unlink_generic(uhci, urb);
+ break;
+ default:
+ dev_info(uhci_dev(uhci), "%s: unknown pipe type %d "
+ "for urb %p\n",
+ __FUNCTION__, usb_pipetype(urb->pipe), urb);
+ }
+
+ /* Move it from uhci->urb_list to uhci->complete_list */
+ uhci_moveto_complete(uhci, urbp);
+
+out:
+ spin_unlock(&urb->lock);
+}
+
+static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct list_head *head;
+ struct uhci_td *td;
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ int prevactive = 0;
+
+ uhci_dec_fsbr(uhci, urb); /* Safe since it checks */
+
+ /*
+ * Now we need to find out what the last successful toggle was
+ * so we can update the local data toggle for the next transfer
+ *
+ * There are 2 ways the last successful completed TD is found:
+ *
+ * 1) The TD is NOT active and the actual length < expected length
+ * 2) The TD is NOT active and it's the last TD in the chain
+ *
+ * and a third way the first uncompleted TD is found:
+ *
+ * 3) The TD is active and the previous TD is NOT active
+ *
+ * Control and Isochronous ignore the toggle, so this is safe
+ * for all types
+ *
+ * FIXME: The toggle fixups won't be 100% reliable until we
+ * change over to using a single queue for each endpoint and
+ * stop the queue before unlinking.
+ */
+ head = &urbp->td_list;
+ list_for_each_entry(td, head, list) {
+ unsigned int ctrlstat = td_status(td);
+
+ if (!(ctrlstat & TD_CTRL_ACTIVE) &&
+ (uhci_actual_length(ctrlstat) <
+ uhci_expected_length(td_token(td)) ||
+ td->list.next == head))
+ usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
+ uhci_packetout(td_token(td)),
+ uhci_toggle(td_token(td)) ^ 1);
+ else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive)
+ usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
+ uhci_packetout(td_token(td)),
+ uhci_toggle(td_token(td)));
+
+ prevactive = ctrlstat & TD_CTRL_ACTIVE;
+ }
+
+ uhci_delete_queued_urb(uhci, urb);
+
+ /* The interrupt loop will reclaim the QH's */
+ uhci_remove_qh(uhci, urbp->qh);
+ urbp->qh = NULL;
+}
+
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ unsigned long flags;
+ struct urb_priv *urbp;
+ unsigned int age;
+
+ spin_lock_irqsave(&uhci->schedule_lock, flags);
+ urbp = urb->hcpriv;
+ if (!urbp) /* URB was never linked! */
+ goto done;
+ list_del_init(&urbp->urb_list);
+
+ uhci_unlink_generic(uhci, urb);
+
+ age = uhci_get_current_frame_number(uhci);
+ if (age != uhci->urb_remove_age) {
+ uhci_remove_pending_urbps(uhci);
+ uhci->urb_remove_age = age;
+ }
+
+ /* If we're the first, set the next interrupt bit */
+ if (list_empty(&uhci->urb_remove_list))
+ uhci_set_next_interrupt(uhci);
+ list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
+
+done:
+ spin_unlock_irqrestore(&uhci->schedule_lock, flags);
+ return 0;
+}
+
+static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct list_head *head;
+ struct uhci_td *td;
+ int count = 0;
+
+ uhci_dec_fsbr(uhci, urb);
+
+ urbp->fsbr_timeout = 1;
+
+ /*
+ * Ideally we would want to fix qh->element as well, but it's
+ * read/write by the HC, so that can introduce a race. It's not
+ * really worth the hassle
+ */
+
+ head = &urbp->td_list;
+ list_for_each_entry(td, head, list) {
+ /*
+ * Make sure we don't do the last one (since it'll have the
+ * TERM bit set) as well as we skip every so many TD's to
+ * make sure it doesn't hog the bandwidth
+ */
+ if (td->list.next != head && (count % DEPTH_INTERVAL) ==
+ (DEPTH_INTERVAL - 1))
+ td->link |= UHCI_PTR_DEPTH;
+
+ count++;
+ }
+
+ return 0;
+}
+
+static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
+{
+ struct uhci_qh *qh, *tmp;
+
+ list_for_each_entry_safe(qh, tmp, &uhci->qh_remove_list, remove_list) {
+ list_del_init(&qh->remove_list);
+
+ uhci_free_qh(uhci, qh);
+ }
+}
+
+static void uhci_free_pending_tds(struct uhci_hcd *uhci)
+{
+ struct uhci_td *td, *tmp;
+
+ list_for_each_entry_safe(td, tmp, &uhci->td_remove_list, remove_list) {
+ list_del_init(&td->remove_list);
+
+ uhci_free_td(uhci, td);
+ }
+}
+
+static void
+uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
+__releases(uhci->schedule_lock)
+__acquires(uhci->schedule_lock)
+{
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+ uhci_destroy_urb_priv(uhci, urb);
+
+ spin_unlock(&uhci->schedule_lock);
+ usb_hcd_giveback_urb(hcd, urb, regs);
+ spin_lock(&uhci->schedule_lock);
+}
+
+static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs)
+{
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ struct urb_priv *urbp, *tmp;
+
+ list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) {
+ struct urb *urb = urbp->urb;
+
+ list_del_init(&urbp->urb_list);
+ uhci_finish_urb(hcd, urb, regs);
+ }
+}
+
+static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
+{
+
+ /* Splice the urb_remove_list onto the end of the complete_list */
+ list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev);
+}
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 83f3c9feae2b..5791723e6083 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -95,6 +95,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
+#include <linux/wait.h>
#include <linux/usb.h>
#include <linux/fs.h>
@@ -330,7 +331,7 @@ static void mdc800_usb_irq (struct urb *urb, struct pt_regs *res)
{
mdc800->camera_request_ready=0;
mdc800->irq_woken=1;
- wake_up_interruptible (&mdc800->irq_wait);
+ wake_up (&mdc800->irq_wait);
}
}
@@ -346,19 +347,9 @@ static void mdc800_usb_irq (struct urb *urb, struct pt_regs *res)
*/
static int mdc800_usb_waitForIRQ (int mode, int msec)
{
- DECLARE_WAITQUEUE(wait, current);
- long timeout;
-
mdc800->camera_request_ready=1+mode;
- add_wait_queue(&mdc800->irq_wait, &wait);
- timeout = msec*HZ/1000;
- while (!mdc800->irq_woken && timeout)
- {
- set_current_state(TASK_UNINTERRUPTIBLE);
- timeout = schedule_timeout (timeout);
- }
- remove_wait_queue(&mdc800->irq_wait, &wait);
+ wait_event_timeout(mdc800->irq_wait, mdc800->irq_woken, msec*HZ/1000);
mdc800->irq_woken = 0;
if (mdc800->camera_request_ready>0)
@@ -395,7 +386,7 @@ static void mdc800_usb_write_notify (struct urb *urb, struct pt_regs *res)
mdc800->state=READY;
}
mdc800->written = 1;
- wake_up_interruptible (&mdc800->write_wait);
+ wake_up (&mdc800->write_wait);
}
@@ -423,7 +414,7 @@ static void mdc800_usb_download_notify (struct urb *urb, struct pt_regs *res)
err ("request bytes fails (status:%i)", urb->status);
}
mdc800->downloaded = 1;
- wake_up_interruptible (&mdc800->download_wait);
+ wake_up (&mdc800->download_wait);
}
@@ -704,8 +695,6 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
{
size_t left=len, sts=len; /* single transfer size */
char __user *ptr = buf;
- long timeout;
- DECLARE_WAITQUEUE(wait, current);
down (&mdc800->io_lock);
if (mdc800->state == NOT_CONNECTED)
@@ -751,14 +740,8 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
up (&mdc800->io_lock);
return len-left;
}
- add_wait_queue(&mdc800->download_wait, &wait);
- timeout = TO_DOWNLOAD_GET_READY*HZ/1000;
- while (!mdc800->downloaded && timeout)
- {
- set_current_state(TASK_UNINTERRUPTIBLE);
- timeout = schedule_timeout (timeout);
- }
- remove_wait_queue(&mdc800->download_wait, &wait);
+ wait_event_timeout(mdc800->download_wait, mdc800->downloaded,
+ TO_DOWNLOAD_GET_READY*HZ/1000);
mdc800->downloaded = 0;
if (mdc800->download_urb->status != 0)
{
@@ -802,7 +785,6 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
static ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos)
{
size_t i=0;
- DECLARE_WAITQUEUE(wait, current);
down (&mdc800->io_lock);
if (mdc800->state != READY)
@@ -856,7 +838,6 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
if (mdc800->in_count == 8)
{
int answersize;
- long timeout;
if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
{
@@ -876,14 +857,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
up (&mdc800->io_lock);
return -EIO;
}
- add_wait_queue(&mdc800->write_wait, &wait);
- timeout = TO_WRITE_GET_READY*HZ/1000;
- while (!mdc800->written && timeout)
- {
- set_current_state(TASK_UNINTERRUPTIBLE);
- timeout = schedule_timeout (timeout);
- }
- remove_wait_queue(&mdc800->write_wait, &wait);
+ wait_event_timeout(mdc800->write_wait, mdc800->written, TO_WRITE_GET_READY*HZ/1000);
mdc800->written = 0;
if (mdc800->state == WORKING)
{
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
index a2a037fe791f..c912f56ff421 100644
--- a/drivers/usb/input/aiptek.c
+++ b/drivers/usb/input/aiptek.c
@@ -297,8 +297,6 @@ struct aiptek_features {
int firmwareCode; /* prom/eeprom version */
char usbPath[64 + 1]; /* device's physical usb path */
char inputPath[64 + 1]; /* input device path */
- char manuName[64 + 1]; /* manufacturer name */
- char prodName[64 + 1]; /* product name */
};
struct aiptek_settings {
@@ -855,7 +853,7 @@ aiptek_set_report(struct aiptek *aiptek,
USB_REQ_SET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE |
USB_DIR_OUT, (report_type << 8) + report_id,
- aiptek->ifnum, buffer, size, 5 * HZ);
+ aiptek->ifnum, buffer, size, 5000);
}
static int
@@ -868,7 +866,7 @@ aiptek_get_report(struct aiptek *aiptek,
USB_REQ_GET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE |
USB_DIR_IN, (report_type << 8) + report_id,
- aiptek->ifnum, buffer, size, 5 * HZ);
+ aiptek->ifnum, buffer, size, 5000);
}
/***********************************************************************
@@ -1089,7 +1087,7 @@ static ssize_t show_tabletManufacturer(struct device *dev, char *buf)
if (aiptek == NULL)
return 0;
- retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->features.manuName);
+ retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->manufacturer);
return retval;
}
@@ -1106,7 +1104,7 @@ static ssize_t show_tabletProduct(struct device *dev, char *buf)
if (aiptek == NULL)
return 0;
- retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->features.prodName);
+ retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->product);
return retval;
}
@@ -2166,19 +2164,6 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
*/
input_register_device(&aiptek->inputdev);
- /* Go and decode the USB representation of the tablet's manufacturer
- * name and product name. They only change once every hotplug event,
- * which is why we put it here instead of in the sysfs interface.
- */
- usb_string(usbdev,
- usbdev->descriptor.iManufacturer,
- aiptek->features.manuName,
- sizeof(aiptek->features.manuName));
- usb_string(usbdev,
- usbdev->descriptor.iProduct,
- aiptek->features.prodName,
- sizeof(aiptek->features.prodName));
-
/* We now will look for the evdev device which is mapped to
* the tablet. The partial name is kept in the link list of
* input_handles associated with this input device.
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
index 3f5414446485..3f1c4a9a4a80 100644
--- a/drivers/usb/input/ati_remote.c
+++ b/drivers/usb/input/ati_remote.c
@@ -94,6 +94,7 @@
#include <linux/moduleparam.h>
#include <linux/input.h>
#include <linux/usb.h>
+#include <linux/wait.h>
/*
* Module and Version Information, Module Parameters
@@ -396,8 +397,6 @@ static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
*/
static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
{
- DECLARE_WAITQUEUE(wait, current);
- int timeout = HZ; /* 1 second */
int retval = 0;
/* Set up out_urb */
@@ -415,18 +414,10 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigne
return retval;
}
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&ati_remote->wait, &wait);
-
- while (timeout && (ati_remote->out_urb->status == -EINPROGRESS)
- && !(ati_remote->send_flags & SEND_FLAG_COMPLETE)) {
- set_current_state(TASK_INTERRUPTIBLE);
- timeout = schedule_timeout(timeout);
- rmb();
- }
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&ati_remote->wait, &wait);
+ wait_event_timeout(ati_remote->wait,
+ ((ati_remote->out_urb->status != -EINPROGRESS) ||
+ (ati_remote->send_flags & SEND_FLAG_COMPLETE)),
+ HZ);
usb_kill_urb(ati_remote->out_urb);
return retval;
@@ -727,7 +718,6 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
struct usb_host_interface *iface_host;
int retval = -ENOMEM;
char path[64];
- char *buf = NULL;
/* Allocate and clear an ati_remote struct */
if (!(ati_remote = kmalloc(sizeof (struct ati_remote), GFP_KERNEL)))
@@ -761,8 +751,6 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
retval = -ENODEV;
goto error;
}
- if (!(buf = kmalloc(NAME_BUFSIZE, GFP_KERNEL)))
- goto error;
/* Allocate URB buffers, URBs */
ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC,
@@ -785,14 +773,11 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
usb_make_path(udev, path, NAME_BUFSIZE);
sprintf(ati_remote->phys, "%s/input%d", path, ATI_INPUTNUM);
- if (udev->descriptor.iManufacturer &&
- (usb_string(udev, udev->descriptor.iManufacturer, buf,
- NAME_BUFSIZE) > 0))
- strcat(ati_remote->name, buf);
+ if (udev->manufacturer)
+ strcat(ati_remote->name, udev->manufacturer);
- if (udev->descriptor.iProduct &&
- (usb_string(udev, udev->descriptor.iProduct, buf, NAME_BUFSIZE) > 0))
- sprintf(ati_remote->name, "%s %s", ati_remote->name, buf);
+ if (udev->product)
+ sprintf(ati_remote->name, "%s %s", ati_remote->name, udev->product);
if (!strlen(ati_remote->name))
sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)",
@@ -815,9 +800,6 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
ati_remote->present = 1;
error:
- if (buf)
- kfree(buf);
-
if (retval)
ati_remote_delete(ati_remote);
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 2280d13986e6..0f04d286d6b7 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -24,6 +24,7 @@
#include <asm/unaligned.h>
#include <asm/byteorder.h>
#include <linux/input.h>
+#include <linux/wait.h>
#undef DEBUG
#undef DEBUG_DATA
@@ -1268,22 +1269,9 @@ void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsign
int hid_wait_io(struct hid_device *hid)
{
- DECLARE_WAITQUEUE(wait, current);
- int timeout = 10*HZ;
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&hid->wait, &wait);
-
- while (timeout && (test_bit(HID_CTRL_RUNNING, &hid->iofl) ||
- test_bit(HID_OUT_RUNNING, &hid->iofl))) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- timeout = schedule_timeout(timeout);
- }
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&hid->wait, &wait);
-
- if (!timeout) {
+ if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &hid->iofl) &&
+ !test_bit(HID_OUT_RUNNING, &hid->iofl)),
+ 10*HZ)) {
dbg("timeout waiting for ctrl or out queue to clear");
return -1;
}
@@ -1301,7 +1289,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
do {
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
- (type << 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT);
+ (type << 8), ifnum, buf, size, USB_CTRL_GET_TIMEOUT);
retries--;
} while (result < size && retries);
return result;
@@ -1352,7 +1340,7 @@ void hid_init_reports(struct hid_device *hid)
*/
usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (1 << 8),
- hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+ hid->ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
report_enum = hid->report_enum + HID_INPUT_REPORT;
list = report_enum->report_list.next;
@@ -1394,7 +1382,7 @@ void hid_init_reports(struct hid_device *hid)
report = (struct hid_report *) list;
usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id,
- hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+ hid->ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
list = list->next;
}
}
@@ -1739,12 +1727,12 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if (!(buf = kmalloc(64, GFP_KERNEL)))
goto fail;
- if (usb_string(dev, dev->descriptor.iManufacturer, buf, 64) > 0) {
- strcat(hid->name, buf);
- if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0)
- snprintf(hid->name, 64, "%s %s", hid->name, buf);
- } else if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0) {
- snprintf(hid->name, 128, "%s", buf);
+ if (dev->manufacturer) {
+ strcat(hid->name, dev->manufacturer);
+ if (dev->product)
+ snprintf(hid->name, 64, "%s %s", hid->name, dev->product);
+ } else if (dev->product) {
+ snprintf(hid->name, 128, "%s", dev->product);
} else
snprintf(hid->name, 128, "%04x:%04x",
le16_to_cpu(dev->descriptor.idVendor),
diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
index f0e75c939a48..af6f77bdf6ac 100644
--- a/drivers/usb/input/mtouchusb.c
+++ b/drivers/usb/input/mtouchusb.c
@@ -187,7 +187,6 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev (intf);
char path[64];
- char *buf;
int nRet;
dbg("%s - called", __FUNCTION__);
@@ -242,24 +241,15 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
- if (!(buf = kmalloc(63, GFP_KERNEL))) {
- kfree(mtouch);
- return -ENOMEM;
- }
-
- if (udev->descriptor.iManufacturer &&
- usb_string(udev, udev->descriptor.iManufacturer, buf, 63) > 0)
- strcat(mtouch->name, buf);
- if (udev->descriptor.iProduct &&
- usb_string(udev, udev->descriptor.iProduct, buf, 63) > 0)
- sprintf(mtouch->name, "%s %s", mtouch->name, buf);
+ if (udev->manufacturer)
+ strcat(mtouch->name, udev->manufacturer);
+ if (udev->product)
+ sprintf(mtouch->name, "%s %s", mtouch->name, udev->product);
if (!strlen(mtouch->name))
sprintf(mtouch->name, "USB Touchscreen %04x:%04x",
mtouch->input.id.vendor, mtouch->input.id.product);
- kfree(buf);
-
nRet = usb_control_msg(mtouch->udev,
usb_rcvctrlpipe(udev, 0),
MTOUCHUSB_RESET,
@@ -268,7 +258,7 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
0,
NULL,
0,
- HZ * USB_CTRL_SET_TIMEOUT);
+ USB_CTRL_SET_TIMEOUT);
dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
__FUNCTION__, nRet);
@@ -302,7 +292,7 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
1,
NULL,
0,
- HZ * USB_CTRL_SET_TIMEOUT);
+ USB_CTRL_SET_TIMEOUT);
dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
__FUNCTION__, nRet);
diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
index 6e77750b44a4..3a03c454a1df 100644
--- a/drivers/usb/input/powermate.c
+++ b/drivers/usb/input/powermate.c
@@ -320,7 +320,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, interface->desc.bInterfaceNumber, NULL, 0,
- HZ * USB_CTRL_SET_TIMEOUT);
+ USB_CTRL_SET_TIMEOUT);
if (!(pm = kmalloc(sizeof(struct powermate_device), GFP_KERNEL)))
return -ENOMEM;
diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c
index 734e1114aafb..a71f1bbd0a17 100644
--- a/drivers/usb/input/touchkitusb.c
+++ b/drivers/usb/input/touchkitusb.c
@@ -184,7 +184,6 @@ static int touchkit_probe(struct usb_interface *intf,
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev(intf);
char path[64];
- char *buf;
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
@@ -230,25 +229,15 @@ static int touchkit_probe(struct usb_interface *intf,
touchkit->input.absfuzz[ABS_Y] = TOUCHKIT_YC_FUZZ;
touchkit->input.absflat[ABS_Y] = TOUCHKIT_YC_FLAT;
- buf = kmalloc(63, GFP_KERNEL);
- if (!buf) {
- ret = -ENOMEM;
- goto out_free_buffers;
- }
-
- if (udev->descriptor.iManufacturer &&
- usb_string(udev, udev->descriptor.iManufacturer, buf, 63) > 0)
- strcat(touchkit->name, buf);
- if (udev->descriptor.iProduct &&
- usb_string(udev, udev->descriptor.iProduct, buf, 63) > 0)
- sprintf(touchkit->name, "%s %s", touchkit->name, buf);
+ if (udev->manufacturer)
+ strcat(touchkit->name, udev->manufacturer);
+ if (udev->product)
+ sprintf(touchkit->name, "%s %s", touchkit->name, udev->product);
if (!strlen(touchkit->name))
sprintf(touchkit->name, "USB Touchscreen %04x:%04x",
touchkit->input.id.vendor, touchkit->input.id.product);
- kfree(buf);
-
touchkit->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!touchkit->irq) {
dbg("%s - usb_alloc_urb failed: touchkit->irq", __FUNCTION__);
diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
index 148d81e03480..01514b0551b8 100644
--- a/drivers/usb/input/usbkbd.c
+++ b/drivers/usb/input/usbkbd.c
@@ -238,7 +238,6 @@ static int usb_kbd_probe(struct usb_interface *iface,
struct usb_kbd *kbd;
int i, pipe, maxp;
char path[64];
- char *buf;
interface = iface->cur_altsetting;
@@ -301,26 +300,15 @@ static int usb_kbd_probe(struct usb_interface *iface,
kbd->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
kbd->dev.dev = &iface->dev;
- if (!(buf = kmalloc(63, GFP_KERNEL))) {
- usb_free_urb(kbd->irq);
- usb_kbd_free_mem(dev, kbd);
- kfree(kbd);
- return -ENOMEM;
- }
-
- if (dev->descriptor.iManufacturer &&
- usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0)
- strcat(kbd->name, buf);
- if (dev->descriptor.iProduct &&
- usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
- sprintf(kbd->name, "%s %s", kbd->name, buf);
+ if (dev->manufacturer)
+ strcat(kbd->name, dev->manufacturer);
+ if (dev->product)
+ sprintf(kbd->name, "%s %s", kbd->name, dev->product);
if (!strlen(kbd->name))
sprintf(kbd->name, "USB HIDBP Keyboard %04x:%04x",
kbd->dev.id.vendor, kbd->dev.id.product);
- kfree(buf);
-
usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
(void *) kbd->cr, kbd->leds, 1,
usb_kbd_led, kbd);
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
index 54b247cfd312..01155bbddd43 100644
--- a/drivers/usb/input/usbmouse.c
+++ b/drivers/usb/input/usbmouse.c
@@ -129,7 +129,6 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_
struct usb_mouse *mouse;
int pipe, maxp;
char path[64];
- char *buf;
interface = intf->cur_altsetting;
@@ -185,25 +184,15 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_
mouse->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
mouse->dev.dev = &intf->dev;
- if (!(buf = kmalloc(63, GFP_KERNEL))) {
- usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
- kfree(mouse);
- return -ENOMEM;
- }
-
- if (dev->descriptor.iManufacturer &&
- usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0)
- strcat(mouse->name, buf);
- if (dev->descriptor.iProduct &&
- usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
- sprintf(mouse->name, "%s %s", mouse->name, buf);
+ if (dev->manufacturer)
+ strcat(mouse->name, dev->manufacturer);
+ if (dev->product)
+ sprintf(mouse->name, "%s %s", mouse->name, dev->product);
if (!strlen(mouse->name))
sprintf(mouse->name, "USB HIDBP Mouse %04x:%04x",
mouse->dev.id.vendor, mouse->dev.id.product);
- kfree(buf);
-
usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
(maxp > 8 ? 8 : maxp),
usb_mouse_irq, mouse, endpoint->bInterval);
diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
index f2f34392f855..8dd82922f6e4 100644
--- a/drivers/usb/input/wacom.c
+++ b/drivers/usb/input/wacom.c
@@ -115,7 +115,7 @@ static int usb_set_report(struct usb_interface *intf, unsigned char type,
usb_sndctrlpipe(interface_to_usbdev(intf), 0),
USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
- buf, size, HZ);
+ buf, size, 1000);
}
static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
diff --git a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c
index 64eb7ca72836..61994e7322da 100644
--- a/drivers/usb/media/ibmcam.c
+++ b/drivers/usb/media/ibmcam.c
@@ -1137,7 +1137,7 @@ static int ibmcam_veio(
index,
cp,
sizeof(cp),
- HZ);
+ 1000);
#if 0
info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
"(req=$%02x val=$%04x ind=$%04x)",
@@ -1154,7 +1154,7 @@ static int ibmcam_veio(
index,
NULL,
0,
- HZ);
+ 1000);
}
if (i < 0) {
err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
diff --git a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c
index 7ff1468f5977..08521a2b4f3d 100644
--- a/drivers/usb/media/konicawc.c
+++ b/drivers/usb/media/konicawc.c
@@ -133,7 +133,7 @@ static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16
{
int retval = usb_control_msg(uvd->dev,
dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
- request, 0x40 | dir, value, index, buf, len, HZ);
+ request, 0x40 | dir, value, index, buf, len, 1000);
return retval < 0 ? retval : 0;
}
diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c
index 88c3628dc2f5..0fd7ffed3a98 100644
--- a/drivers/usb/media/ov511.c
+++ b/drivers/usb/media/ov511.c
@@ -383,7 +383,7 @@ reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
usb_sndctrlpipe(ov->dev, 0),
(ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, (__u16)reg, &ov->cbuf[0], 1, HZ);
+ 0, (__u16)reg, &ov->cbuf[0], 1, 1000);
up(&ov->cbuf_lock);
if (rc < 0)
@@ -404,7 +404,7 @@ reg_r(struct usb_ov511 *ov, unsigned char reg)
usb_rcvctrlpipe(ov->dev, 0),
(ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, (__u16)reg, &ov->cbuf[0], 1, HZ);
+ 0, (__u16)reg, &ov->cbuf[0], 1, 1000);
if (rc < 0) {
err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
@@ -464,7 +464,7 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
usb_sndctrlpipe(ov->dev, 0),
1 /* REG_IO */,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, (__u16)reg, ov->cbuf, n, HZ);
+ 0, (__u16)reg, ov->cbuf, n, 1000);
up(&ov->cbuf_lock);
if (rc < 0)
diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
index 6761806bc86f..685bdae5cb62 100644
--- a/drivers/usb/media/se401.c
+++ b/drivers/usb/media/se401.c
@@ -122,7 +122,7 @@ static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
0,
cp,
size,
- HZ
+ 1000
);
}
@@ -142,7 +142,7 @@ static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
selector,
NULL,
0,
- HZ
+ 1000
);
}
@@ -162,7 +162,7 @@ static unsigned short se401_get_feature(struct usb_se401 *se401,
selector,
cp,
2,
- HZ
+ 1000
);
return cp[0]+cp[1]*256;
}
diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h
index 795ebc641377..8b8a4c8743f8 100644
--- a/drivers/usb/media/sn9c102.h
+++ b/drivers/usb/media/sn9c102.h
@@ -48,16 +48,16 @@
#define SN9C102_ISO_PACKETS 7
#define SN9C102_ALTERNATE_SETTING 8
#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
-#define SN9C102_CTRL_TIMEOUT msecs_to_jiffies(300)
+#define SN9C102_CTRL_TIMEOUT 300
/*****************************************************************************/
#define SN9C102_MODULE_NAME "V4L2 driver for SN9C10x PC Camera Controllers"
-#define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia"
+#define SN9C102_MODULE_AUTHOR "(C) 2004-2005 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL"
-#define SN9C102_MODULE_VERSION "1:1.22"
-#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 22)
+#define SN9C102_MODULE_VERSION "1:1.24"
+#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 24)
enum sn9c102_bridge {
BRIDGE_SN9C101 = 0x01,
diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c
index e509d2ffa0f6..898401cf7dcc 100644
--- a/drivers/usb/media/sn9c102_core.c
+++ b/drivers/usb/media/sn9c102_core.c
@@ -164,8 +164,8 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
struct v4l2_rect* r = &(cam->sensor->cropcap.bounds);
const size_t imagesize = cam->module_param.force_munmap ||
io == IO_READ ?
- (p->width * p->height * p->priv)/8 :
- (r->width * r->height * p->priv)/8;
+ (p->width * p->height * p->priv) / 8 :
+ (r->width * r->height * p->priv) / 8;
void* buff = NULL;
u32 i;
@@ -499,6 +499,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
{
struct sn9c102_device* cam = urb->context;
struct sn9c102_frame_t** f;
+ size_t imagesize;
unsigned long lock_flags;
u8 i;
int err = 0;
@@ -516,8 +517,13 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
wake_up_interruptible(&cam->wait_stream);
}
- if ((cam->state & DEV_DISCONNECTED)||(cam->state & DEV_MISCONFIGURED))
+ if (cam->state & DEV_DISCONNECTED)
+ return;
+
+ if (cam->state & DEV_MISCONFIGURED) {
+ wake_up_interruptible(&cam->wait_frame);
return;
+ }
if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
goto resubmit_urb;
@@ -526,6 +532,10 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
(*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
frame);
+ imagesize = (cam->sensor->pix_format.width *
+ cam->sensor->pix_format.height *
+ cam->sensor->pix_format.priv) / 8;
+
for (i = 0; i < urb->number_of_packets; i++) {
unsigned int img, len, status;
void *pos, *sof, *eof;
@@ -560,11 +570,10 @@ end_of_frame:
if (eof)
img = (eof > pos) ? eof - pos - 1 : 0;
- if ((*f)->buf.bytesused+img>(*f)->buf.length) {
+ if ((*f)->buf.bytesused+img > imagesize) {
u32 b = (*f)->buf.bytesused + img -
- (*f)->buf.length;
- img = (*f)->buf.length -
- (*f)->buf.bytesused;
+ imagesize;
+ img = imagesize - (*f)->buf.bytesused;
DBG(3, "Expected EOF not found: "
"video frame cut")
if (eof)
@@ -580,7 +589,7 @@ end_of_frame:
(*f)->buf.bytesused += img;
- if ((*f)->buf.bytesused == (*f)->buf.length ||
+ if ((*f)->buf.bytesused == imagesize ||
(cam->sensor->pix_format.pixelformat ==
V4L2_PIX_FMT_SN9C10X && eof)) {
u32 b = (*f)->buf.bytesused;
@@ -1558,7 +1567,8 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
err = wait_event_interruptible
( cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
- (cam->state & DEV_DISCONNECTED) );
+ (cam->state & DEV_DISCONNECTED) ||
+ (cam->state & DEV_MISCONFIGURED) );
if (err) {
up(&cam->fileop_sem);
return err;
@@ -1567,6 +1577,10 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
up(&cam->fileop_sem);
return -ENODEV;
}
+ if (cam->state & DEV_MISCONFIGURED) {
+ up(&cam->fileop_sem);
+ return -EIO;
+ }
}
f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);
@@ -1615,7 +1629,8 @@ static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
}
if (cam->io == IO_NONE) {
- if (!sn9c102_request_buffers(cam, 2, IO_READ)) {
+ if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
+ IO_READ)) {
DBG(1, "poll() failed, not enough memory")
goto error;
}
@@ -1729,7 +1744,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
}
-static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
+static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
unsigned int cmd, void __user * arg)
{
struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
@@ -1970,7 +1985,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
return -EFAULT;
}
- if (cam->module_param.force_munmap)
+ if (cam->module_param.force_munmap || cam->io == IO_READ)
sn9c102_release_buffers(cam);
err = sn9c102_set_crop(cam, rect);
@@ -1990,7 +2005,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
s->pix_format.height = rect->height/scale;
memcpy(&(s->_rect), rect, sizeof(*rect));
- if (cam->module_param.force_munmap &&
+ if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
nbuffers != sn9c102_request_buffers(cam, nbuffers,
cam->io)) {
cam->state |= DEV_MISCONFIGURED;
@@ -2146,7 +2161,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
return -EFAULT;
}
- if (cam->module_param.force_munmap)
+ if (cam->module_param.force_munmap || cam->io == IO_READ)
sn9c102_release_buffers(cam);
err += sn9c102_set_pix_format(cam, pix);
@@ -2168,7 +2183,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
memcpy(pfmt, pix, sizeof(*pix));
memcpy(&(s->_rect), &rect, sizeof(rect));
- if (cam->module_param.force_munmap &&
+ if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
nbuffers != sn9c102_request_buffers(cam, nbuffers,
cam->io)) {
cam->state |= DEV_MISCONFIGURED;
@@ -2346,11 +2361,14 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
err = wait_event_interruptible
( cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
- (cam->state & DEV_DISCONNECTED) );
+ (cam->state & DEV_DISCONNECTED) ||
+ (cam->state & DEV_MISCONFIGURED) );
if (err)
return err;
if (cam->state & DEV_DISCONNECTED)
return -ENODEV;
+ if (cam->state & DEV_MISCONFIGURED)
+ return -EIO;
}
spin_lock_irqsave(&cam->queue_lock, lock_flags);
@@ -2495,7 +2513,7 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
return -EIO;
}
- err = sn9c102_v4l2_ioctl(inode, filp, cmd, (void __user *)arg);
+ err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
up(&cam->fileop_sem);
diff --git a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c
index fec1f09615f4..75ff755224df 100644
--- a/drivers/usb/media/ultracam.c
+++ b/drivers/usb/media/ultracam.c
@@ -155,7 +155,7 @@ static int ultracam_veio(
index,
cp,
sizeof(cp),
- HZ);
+ 1000);
#if 1
info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
"(req=$%02x val=$%04x ind=$%04x)",
@@ -172,7 +172,7 @@ static int ultracam_veio(
index,
NULL,
0,
- HZ);
+ 1000);
}
if (i < 0) {
err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
index 908ff5b7a9d6..4a5857c53f11 100644
--- a/drivers/usb/media/vicam.c
+++ b/drivers/usb/media/vicam.c
@@ -441,7 +441,7 @@ static int __send_control_msg(struct vicam_camera *cam,
request,
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_DEVICE, value, index,
- cp, size, HZ);
+ cp, size, 1000);
status = min(status, 0);
@@ -977,7 +977,7 @@ read_frame(struct vicam_camera *cam, int framenum)
n = usb_bulk_msg(cam->udev,
usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
cam->raw_image,
- 512 * 242 + 128, &actual_length, HZ*10);
+ 512 * 242 + 128, &actual_length, 10000);
if (n < 0) {
printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
diff --git a/drivers/usb/media/w9968cf.h b/drivers/usb/media/w9968cf.h
index 988125ab3071..8acbfe205bc7 100644
--- a/drivers/usb/media/w9968cf.h
+++ b/drivers/usb/media/w9968cf.h
@@ -65,7 +65,7 @@ static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575,
#define W9968CF_PACKET_SIZE 1023 /* according to wMaxPacketSizes[] */
#define W9968CF_MIN_PACKET_SIZE 63 /* minimum value */
#define W9968CF_ISO_PACKETS 5 /* n.of packets for isochronous transfers */
-#define W9968CF_USB_CTRL_TIMEOUT HZ /* timeout for usb control commands */
+#define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */
#define W9968CF_URBS 2 /* n. of scheduled URBs for ISO transfer */
#define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index abd5ac02be48..3a896954b3a9 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -137,6 +137,8 @@ config USB_IDMOUSE
See also <http://www.fs.tum.de/~echtler/idmouse/>.
+source "drivers/usb/misc/sisusbvga/Kconfig"
+
config USB_TEST
tristate "USB testing driver (DEVELOPMENT)"
depends on USB && USB_DEVICEFS && EXPERIMENTAL
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 566e26ae6480..4a3814cbd48d 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -16,3 +16,5 @@ obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o
obj-$(CONFIG_USB_RIO500) += rio500.o
obj-$(CONFIG_USB_TEST) += usbtest.o
obj-$(CONFIG_USB_USS720) += uss720.o
+
+obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ \ No newline at end of file
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index d656592c25dd..a530bb976e43 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -29,6 +29,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/wait.h>
#undef DEBUG /* include debug macros until it's done */
#include <linux/usb.h>
@@ -605,7 +606,6 @@ static void auerchain_blocking_completion (struct urb *urb, struct pt_regs *regs
/* Starts chained urb and waits for completion or timeout */
static int auerchain_start_wait_urb (pauerchain_t acp, struct urb *urb, int timeout, int* actual_length)
{
- DECLARE_WAITQUEUE (wait, current);
auerchain_chs_t chs;
int status;
@@ -613,26 +613,13 @@ static int auerchain_start_wait_urb (pauerchain_t acp, struct urb *urb, int time
init_waitqueue_head (&chs.wqh);
chs.done = 0;
- set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&chs.wqh, &wait);
urb->context = &chs;
status = auerchain_submit_urb (acp, urb);
- if (status) {
+ if (status)
/* something went wrong */
- set_current_state (TASK_RUNNING);
- remove_wait_queue (&chs.wqh, &wait);
return status;
- }
-
- while (timeout && !chs.done)
- {
- timeout = schedule_timeout (timeout);
- set_current_state(TASK_UNINTERRUPTIBLE);
- rmb();
- }
- set_current_state (TASK_RUNNING);
- remove_wait_queue (&chs.wqh, &wait);
+ timeout = wait_event_timeout(chs.wqh, chs.done, timeout);
if (!timeout && !chs.done) {
if (urb->status != -EINPROGRESS) { /* No callback?!! */
@@ -2009,7 +1996,7 @@ static int auerswald_probe (struct usb_interface *intf,
AUDI_MBCTRANS, /* USB message index value */
pbuf, /* pointer to the receive buffer */
2, /* length of the buffer */
- HZ * 2); /* time to wait for the message to complete before timing out */
+ 2000); /* time to wait for the message to complete before timing out */
if (ret == 2) {
cp->maxControlLength = le16_to_cpup(pbuf);
kfree(pbuf);
diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c
index 4d27eab24448..626e2b05f719 100644
--- a/drivers/usb/misc/cytherm.c
+++ b/drivers/usb/misc/cytherm.c
@@ -77,7 +77,7 @@ static int vendor_command(struct usb_device *dev, unsigned char request,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
value,
index, buf, size,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
}
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 04f091244e3a..ce030d1f1c1f 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -124,28 +124,28 @@ static int idmouse_create_image(struct usb_idmouse *dev)
means init..
*/
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x21, 0x42, 0x0001, 0x0002, NULL, 0, HZ);
+ 0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
if (result < 0)
return result;
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x20, 0x42, 0x0001, 0x0002, NULL, 0, HZ);
+ 0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
if (result < 0)
return result;
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x22, 0x42, 0x0000, 0x0002, NULL, 0, HZ);
+ 0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
if (result < 0)
return result;
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x21, 0x42, 0x0001, 0x0002, NULL, 0, HZ);
+ 0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
if (result < 0)
return result;
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x20, 0x42, 0x0001, 0x0002, NULL, 0, HZ);
+ 0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
if (result < 0)
return result;
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x20, 0x42, 0x0000, 0x0002, NULL, 0, HZ);
+ 0x20, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
if (result < 0)
return result;
@@ -154,7 +154,7 @@ static int idmouse_create_image(struct usb_idmouse *dev)
result = usb_bulk_msg (dev->udev,
usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer + bytes_read,
- dev->bulk_in_size, &bulk_read, HZ * 5);
+ dev->bulk_in_size, &bulk_read, 5000);
if (result < 0)
return result;
if (signal_pending(current))
@@ -164,7 +164,7 @@ static int idmouse_create_image(struct usb_idmouse *dev)
/* reset the device */
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x22, 0x42, 0x0000, 0x0002, NULL, 0, HZ);
+ 0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
if (result < 0)
return result;
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index edf3df586a8c..dd4580cb57e0 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -391,7 +391,7 @@ static int tower_open (struct inode *inode, struct file *file)
0,
&reset_reply,
sizeof(reset_reply),
- HZ);
+ 1000);
if (result < 0) {
err("LEGO USB Tower reset control request failed");
retval = result;
@@ -972,7 +972,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
0,
&get_version_reply,
sizeof(get_version_reply),
- HZ);
+ 1000);
if (result < 0) {
err("LEGO USB Tower get version control request failed");
retval = result;
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
index ace44a748573..ddbf8e992368 100644
--- a/drivers/usb/misc/phidgetkit.c
+++ b/drivers/usb/misc/phidgetkit.c
@@ -103,14 +103,15 @@ static int change_outputs(struct phidget_interfacekit *kit, int output_num, int
}
}
- dev_dbg(&kit->udev->dev, "data: %02x %02x\n", buffer[0], buffer[1]);
+ dev_dbg(&kit->udev->dev, "sending data: %02x\n", buffer[0]);
retval = usb_control_msg(kit->udev,
usb_sndctrlpipe(kit->udev, 0),
- 0x09, 0x21, 0x0200, 0x0000, buffer, 4, 2 * HZ);
+ 0x09, 0x21, 0x0200, 0x0000, buffer, 4, 2000);
if (retval != 4)
- dev_err(&kit->udev->dev, "retval = %d\n", retval);
+ dev_err(&kit->udev->dev, "usb_control_msg returned %d\n",
+ retval);
kfree(buffer);
return retval < 0 ? retval : 0;
@@ -158,7 +159,7 @@ static int change_string(struct phidget_interfacekit *kit, const char *display,
retval = usb_control_msg(kit->udev,
usb_sndctrlpipe(kit->udev, 0),
- 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2 * HZ);
+ 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000);
if (retval < 0)
goto exit;
}
@@ -210,7 +211,7 @@ static ssize_t set_backlight(struct device *dev, const char *buf, size_t count)
retval = usb_control_msg(kit->udev,
usb_sndctrlpipe(kit->udev, 0),
- 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2 * HZ);
+ 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000);
if (retval < 0)
goto exit;
@@ -328,7 +329,7 @@ static ssize_t show_output##value(struct device *dev, char *buf) \
struct usb_interface *intf = to_usb_interface(dev); \
struct phidget_interfacekit *kit = usb_get_intfdata(intf); \
\
- return sprintf(buf, "%d\n", kit->outputs[value - 1 ]); \
+ return sprintf(buf, "%d\n", kit->outputs[value - 1]); \
} \
static DEVICE_ATTR(output##value, S_IWUGO | S_IRUGO, \
show_output##value, set_output##value);
@@ -440,11 +441,13 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
return -EIO;
}
- if (ifkit->outputs == 8) {
+ if (ifkit->outputs >= 4) {
device_create_file(&intf->dev, &dev_attr_output1);
device_create_file(&intf->dev, &dev_attr_output2);
device_create_file(&intf->dev, &dev_attr_output3);
device_create_file(&intf->dev, &dev_attr_output4);
+ }
+ if (ifkit->outputs == 8) {
device_create_file(&intf->dev, &dev_attr_output5);
device_create_file(&intf->dev, &dev_attr_output6);
device_create_file(&intf->dev, &dev_attr_output7);
@@ -483,7 +486,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
device_create_file(&intf->dev, &dev_attr_lcd);
dev_info(&intf->dev, "USB PhidgetInterfaceKit %d/%d/%d attached\n",
- ifkit->inputs, ifkit->outputs, ifkit->sensors);
+ ifkit->sensors, ifkit->inputs, ifkit->outputs);
return 0;
}
@@ -497,15 +500,17 @@ static void interfacekit_disconnect(struct usb_interface *interface)
if (!kit)
return;
- if (kit->ifkit->outputs == MAX_INTERFACES) {
+ if (kit->ifkit->outputs >= 4) {
device_remove_file(&interface->dev, &dev_attr_output1);
device_remove_file(&interface->dev, &dev_attr_output2);
device_remove_file(&interface->dev, &dev_attr_output3);
device_remove_file(&interface->dev, &dev_attr_output4);
+ }
+ if (kit->ifkit->outputs == 8) {
device_remove_file(&interface->dev, &dev_attr_output5);
device_remove_file(&interface->dev, &dev_attr_output6);
device_remove_file(&interface->dev, &dev_attr_output7);
- device_remove_file(&interface->dev, &dev_attr_output7);
+ device_remove_file(&interface->dev, &dev_attr_output8);
}
if (kit->ifkit->inputs >= 4) {
@@ -536,10 +541,10 @@ static void interfacekit_disconnect(struct usb_interface *interface)
device_remove_file(&interface->dev, &dev_attr_sensor8);
}
if (kit->ifkit->has_lcd)
- device_create_file(&interface->dev, &dev_attr_lcd);
+ device_remove_file(&interface->dev, &dev_attr_lcd);
dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n",
- kit->ifkit->inputs, kit->ifkit->outputs, kit->ifkit->sensors);
+ kit->ifkit->sensors, kit->ifkit->inputs, kit->ifkit->outputs);
usb_kill_urb(kit->irq);
usb_free_urb(kit->irq);
diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c
index 8cca7e7474a9..4bd291502a3c 100644
--- a/drivers/usb/misc/phidgetservo.c
+++ b/drivers/usb/misc/phidgetservo.c
@@ -148,7 +148,7 @@ change_position_v30(struct phidget_servo *servo, int servo_no, int degrees,
retval = usb_control_msg(servo->udev,
usb_sndctrlpipe(servo->udev, 0),
- 0x09, 0x21, 0x0200, 0x0000, buffer, 6, 2 * HZ);
+ 0x09, 0x21, 0x0200, 0x0000, buffer, 6, 2000);
kfree(buffer);
@@ -199,7 +199,7 @@ change_position_v20(struct phidget_servo *servo, int servo_no, int degrees,
retval = usb_control_msg(servo->udev,
usb_sndctrlpipe(servo->udev, 0),
- 0x09, 0x21, 0x0200, 0x0000, buffer, 2, 2 * HZ);
+ 0x09, 0x21, 0x0200, 0x0000, buffer, 2, 2000);
kfree(buffer);
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 6a6e3de91a0a..9a5cd6facfa7 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -166,7 +166,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
rio_cmd.value,
rio_cmd.index, buffer,
rio_cmd.length,
- rio_cmd.timeout);
+ jiffies_to_msecs(rio_cmd.timeout));
if (result == -ETIMEDOUT)
retries--;
else if (result < 0) {
@@ -233,7 +233,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
rio_cmd.value,
rio_cmd.index, buffer,
rio_cmd.length,
- rio_cmd.timeout);
+ jiffies_to_msecs(rio_cmd.timeout));
if (result == -ETIMEDOUT)
retries--;
else if (result < 0) {
@@ -309,7 +309,7 @@ write_rio(struct file *file, const char __user *buffer,
result = usb_bulk_msg(rio->rio_dev,
usb_sndbulkpipe(rio->rio_dev, 2),
- obuf, thistime, &partial, 5 * HZ);
+ obuf, thistime, &partial, 5000);
dbg("write stats: result:%d thistime:%lu partial:%u",
result, thistime, partial);
@@ -386,7 +386,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
result = usb_bulk_msg(rio->rio_dev,
usb_rcvbulkpipe(rio->rio_dev, 1),
ibuf, this_read, &partial,
- (int) (HZ * 8));
+ 8000);
dbg(KERN_DEBUG "read stats: result:%d this_read:%u partial:%u",
result, this_read, partial);
diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig
new file mode 100644
index 000000000000..3957e144caf7
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/Kconfig
@@ -0,0 +1,14 @@
+
+config USB_SISUSBVGA
+ tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)"
+ depends on USB && USB_EHCI_HCD
+ ---help---
+ Say Y here if you intend to attach a USB2VGA dongle based on a
+ Net2280 and a SiS315 chip.
+
+ Note that this device requires a USB 2.0 host controller. It will not
+ work with USB 1.x controllers.
+
+ To compile this driver as a module, choose M here: the module will be
+ called sisusb. If unsure, say N.
+
diff --git a/drivers/usb/misc/sisusbvga/Makefile b/drivers/usb/misc/sisusbvga/Makefile
new file mode 100644
index 000000000000..76f1643ceaf8
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the sisusb driver (if driver is inside kernel tree).
+#
+
+obj-$(CONFIG_USB_SISUSBVGA) += sisusb.o
+
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
new file mode 100644
index 000000000000..718136a6c9ff
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -0,0 +1,3144 @@
+/*
+ * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
+ *
+ * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, this code is licensed under the
+ * terms of the GPL v2.
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * * notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * * notice, this list of conditions and the following disclaimer in the
+ * * documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * * derived from this software without specific psisusbr written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+
+#include "sisusb.h"
+
+#define SISUSB_DONTSYNC
+
+/* Forward declarations / clean-up routines */
+
+static struct usb_driver sisusb_driver;
+
+static DECLARE_MUTEX(disconnect_sem);
+
+static void
+sisusb_free_buffers(struct sisusb_usb_data *sisusb)
+{
+ int i;
+
+ for (i = 0; i < NUMOBUFS; i++) {
+ if (sisusb->obuf[i]) {
+ usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize,
+ sisusb->obuf[i], sisusb->transfer_dma_out[i]);
+ sisusb->obuf[i] = NULL;
+ }
+ }
+ if (sisusb->ibuf) {
+ usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
+ sisusb->ibuf, sisusb->transfer_dma_in);
+ sisusb->ibuf = NULL;
+ }
+}
+
+static void
+sisusb_free_urbs(struct sisusb_usb_data *sisusb)
+{
+ int i;
+
+ for (i = 0; i < NUMOBUFS; i++) {
+ usb_free_urb(sisusb->sisurbout[i]);
+ sisusb->sisurbout[i] = NULL;
+ }
+ usb_free_urb(sisusb->sisurbin);
+ sisusb->sisurbin = NULL;
+}
+
+/* Level 0: USB transport layer */
+
+/* 1. out-bulks */
+
+/* out-urb management */
+
+/* Return 1 if all free, 0 otherwise */
+static int
+sisusb_all_free(struct sisusb_usb_data *sisusb)
+{
+ int i;
+
+ for (i = 0; i < sisusb->numobufs; i++) {
+
+ if (sisusb->urbstatus[i] & SU_URB_BUSY)
+ return 0;
+
+ }
+
+ return 1;
+}
+
+/* Kill all busy URBs */
+static void
+sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
+{
+ int i;
+
+ if (sisusb_all_free(sisusb))
+ return;
+
+ for (i = 0; i < sisusb->numobufs; i++) {
+
+ if (sisusb->urbstatus[i] & SU_URB_BUSY)
+ usb_kill_urb(sisusb->sisurbout[i]);
+
+ }
+}
+
+/* Return 1 if ok, 0 if error (not all complete within timeout) */
+static int
+sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
+{
+ int timeout = 5 * HZ, i = 1;
+
+ wait_event_timeout(sisusb->wait_q,
+ (i = sisusb_all_free(sisusb)),
+ timeout);
+
+ return i;
+}
+
+static int
+sisusb_outurb_available(struct sisusb_usb_data *sisusb)
+{
+ int i;
+
+ for (i = 0; i < sisusb->numobufs; i++) {
+
+ if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
+ return i;
+
+ }
+
+ return -1;
+}
+
+static int
+sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
+{
+ int i, timeout = 5 * HZ;
+
+ wait_event_timeout(sisusb->wait_q,
+ ((i = sisusb_outurb_available(sisusb)) >= 0),
+ timeout);
+
+ return i;
+}
+
+static int
+sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
+{
+ int i;
+
+ i = sisusb_outurb_available(sisusb);
+
+ if (i >= 0)
+ sisusb->urbstatus[i] |= SU_URB_ALLOC;
+
+ return i;
+}
+
+static void
+sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
+{
+ if ((index >= 0) && (index < sisusb->numobufs))
+ sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
+}
+
+/* completion callback */
+
+static void
+sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs)
+{
+ struct sisusb_urb_context *context = urb->context;
+ struct sisusb_usb_data *sisusb;
+
+ if (!context)
+ return;
+
+ sisusb = context->sisusb;
+
+ if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
+ return;
+
+#ifndef SISUSB_DONTSYNC
+ if (context->actual_length)
+ *(context->actual_length) += urb->actual_length;
+#endif
+
+ sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
+ wake_up(&sisusb->wait_q);
+}
+
+static int
+sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
+ int len, int *actual_length, int timeout, unsigned int tflags,
+ dma_addr_t transfer_dma)
+{
+ struct urb *urb = sisusb->sisurbout[index];
+ int retval, byteswritten = 0;
+
+ /* Set up URB */
+ urb->transfer_flags = 0;
+
+ usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
+ sisusb_bulk_completeout, &sisusb->urbout_context[index]);
+
+ urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
+ urb->actual_length = 0;
+
+ if ((urb->transfer_dma = transfer_dma))
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ /* Set up context */
+ sisusb->urbout_context[index].actual_length = (timeout) ?
+ NULL : actual_length;
+
+ /* Declare this urb/buffer in use */
+ sisusb->urbstatus[index] |= SU_URB_BUSY;
+
+ /* Submit URB */
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+ /* If OK, and if timeout > 0, wait for completion */
+ if ((retval == 0) && timeout) {
+ wait_event_timeout(sisusb->wait_q,
+ (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
+ timeout);
+ if (sisusb->urbstatus[index] & SU_URB_BUSY) {
+ /* URB timed out... kill it and report error */
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ } else {
+ /* Otherwise, report urb status */
+ retval = urb->status;
+ byteswritten = urb->actual_length;
+ }
+ }
+
+ if (actual_length)
+ *actual_length = byteswritten;
+
+ return retval;
+}
+
+/* 2. in-bulks */
+
+/* completion callback */
+
+static void
+sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs)
+{
+ struct sisusb_usb_data *sisusb = urb->context;
+
+ if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
+ return;
+
+ sisusb->completein = 1;
+ wake_up(&sisusb->wait_q);
+}
+
+static int
+sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len,
+ int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma)
+{
+ struct urb *urb = sisusb->sisurbin;
+ int retval, readbytes = 0;
+
+ urb->transfer_flags = 0;
+
+ usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
+ sisusb_bulk_completein, sisusb);
+
+ urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
+ urb->actual_length = 0;
+
+ if ((urb->transfer_dma = transfer_dma))
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ sisusb->completein = 0;
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval == 0) {
+ wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
+ if (!sisusb->completein) {
+ /* URB timed out... kill it and report error */
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ } else {
+ /* URB completed within timout */
+ retval = urb->status;
+ readbytes = urb->actual_length;
+ }
+ }
+
+ if (actual_length)
+ *actual_length = readbytes;
+
+ return retval;
+}
+
+
+/* Level 1: */
+
+/* Send a bulk message of variable size
+ *
+ * To copy the data from userspace, give pointer to "userbuffer",
+ * to copy from (non-DMA) kernel memory, give "kernbuffer". If
+ * both of these are NULL, it is assumed, that the transfer
+ * buffer "sisusb->obuf[index]" is set up with the data to send.
+ * Index is ignored if either kernbuffer or userbuffer is set.
+ * If async is nonzero, URBs will be sent without waiting for
+ * completion of the previous URB.
+ *
+ * (return 0 on success)
+ */
+
+static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
+ char *kernbuffer, const char __user *userbuffer, int index,
+ ssize_t *bytes_written, unsigned int tflags, int async)
+{
+ int result = 0, retry, count = len;
+ int passsize, thispass, transferred_len = 0;
+ int fromuser = (userbuffer != NULL) ? 1 : 0;
+ int fromkern = (kernbuffer != NULL) ? 1 : 0;
+ unsigned int pipe;
+ char *buffer;
+
+ (*bytes_written) = 0;
+
+ /* Sanity check */
+ if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
+ return -ENODEV;
+
+ /* If we copy data from kernel or userspace, force the
+ * allocation of a buffer/urb. If we have the data in
+ * the transfer buffer[index] already, reuse the buffer/URB
+ * if the length is > buffer size. (So, transmitting
+ * large data amounts directly from the transfer buffer
+ * treats the buffer as a ring buffer. However, we need
+ * to sync in this case.)
+ */
+ if (fromuser || fromkern)
+ index = -1;
+ else if (len > sisusb->obufsize)
+ async = 0;
+
+ pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
+
+ do {
+ passsize = thispass = (sisusb->obufsize < count) ?
+ sisusb->obufsize : count;
+
+ if (index < 0)
+ index = sisusb_get_free_outbuf(sisusb);
+
+ if (index < 0)
+ return -EIO;
+
+ buffer = sisusb->obuf[index];
+
+ if (fromuser) {
+
+ if (copy_from_user(buffer, userbuffer, passsize))
+ return -EFAULT;
+
+ userbuffer += passsize;
+
+ } else if (fromkern) {
+
+ memcpy(buffer, kernbuffer, passsize);
+ kernbuffer += passsize;
+
+ }
+
+ retry = 5;
+ while (thispass) {
+
+ if (!sisusb->sisusb_dev)
+ return -ENODEV;
+
+ result = sisusb_bulkout_msg(sisusb,
+ index,
+ pipe,
+ buffer,
+ thispass,
+ &transferred_len,
+ async ? 0 : 5 * HZ,
+ tflags,
+ sisusb->transfer_dma_out[index]);
+
+ if (result == -ETIMEDOUT) {
+
+ /* Will not happen if async */
+ if (!retry--)
+ return -ETIME;
+
+ continue;
+
+ } else if ((result == 0) && !async && transferred_len) {
+
+ thispass -= transferred_len;
+ if (thispass) {
+ if (sisusb->transfer_dma_out) {
+ /* If DMA, copy remaining
+ * to beginning of buffer
+ */
+ memcpy(buffer,
+ buffer + transferred_len,
+ thispass);
+ } else {
+ /* If not DMA, simply increase
+ * the pointer
+ */
+ buffer += transferred_len;
+ }
+ }
+
+ } else
+ break;
+ };
+
+ if (result)
+ return result;
+
+ (*bytes_written) += passsize;
+ count -= passsize;
+
+ /* Force new allocation in next iteration */
+ if (fromuser || fromkern)
+ index = -1;
+
+ } while (count > 0);
+
+ if (async) {
+#ifdef SISUSB_DONTSYNC
+ (*bytes_written) = len;
+ /* Some URBs/buffers might be busy */
+#else
+ sisusb_wait_all_out_complete(sisusb);
+ (*bytes_written) = transferred_len;
+ /* All URBs and all buffers are available */
+#endif
+ }
+
+ return ((*bytes_written) == len) ? 0 : -EIO;
+}
+
+/* Receive a bulk message of variable size
+ *
+ * To copy the data to userspace, give pointer to "userbuffer",
+ * to copy to kernel memory, give "kernbuffer". One of them
+ * MUST be set. (There is no technique for letting the caller
+ * read directly from the ibuf.)
+ *
+ */
+
+static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
+ void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
+ unsigned int tflags)
+{
+ int result = 0, retry, count = len;
+ int bufsize, thispass, transferred_len;
+ unsigned int pipe;
+ char *buffer;
+
+ (*bytes_read) = 0;
+
+ /* Sanity check */
+ if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
+ return -ENODEV;
+
+ pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
+ buffer = sisusb->ibuf;
+ bufsize = sisusb->ibufsize;
+
+ retry = 5;
+
+#ifdef SISUSB_DONTSYNC
+ if (!(sisusb_wait_all_out_complete(sisusb)))
+ return -EIO;
+#endif
+
+ while (count > 0) {
+
+ if (!sisusb->sisusb_dev)
+ return -ENODEV;
+
+ thispass = (bufsize < count) ? bufsize : count;
+
+ result = sisusb_bulkin_msg(sisusb,
+ pipe,
+ buffer,
+ thispass,
+ &transferred_len,
+ 5 * HZ,
+ tflags,
+ sisusb->transfer_dma_in);
+
+ if (transferred_len)
+ thispass = transferred_len;
+
+ else if (result == -ETIMEDOUT) {
+
+ if (!retry--)
+ return -ETIME;
+
+ continue;
+
+ } else
+ return -EIO;
+
+
+ if (thispass) {
+
+ (*bytes_read) += thispass;
+ count -= thispass;
+
+ if (userbuffer) {
+
+ if (copy_to_user(userbuffer, buffer, thispass))
+ return -EFAULT;
+
+ userbuffer += thispass;
+
+ } else {
+
+ memcpy(kernbuffer, buffer, thispass);
+ kernbuffer += thispass;
+
+ }
+
+ }
+
+ }
+
+ return ((*bytes_read) == len) ? 0 : -EIO;
+}
+
+static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
+ struct sisusb_packet *packet)
+{
+ int ret;
+ int bytes_transferred = 0;
+ __le32 tmp;
+
+ if (len == 6)
+ packet->data = 0;
+
+#ifdef SISUSB_DONTSYNC
+ if (!(sisusb_wait_all_out_complete(sisusb)))
+ return 1;
+#endif
+
+ /* Eventually correct endianness */
+ SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
+
+ /* 1. send the packet */
+ ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
+ (char *)packet, NULL, 0, &bytes_transferred, 0, 0);
+
+ if ((ret == 0) && (len == 6)) {
+
+ /* 2. if packet len == 6, it means we read, so wait for 32bit
+ * return value and write it to packet->data
+ */
+ ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
+ (char *)&tmp, NULL, &bytes_transferred, 0);
+
+ packet->data = le32_to_cpu(tmp);
+ }
+
+ return ret;
+}
+
+static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
+ struct sisusb_packet *packet,
+ unsigned int tflags)
+{
+ int ret;
+ int bytes_transferred = 0;
+ __le32 tmp;
+
+ if (len == 6)
+ packet->data = 0;
+
+#ifdef SISUSB_DONTSYNC
+ if (!(sisusb_wait_all_out_complete(sisusb)))
+ return 1;
+#endif
+
+ /* Eventually correct endianness */
+ SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
+
+ /* 1. send the packet */
+ ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
+ (char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
+
+ if ((ret == 0) && (len == 6)) {
+
+ /* 2. if packet len == 6, it means we read, so wait for 32bit
+ * return value and write it to packet->data
+ */
+ ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
+ (char *)&tmp, NULL, &bytes_transferred, 0);
+
+ packet->data = le32_to_cpu(tmp);
+ }
+
+ return ret;
+}
+
+/* access video memory and mmio (return 0 on success) */
+
+/* Low level */
+
+/* The following routines assume being used to transfer byte, word,
+ * long etc.
+ * This means that they assume "data" in machine endianness format.
+ */
+
+static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
+ u32 addr, u8 data)
+{
+ struct sisusb_packet packet;
+ int ret;
+
+ packet.header = (1 << (addr & 3)) | (type << 6);
+ packet.address = addr & ~3;
+ packet.data = data << ((addr & 3) << 3);
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ return ret;
+}
+
+static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
+ u32 addr, u16 data)
+{
+ struct sisusb_packet packet;
+ int ret = 0;
+
+ packet.address = addr & ~3;
+
+ switch (addr & 3) {
+ case 0:
+ packet.header = (type << 6) | 0x0003;
+ packet.data = (u32)data;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 1:
+ packet.header = (type << 6) | 0x0006;
+ packet.data = (u32)data << 8;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 2:
+ packet.header = (type << 6) | 0x000c;
+ packet.data = (u32)data << 16;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 3:
+ packet.header = (type << 6) | 0x0008;
+ packet.data = (u32)data << 24;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ packet.header = (type << 6) | 0x0001;
+ packet.address = (addr & ~3) + 4;
+ packet.data = (u32)data >> 8;
+ ret |= sisusb_send_packet(sisusb, 10, &packet);
+ }
+
+ return ret;
+}
+
+static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
+ u32 addr, u32 data)
+{
+ struct sisusb_packet packet;
+ int ret = 0;
+
+ packet.address = addr & ~3;
+
+ switch (addr & 3) {
+ case 0:
+ packet.header = (type << 6) | 0x0007;
+ packet.data = data & 0x00ffffff;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 1:
+ packet.header = (type << 6) | 0x000e;
+ packet.data = data << 8;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 2:
+ packet.header = (type << 6) | 0x000c;
+ packet.data = data << 16;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ packet.header = (type << 6) | 0x0001;
+ packet.address = (addr & ~3) + 4;
+ packet.data = (data >> 16) & 0x00ff;
+ ret |= sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 3:
+ packet.header = (type << 6) | 0x0008;
+ packet.data = data << 24;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ packet.header = (type << 6) | 0x0003;
+ packet.address = (addr & ~3) + 4;
+ packet.data = (data >> 8) & 0xffff;
+ ret |= sisusb_send_packet(sisusb, 10, &packet);
+ }
+
+ return ret;
+}
+
+static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
+ u32 addr, u32 data)
+{
+ struct sisusb_packet packet;
+ int ret = 0;
+
+ packet.address = addr & ~3;
+
+ switch (addr & 3) {
+ case 0:
+ packet.header = (type << 6) | 0x000f;
+ packet.data = data;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 1:
+ packet.header = (type << 6) | 0x000e;
+ packet.data = data << 8;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ packet.header = (type << 6) | 0x0001;
+ packet.address = (addr & ~3) + 4;
+ packet.data = data >> 24;
+ ret |= sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 2:
+ packet.header = (type << 6) | 0x000c;
+ packet.data = data << 16;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ packet.header = (type << 6) | 0x0003;
+ packet.address = (addr & ~3) + 4;
+ packet.data = data >> 16;
+ ret |= sisusb_send_packet(sisusb, 10, &packet);
+ break;
+ case 3:
+ packet.header = (type << 6) | 0x0008;
+ packet.data = data << 24;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ packet.header = (type << 6) | 0x0007;
+ packet.address = (addr & ~3) + 4;
+ packet.data = data >> 8;
+ ret |= sisusb_send_packet(sisusb, 10, &packet);
+ }
+
+ return ret;
+}
+
+/* The xxx_bulk routines copy a buffer of variable size. They treat the
+ * buffer as chars, therefore lsb/msb has to be corrected if using the
+ * byte/word/long/etc routines for speed-up
+ *
+ * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
+ * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
+ * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
+ * that the data already is in the transfer buffer "sisusb->obuf[index]".
+ */
+
+static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
+ char *kernbuffer, int length,
+ const char __user *userbuffer, int index,
+ ssize_t *bytes_written)
+{
+ struct sisusb_packet packet;
+ int ret = 0;
+ static int msgcount = 0;
+ u8 swap8, fromkern = kernbuffer ? 1 : 0;
+ u16 swap16;
+ u32 swap32, flag = (length >> 28) & 1;
+ char buf[4];
+
+ /* if neither kernbuffer not userbuffer are given, assume
+ * data in obuf
+ */
+ if (!fromkern && !userbuffer)
+ kernbuffer = sisusb->obuf[index];
+
+ (*bytes_written = 0);
+
+ length &= 0x00ffffff;
+
+ while (length) {
+
+ switch (length) {
+
+ case 0:
+ return ret;
+
+ case 1:
+ if (userbuffer) {
+ if (get_user(swap8, (u8 __user *)userbuffer))
+ return -EFAULT;
+ } else
+ swap8 = kernbuffer[0];
+
+ ret = sisusb_write_memio_byte(sisusb,
+ SISUSB_TYPE_MEM,
+ addr, swap8);
+
+ if (!ret)
+ (*bytes_written)++;
+
+ return ret;
+
+ case 2:
+ if (userbuffer) {
+ if (get_user(swap16, (u16 __user *)userbuffer))
+ return -EFAULT;
+ } else
+ swap16 = (kernbuffer[0] << 8) | kernbuffer[1];
+
+ ret = sisusb_write_memio_word(sisusb,
+ SISUSB_TYPE_MEM,
+ addr,
+ swap16);
+
+ if (!ret)
+ (*bytes_written) += 2;
+
+ return ret;
+
+ case 3:
+ if (userbuffer) {
+ if (copy_from_user(&buf, userbuffer, 3))
+ return -EFAULT;
+
+ swap32 = (buf[0] << 16) |
+ (buf[1] << 8) |
+ buf[2];
+ } else
+ swap32 = (kernbuffer[0] << 16) |
+ (kernbuffer[1] << 8) |
+ kernbuffer[2];
+
+ ret = sisusb_write_memio_24bit(sisusb,
+ SISUSB_TYPE_MEM,
+ addr,
+ swap32);
+
+ if (!ret)
+ (*bytes_written) += 3;
+
+ return ret;
+
+ case 4:
+ if (userbuffer) {
+ if (get_user(swap32, (u32 __user *)userbuffer))
+ return -EFAULT;
+ } else
+ swap32 = (kernbuffer[0] << 24) |
+ (kernbuffer[1] << 16) |
+ (kernbuffer[2] << 8) |
+ kernbuffer[3];
+
+ ret = sisusb_write_memio_long(sisusb,
+ SISUSB_TYPE_MEM,
+ addr,
+ swap32);
+ if (!ret)
+ (*bytes_written) += 4;
+
+ return ret;
+
+ default:
+ if ((length & ~3) > 0x10000) {
+
+ packet.header = 0x001f;
+ packet.address = 0x000001d4;
+ packet.data = addr;
+ ret = sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ packet.header = 0x001f;
+ packet.address = 0x000001d0;
+ packet.data = (length & ~3);
+ ret |= sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ packet.header = 0x001f;
+ packet.address = 0x000001c0;
+ packet.data = flag | 0x16;
+ ret |= sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ if (userbuffer) {
+ ret |= sisusb_send_bulk_msg(sisusb,
+ SISUSB_EP_GFX_LBULK_OUT,
+ (length & ~3),
+ NULL, userbuffer, 0,
+ bytes_written, 0, 1);
+ userbuffer += (*bytes_written);
+ } else if (fromkern) {
+ ret |= sisusb_send_bulk_msg(sisusb,
+ SISUSB_EP_GFX_LBULK_OUT,
+ (length & ~3),
+ kernbuffer, NULL, 0,
+ bytes_written, 0, 1);
+ kernbuffer += (*bytes_written);
+ } else {
+ ret |= sisusb_send_bulk_msg(sisusb,
+ SISUSB_EP_GFX_LBULK_OUT,
+ (length & ~3),
+ NULL, NULL, index,
+ bytes_written, 0, 1);
+ kernbuffer += ((*bytes_written) &
+ (sisusb->obufsize-1));
+ }
+
+ } else {
+
+ packet.header = 0x001f;
+ packet.address = 0x00000194;
+ packet.data = addr;
+ ret = sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ packet.header = 0x001f;
+ packet.address = 0x00000190;
+ packet.data = (length & ~3);
+ ret |= sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ if (sisusb->flagb0 != 0x16) {
+ packet.header = 0x001f;
+ packet.address = 0x00000180;
+ packet.data = flag | 0x16;
+ ret |= sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ sisusb->flagb0 = 0x16;
+ }
+ if (userbuffer) {
+ ret |= sisusb_send_bulk_msg(sisusb,
+ SISUSB_EP_GFX_BULK_OUT,
+ (length & ~3),
+ NULL, userbuffer, 0,
+ bytes_written, 0, 1);
+ userbuffer += (*bytes_written);
+ } else if (fromkern) {
+ ret |= sisusb_send_bulk_msg(sisusb,
+ SISUSB_EP_GFX_BULK_OUT,
+ (length & ~3),
+ kernbuffer, NULL, 0,
+ bytes_written, 0, 1);
+ kernbuffer += (*bytes_written);
+ } else {
+ ret |= sisusb_send_bulk_msg(sisusb,
+ SISUSB_EP_GFX_BULK_OUT,
+ (length & ~3),
+ NULL, NULL, index,
+ bytes_written, 0, 1);
+ kernbuffer += ((*bytes_written) &
+ (sisusb->obufsize-1));
+ }
+ }
+ if (ret) {
+ msgcount++;
+ if (msgcount < 500)
+ printk(KERN_ERR
+ "sisusbvga[%d]: Wrote %d of "
+ "%d bytes, error %d\n",
+ sisusb->minor, *bytes_written,
+ length, ret);
+ else if (msgcount == 500)
+ printk(KERN_ERR
+ "sisusbvga[%d]: Too many errors"
+ ", logging stopped\n",
+ sisusb->minor);
+ }
+ addr += (*bytes_written);
+ length -= (*bytes_written);
+ }
+
+ if (ret)
+ break;
+
+ }
+
+ return ret ? -EIO : 0;
+}
+
+static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
+ u32 addr, u8 *data)
+{
+ struct sisusb_packet packet;
+ int ret;
+
+ CLEARPACKET(&packet);
+ packet.header = (1 << (addr & 3)) | (type << 6);
+ packet.address = addr & ~3;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = (u8)(packet.data >> ((addr & 3) << 3));
+ return ret;
+}
+
+static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
+ u32 addr, u16 *data)
+{
+ struct sisusb_packet packet;
+ int ret = 0;
+
+ CLEARPACKET(&packet);
+
+ packet.address = addr & ~3;
+
+ switch (addr & 3) {
+ case 0:
+ packet.header = (type << 6) | 0x0003;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = (u16)(packet.data);
+ break;
+ case 1:
+ packet.header = (type << 6) | 0x0006;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = (u16)(packet.data >> 8);
+ break;
+ case 2:
+ packet.header = (type << 6) | 0x000c;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = (u16)(packet.data >> 16);
+ break;
+ case 3:
+ packet.header = (type << 6) | 0x0008;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = (u16)(packet.data >> 24);
+ packet.header = (type << 6) | 0x0001;
+ packet.address = (addr & ~3) + 4;
+ ret |= sisusb_send_packet(sisusb, 6, &packet);
+ *data |= (u16)(packet.data << 8);
+ }
+
+ return ret;
+}
+
+static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
+ u32 addr, u32 *data)
+{
+ struct sisusb_packet packet;
+ int ret = 0;
+
+ packet.address = addr & ~3;
+
+ switch (addr & 3) {
+ case 0:
+ packet.header = (type << 6) | 0x0007;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data & 0x00ffffff;
+ break;
+ case 1:
+ packet.header = (type << 6) | 0x000e;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data >> 8;
+ break;
+ case 2:
+ packet.header = (type << 6) | 0x000c;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data >> 16;
+ packet.header = (type << 6) | 0x0001;
+ packet.address = (addr & ~3) + 4;
+ ret |= sisusb_send_packet(sisusb, 6, &packet);
+ *data |= ((packet.data & 0xff) << 16);
+ break;
+ case 3:
+ packet.header = (type << 6) | 0x0008;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data >> 24;
+ packet.header = (type << 6) | 0x0003;
+ packet.address = (addr & ~3) + 4;
+ ret |= sisusb_send_packet(sisusb, 6, &packet);
+ *data |= ((packet.data & 0xffff) << 8);
+ }
+
+ return ret;
+}
+
+static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
+ u32 addr, u32 *data)
+{
+ struct sisusb_packet packet;
+ int ret = 0;
+
+ packet.address = addr & ~3;
+
+ switch (addr & 3) {
+ case 0:
+ packet.header = (type << 6) | 0x000f;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data;
+ break;
+ case 1:
+ packet.header = (type << 6) | 0x000e;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data >> 8;
+ packet.header = (type << 6) | 0x0001;
+ packet.address = (addr & ~3) + 4;
+ ret |= sisusb_send_packet(sisusb, 6, &packet);
+ *data |= (packet.data << 24);
+ break;
+ case 2:
+ packet.header = (type << 6) | 0x000c;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data >> 16;
+ packet.header = (type << 6) | 0x0003;
+ packet.address = (addr & ~3) + 4;
+ ret |= sisusb_send_packet(sisusb, 6, &packet);
+ *data |= (packet.data << 16);
+ break;
+ case 3:
+ packet.header = (type << 6) | 0x0008;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data >> 24;
+ packet.header = (type << 6) | 0x0007;
+ packet.address = (addr & ~3) + 4;
+ ret |= sisusb_send_packet(sisusb, 6, &packet);
+ *data |= (packet.data << 8);
+ }
+
+ return ret;
+}
+
+static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
+ char *kernbuffer, int length,
+ char __user *userbuffer, ssize_t *bytes_read)
+{
+ int ret = 0;
+ char buf[4];
+ u16 swap16;
+ u32 swap32;
+
+ (*bytes_read = 0);
+
+ length &= 0x00ffffff;
+
+ while (length) {
+
+ switch (length) {
+
+ case 0:
+ return ret;
+
+ case 1:
+
+ ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
+ addr, &buf[0]);
+ if (!ret) {
+ (*bytes_read)++;
+ if (userbuffer) {
+ if (put_user(buf[0],
+ (u8 __user *)userbuffer)) {
+ return -EFAULT;
+ }
+ } else {
+ kernbuffer[0] = buf[0];
+ }
+ }
+ return ret;
+
+ case 2:
+ ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
+ addr, &swap16);
+ if (!ret) {
+ (*bytes_read) += 2;
+ if (userbuffer) {
+ if (put_user(swap16,
+ (u16 __user *)userbuffer))
+ return -EFAULT;
+ } else {
+ kernbuffer[0] = swap16 >> 8;
+ kernbuffer[1] = swap16 & 0xff;
+ }
+ }
+ return ret;
+
+ case 3:
+ ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
+ addr, &swap32);
+ if (!ret) {
+ (*bytes_read) += 3;
+ buf[0] = (swap32 >> 16) & 0xff;
+ buf[1] = (swap32 >> 8) & 0xff;
+ buf[2] = swap32 & 0xff;
+ if (userbuffer) {
+ if (copy_to_user(userbuffer, &buf[0], 3))
+ return -EFAULT;
+ } else {
+ kernbuffer[0] = buf[0];
+ kernbuffer[1] = buf[1];
+ kernbuffer[2] = buf[2];
+ }
+ }
+ return ret;
+
+ default:
+ ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
+ addr, &swap32);
+ if (!ret) {
+ (*bytes_read) += 4;
+ if (userbuffer) {
+ if (put_user(swap32,
+ (u32 __user *)userbuffer))
+ return -EFAULT;
+
+ userbuffer += 4;
+ } else {
+ kernbuffer[0] = (swap32 >> 24) & 0xff;
+ kernbuffer[1] = (swap32 >> 16) & 0xff;
+ kernbuffer[2] = (swap32 >> 8) & 0xff;
+ kernbuffer[3] = swap32 & 0xff;
+ kernbuffer += 4;
+ }
+ addr += 4;
+ length -= 4;
+ }
+#if 0 /* That does not work, as EP 2 is an OUT EP! */
+ default:
+ CLEARPACKET(&packet);
+ packet.header = 0x001f;
+ packet.address = 0x000001a0;
+ packet.data = 0x00000006;
+ ret |= sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ packet.header = 0x001f;
+ packet.address = 0x000001b0;
+ packet.data = (length & ~3) | 0x40000000;
+ ret |= sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ packet.header = 0x001f;
+ packet.address = 0x000001b4;
+ packet.data = addr;
+ ret |= sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ packet.header = 0x001f;
+ packet.address = 0x000001a4;
+ packet.data = 0x00000001;
+ ret |= sisusb_send_bridge_packet(sisusb, 10,
+ &packet, 0);
+ if (userbuffer) {
+ ret |= sisusb_recv_bulk_msg(sisusb,
+ SISUSB_EP_GFX_BULK_IN,
+ (length & ~3),
+ NULL, userbuffer,
+ bytes_read, 0);
+ if (!ret) userbuffer += (*bytes_read);
+ } else {
+ ret |= sisusb_recv_bulk_msg(sisusb,
+ SISUSB_EP_GFX_BULK_IN,
+ (length & ~3),
+ kernbuffer, NULL,
+ bytes_read, 0);
+ if (!ret) kernbuffer += (*bytes_read);
+ }
+ addr += (*bytes_read);
+ length -= (*bytes_read);
+#endif
+ }
+
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+/* High level: Gfx (indexed) register access */
+
+static int
+sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
+{
+ int ret;
+ ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
+ ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
+ return ret;
+}
+
+static int
+sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
+{
+ int ret;
+ ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
+ ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
+ return ret;
+}
+
+static int
+sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
+ u8 myand, u8 myor)
+{
+ int ret;
+ u8 tmp;
+
+ ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
+ ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
+ tmp &= myand;
+ tmp |= myor;
+ ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
+ return ret;
+}
+
+static int
+sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
+ u8 data, u8 mask)
+{
+ int ret;
+ u8 tmp;
+ ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
+ ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
+ tmp &= ~(mask);
+ tmp |= (data & mask);
+ ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
+ return ret;
+}
+
+static int
+sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
+{
+ return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
+}
+
+static int
+sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
+{
+ return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
+}
+
+/* access pci config registers (reg numbers 0, 4, 8, etc) */
+
+static int
+sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
+{
+ struct sisusb_packet packet;
+ int ret;
+
+ packet.header = 0x008f;
+ packet.address = regnum | 0x10000;
+ packet.data = data;
+ ret = sisusb_send_packet(sisusb, 10, &packet);
+ return ret;
+}
+
+static int
+sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
+{
+ struct sisusb_packet packet;
+ int ret;
+
+ packet.header = 0x008f;
+ packet.address = (u32)regnum | 0x10000;
+ ret = sisusb_send_packet(sisusb, 6, &packet);
+ *data = packet.data;
+ return ret;
+}
+
+/* Clear video RAM */
+
+static int
+sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
+{
+ int ret, i, j;
+
+ if (address < sisusb->vrambase)
+ return 1;
+
+ if (address >= sisusb->vrambase + sisusb->vramsize)
+ return 1;
+
+ if (address + length > sisusb->vrambase + sisusb->vramsize)
+ length = sisusb->vrambase + sisusb->vramsize - address;
+
+ if (length <= 0)
+ return 0;
+
+ /* allocate free buffer/urb and clear the buffer */
+ if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
+ return -EBUSY;
+
+ memset(sisusb->obuf[i], 0, sisusb->obufsize);
+
+ /* We can write a length > buffer size here. The buffer
+ * data will simply be re-used (like a ring-buffer).
+ */
+ ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
+
+ /* Free the buffer/urb */
+ sisusb_free_outbuf(sisusb, i);
+
+ return ret;
+}
+
+/* Initialize the graphics core (return 0 on success)
+ * This resets the graphics hardware and puts it into
+ * a defined mode (640x480@60Hz)
+ */
+
+#define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
+#define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
+#define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
+#define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
+#define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
+#define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
+#define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
+#define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+
+static int
+sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
+{
+ int ret;
+ u8 tmp8;
+
+ ret = GETIREG(SISSR, 0x16, &tmp8);
+ if (ramtype <= 1) {
+ tmp8 &= 0x3f;
+ ret |= SETIREG(SISSR, 0x16, tmp8);
+ tmp8 |= 0x80;
+ ret |= SETIREG(SISSR, 0x16, tmp8);
+ } else {
+ tmp8 |= 0xc0;
+ ret |= SETIREG(SISSR, 0x16, tmp8);
+ tmp8 &= 0x0f;
+ ret |= SETIREG(SISSR, 0x16, tmp8);
+ tmp8 |= 0x80;
+ ret |= SETIREG(SISSR, 0x16, tmp8);
+ tmp8 &= 0x0f;
+ ret |= SETIREG(SISSR, 0x16, tmp8);
+ tmp8 |= 0xd0;
+ ret |= SETIREG(SISSR, 0x16, tmp8);
+ tmp8 &= 0x0f;
+ ret |= SETIREG(SISSR, 0x16, tmp8);
+ tmp8 |= 0xa0;
+ ret |= SETIREG(SISSR, 0x16, tmp8);
+ }
+ return ret;
+}
+
+static int
+sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
+{
+ int ret;
+ u8 ramtype, done = 0;
+ u32 t0, t1, t2, t3;
+ u32 ramptr = SISUSB_PCI_MEMBASE;
+
+ ret = GETIREG(SISSR, 0x3a, &ramtype);
+ ramtype &= 3;
+
+ ret |= SETIREG(SISSR, 0x13, 0x00);
+
+ if (ramtype <= 1) {
+ ret |= SETIREG(SISSR, 0x14, 0x12);
+ ret |= SETIREGAND(SISSR, 0x15, 0xef);
+ } else {
+ ret |= SETIREG(SISSR, 0x14, 0x02);
+ }
+
+ ret |= sisusb_triggersr16(sisusb, ramtype);
+ ret |= WRITEL(ramptr + 0, 0x01234567);
+ ret |= WRITEL(ramptr + 4, 0x456789ab);
+ ret |= WRITEL(ramptr + 8, 0x89abcdef);
+ ret |= WRITEL(ramptr + 12, 0xcdef0123);
+ ret |= WRITEL(ramptr + 16, 0x55555555);
+ ret |= WRITEL(ramptr + 20, 0x55555555);
+ ret |= WRITEL(ramptr + 24, 0xffffffff);
+ ret |= WRITEL(ramptr + 28, 0xffffffff);
+ ret |= READL(ramptr + 0, &t0);
+ ret |= READL(ramptr + 4, &t1);
+ ret |= READL(ramptr + 8, &t2);
+ ret |= READL(ramptr + 12, &t3);
+
+ if (ramtype <= 1) {
+
+ *chab = 0; *bw = 64;
+
+ if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
+ if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
+ *chab = 0; *bw = 64;
+ ret |= SETIREGAND(SISSR, 0x14, 0xfd);
+ }
+ }
+ if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
+ *chab = 1; *bw = 64;
+ ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
+
+ ret |= sisusb_triggersr16(sisusb, ramtype);
+ ret |= WRITEL(ramptr + 0, 0x89abcdef);
+ ret |= WRITEL(ramptr + 4, 0xcdef0123);
+ ret |= WRITEL(ramptr + 8, 0x55555555);
+ ret |= WRITEL(ramptr + 12, 0x55555555);
+ ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
+ ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
+ ret |= READL(ramptr + 4, &t1);
+
+ if (t1 != 0xcdef0123) {
+ *bw = 32;
+ ret |= SETIREGOR(SISSR, 0x15, 0x10);
+ }
+ }
+
+ } else {
+
+ *chab = 0; *bw = 64; /* default: cha, bw = 64 */
+
+ done = 0;
+
+ if (t1 == 0x456789ab) {
+ if (t0 == 0x01234567) {
+ *chab = 0; *bw = 64;
+ done = 1;
+ }
+ } else {
+ if (t0 == 0x01234567) {
+ *chab = 0; *bw = 32;
+ ret |= SETIREG(SISSR, 0x14, 0x00);
+ done = 1;
+ }
+ }
+
+ if (!done) {
+ ret |= SETIREG(SISSR, 0x14, 0x03);
+ ret |= sisusb_triggersr16(sisusb, ramtype);
+
+ ret |= WRITEL(ramptr + 0, 0x01234567);
+ ret |= WRITEL(ramptr + 4, 0x456789ab);
+ ret |= WRITEL(ramptr + 8, 0x89abcdef);
+ ret |= WRITEL(ramptr + 12, 0xcdef0123);
+ ret |= WRITEL(ramptr + 16, 0x55555555);
+ ret |= WRITEL(ramptr + 20, 0x55555555);
+ ret |= WRITEL(ramptr + 24, 0xffffffff);
+ ret |= WRITEL(ramptr + 28, 0xffffffff);
+ ret |= READL(ramptr + 0, &t0);
+ ret |= READL(ramptr + 4, &t1);
+
+ if (t1 == 0x456789ab) {
+ if (t0 == 0x01234567) {
+ *chab = 1; *bw = 64;
+ return ret;
+ } /* else error */
+ } else {
+ if (t0 == 0x01234567) {
+ *chab = 1; *bw = 32;
+ ret |= SETIREG(SISSR, 0x14, 0x01);
+ } /* else error */
+ }
+ }
+ }
+ return ret;
+}
+
+static int
+sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
+{
+ int ret = 0;
+ u32 ramptr = SISUSB_PCI_MEMBASE;
+ u8 tmp1, tmp2, i, j;
+
+ ret |= WRITEB(ramptr, 0xaa);
+ ret |= WRITEB(ramptr + 16, 0x55);
+ ret |= READB(ramptr, &tmp1);
+ ret |= READB(ramptr + 16, &tmp2);
+ if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
+ for (i = 0, j = 16; i < 2; i++, j += 16) {
+ ret |= GETIREG(SISSR, 0x21, &tmp1);
+ ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
+ ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
+ ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
+ ret |= SETIREG(SISSR, 0x21, tmp1);
+ ret |= WRITEB(ramptr + 16 + j, j);
+ ret |= READB(ramptr + 16 + j, &tmp1);
+ if (tmp1 == j) {
+ ret |= WRITEB(ramptr + j, j);
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+static int
+sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
+ u8 rankno, u8 chab, const u8 dramtype[][5],
+ int bw)
+{
+ int ret = 0, ranksize;
+ u8 tmp;
+
+ *iret = 0;
+
+ if ((rankno == 2) && (dramtype[index][0] == 2))
+ return ret;
+
+ ranksize = dramtype[index][3] / 2 * bw / 32;
+
+ if ((ranksize * rankno) > 128)
+ return ret;
+
+ tmp = 0;
+ while ((ranksize >>= 1) > 0) tmp += 0x10;
+ tmp |= ((rankno - 1) << 2);
+ tmp |= ((bw / 64) & 0x02);
+ tmp |= (chab & 0x01);
+
+ ret = SETIREG(SISSR, 0x14, tmp);
+ ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
+
+ *iret = 1;
+
+ return ret;
+}
+
+static int
+sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
+{
+ int ret = 0, i;
+ u32 j, tmp;
+
+ *iret = 0;
+
+ for (i = 0, j = 0; i < testn; i++) {
+ ret |= WRITEL(sisusb->vrambase + j, j);
+ j += inc;
+ }
+
+ for (i = 0, j = 0; i < testn; i++) {
+ ret |= READL(sisusb->vrambase + j, &tmp);
+ if (tmp != j) return ret;
+ j += inc;
+ }
+
+ *iret = 1;
+ return ret;
+}
+
+static int
+sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
+ int idx, int bw, const u8 rtype[][5])
+{
+ int ret = 0, i, i2ret;
+ u32 inc;
+
+ *iret = 0;
+
+ for (i = rankno; i >= 1; i--) {
+ inc = 1 << (rtype[idx][2] +
+ rtype[idx][1] +
+ rtype[idx][0] +
+ bw / 64 + i);
+ ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
+ if (!i2ret)
+ return ret;
+ }
+
+ inc = 1 << (rtype[idx][2] + bw / 64 + 2);
+ ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
+ if (!i2ret)
+ return ret;
+
+ inc = 1 << (10 + bw / 64);
+ ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
+ if (!i2ret)
+ return ret;
+
+ *iret = 1;
+ return ret;
+}
+
+static int
+sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
+ int chab)
+{
+ int ret = 0, i2ret = 0, i, j;
+ static const u8 sdramtype[13][5] = {
+ { 2, 12, 9, 64, 0x35 },
+ { 1, 13, 9, 64, 0x44 },
+ { 2, 12, 8, 32, 0x31 },
+ { 2, 11, 9, 32, 0x25 },
+ { 1, 12, 9, 32, 0x34 },
+ { 1, 13, 8, 32, 0x40 },
+ { 2, 11, 8, 16, 0x21 },
+ { 1, 12, 8, 16, 0x30 },
+ { 1, 11, 9, 16, 0x24 },
+ { 1, 11, 8, 8, 0x20 },
+ { 2, 9, 8, 4, 0x01 },
+ { 1, 10, 8, 4, 0x10 },
+ { 1, 9, 8, 2, 0x00 }
+ };
+
+ *iret = 1; /* error */
+
+ for (i = 0; i < 13; i++) {
+ ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
+ for (j = 2; j > 0; j--) {
+ ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
+ chab, sdramtype, bw);
+ if (!i2ret)
+ continue;
+
+ ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
+ bw, sdramtype);
+ if (i2ret) {
+ *iret = 0; /* ram size found */
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int
+sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
+{
+ int ret = 0;
+ u32 address;
+ int i, length, modex, modey, bpp;
+
+ modex = 640; modey = 480; bpp = 2;
+
+ address = sisusb->vrambase; /* Clear video ram */
+
+ if (clrall)
+ length = sisusb->vramsize;
+ else
+ length = modex * bpp * modey;
+
+ ret = sisusb_clear_vram(sisusb, address, length);
+
+ if (!ret && drwfr) {
+ for (i = 0; i < modex; i++) {
+ address = sisusb->vrambase + (i * bpp);
+ ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+ address, 0xf100);
+ address += (modex * (modey-1) * bpp);
+ ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+ address, 0xf100);
+ }
+ for (i = 0; i < modey; i++) {
+ address = sisusb->vrambase + ((i * modex) * bpp);
+ ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+ address, 0xf100);
+ address += ((modex - 1) * bpp);
+ ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+ address, 0xf100);
+ }
+ }
+
+ return ret;
+}
+
+static int
+sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
+{
+ int ret = 0, i, j, modex, modey, bpp, du;
+ u8 sr31, cr63, tmp8;
+ static const char attrdata[] = {
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+ 0x01,0x00,0x00,0x00
+ };
+ static const char crtcrdata[] = {
+ 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+ 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+ 0xff
+ };
+ static const char grcdata[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+ 0xff
+ };
+ static const char crtcdata[] = {
+ 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
+ 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
+ 0x00
+ };
+
+ modex = 640; modey = 480; bpp = 2;
+
+ GETIREG(SISSR, 0x31, &sr31);
+ GETIREG(SISCR, 0x63, &cr63);
+ SETIREGOR(SISSR, 0x01, 0x20);
+ SETIREG(SISCR, 0x63, cr63 & 0xbf);
+ SETIREGOR(SISCR, 0x17, 0x80);
+ SETIREGOR(SISSR, 0x1f, 0x04);
+ SETIREGAND(SISSR, 0x07, 0xfb);
+ SETIREG(SISSR, 0x00, 0x03); /* seq */
+ SETIREG(SISSR, 0x01, 0x21);
+ SETIREG(SISSR, 0x02, 0x0f);
+ SETIREG(SISSR, 0x03, 0x00);
+ SETIREG(SISSR, 0x04, 0x0e);
+ SETREG(SISMISCW, 0x23); /* misc */
+ for (i = 0; i <= 0x18; i++) { /* crtc */
+ SETIREG(SISCR, i, crtcrdata[i]);
+ }
+ for (i = 0; i <= 0x13; i++) { /* att */
+ GETREG(SISINPSTAT, &tmp8);
+ SETREG(SISAR, i);
+ SETREG(SISAR, attrdata[i]);
+ }
+ GETREG(SISINPSTAT, &tmp8);
+ SETREG(SISAR, 0x14);
+ SETREG(SISAR, 0x00);
+ GETREG(SISINPSTAT, &tmp8);
+ SETREG(SISAR, 0x20);
+ GETREG(SISINPSTAT, &tmp8);
+ for (i = 0; i <= 0x08; i++) { /* grc */
+ SETIREG(SISGR, i, grcdata[i]);
+ }
+ SETIREGAND(SISGR, 0x05, 0xbf);
+ for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
+ SETIREG(SISSR, i, 0x00);
+ }
+ SETIREGAND(SISSR, 0x37, 0xfe);
+ SETREG(SISMISCW, 0xef); /* sync */
+ SETIREG(SISCR, 0x11, 0x00); /* crtc */
+ for (j = 0x00, i = 0; i <= 7; i++, j++) {
+ SETIREG(SISCR, j, crtcdata[i]);
+ }
+ for (j = 0x10; i <= 10; i++, j++) {
+ SETIREG(SISCR, j, crtcdata[i]);
+ }
+ for (j = 0x15; i <= 12; i++, j++) {
+ SETIREG(SISCR, j, crtcdata[i]);
+ }
+ for (j = 0x0A; i <= 15; i++, j++) {
+ SETIREG(SISSR, j, crtcdata[i]);
+ }
+ SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
+ SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
+ SETIREG(SISCR, 0x14, 0x4f);
+ du = (modex / 16) * (bpp * 2); /* offset/pitch */
+ if (modex % 16) du += bpp;
+ SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
+ SETIREG(SISCR, 0x13, (du & 0xff));
+ du <<= 5;
+ tmp8 = du >> 8;
+ if (du & 0xff) tmp8++;
+ SETIREG(SISSR, 0x10, tmp8);
+ SETIREG(SISSR, 0x31, 0x00); /* VCLK */
+ SETIREG(SISSR, 0x2b, 0x1b);
+ SETIREG(SISSR, 0x2c, 0xe1);
+ SETIREG(SISSR, 0x2d, 0x01);
+ SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
+ SETIREG(SISSR, 0x08, 0xae);
+ SETIREGAND(SISSR, 0x09, 0xf0);
+ SETIREG(SISSR, 0x08, 0x34);
+ SETIREGOR(SISSR, 0x3d, 0x01);
+ SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
+ SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
+ SETIREG(SISCR, 0x19, 0x00);
+ SETIREGAND(SISCR, 0x1a, 0xfc);
+ SETIREGAND(SISSR, 0x0f, 0xb7);
+ SETIREGAND(SISSR, 0x31, 0xfb);
+ SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
+ SETIREGAND(SISSR, 0x32, 0xf3);
+ SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
+ SETIREG(SISCR, 0x52, 0x6c);
+
+ SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
+ SETIREG(SISCR, 0x0c, 0x00);
+ SETIREG(SISSR, 0x0d, 0x00);
+ SETIREGAND(SISSR, 0x37, 0xfe);
+
+ SETIREG(SISCR, 0x32, 0x20);
+ SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
+ SETIREG(SISCR, 0x63, (cr63 & 0xbf));
+ SETIREG(SISSR, 0x31, (sr31 & 0xfb));
+
+ if (touchengines) {
+ SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
+ SETIREGOR(SISSR, 0x1e, 0x5a);
+
+ SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
+ SETIREG(SISSR, 0x27, 0x1f);
+ SETIREG(SISSR, 0x26, 0x00);
+ }
+
+ SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
+
+ return ret;
+}
+
+static int
+sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
+{
+ int ret = 0, i, j, bw, chab, iret, retry = 3;
+ u8 tmp8, ramtype;
+ u32 tmp32;
+ static const char mclktable[] = {
+ 0x3b, 0x22, 0x01, 143,
+ 0x3b, 0x22, 0x01, 143,
+ 0x3b, 0x22, 0x01, 143,
+ 0x3b, 0x22, 0x01, 143
+ };
+ static const char eclktable[] = {
+ 0x3b, 0x22, 0x01, 143,
+ 0x3b, 0x22, 0x01, 143,
+ 0x3b, 0x22, 0x01, 143,
+ 0x3b, 0x22, 0x01, 143
+ };
+ static const char ramtypetable1[] = {
+ 0x00, 0x04, 0x60, 0x60,
+ 0x0f, 0x0f, 0x1f, 0x1f,
+ 0xba, 0xba, 0xba, 0xba,
+ 0xa9, 0xa9, 0xac, 0xac,
+ 0xa0, 0xa0, 0xa0, 0xa8,
+ 0x00, 0x00, 0x02, 0x02,
+ 0x30, 0x30, 0x40, 0x40
+ };
+ static const char ramtypetable2[] = {
+ 0x77, 0x77, 0x44, 0x44,
+ 0x77, 0x77, 0x44, 0x44,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x5b, 0x5b, 0xab, 0xab,
+ 0x00, 0x00, 0xf0, 0xf8
+ };
+
+ while (retry--) {
+
+ /* Enable VGA */
+ ret = GETREG(SISVGAEN, &tmp8);
+ ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
+
+ /* Enable GPU access to VRAM */
+ ret |= GETREG(SISMISCR, &tmp8);
+ ret |= SETREG(SISMISCW, (tmp8 | 0x01));
+
+ if (ret) continue;
+
+ /* Reset registers */
+ ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
+ ret |= SETIREG(SISSR, 0x05, 0x86);
+ ret |= SETIREGOR(SISSR, 0x20, 0x01);
+
+ ret |= SETREG(SISMISCW, 0x67);
+
+ for (i = 0x06; i <= 0x1f; i++) {
+ ret |= SETIREG(SISSR, i, 0x00);
+ }
+ for (i = 0x21; i <= 0x27; i++) {
+ ret |= SETIREG(SISSR, i, 0x00);
+ }
+ for (i = 0x31; i <= 0x3d; i++) {
+ ret |= SETIREG(SISSR, i, 0x00);
+ }
+ for (i = 0x12; i <= 0x1b; i++) {
+ ret |= SETIREG(SISSR, i, 0x00);
+ }
+ for (i = 0x79; i <= 0x7c; i++) {
+ ret |= SETIREG(SISCR, i, 0x00);
+ }
+
+ if (ret) continue;
+
+ ret |= SETIREG(SISCR, 0x63, 0x80);
+
+ ret |= GETIREG(SISSR, 0x3a, &ramtype);
+ ramtype &= 0x03;
+
+ ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
+ ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
+ ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
+
+ ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
+ ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
+ ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
+
+ ret |= SETIREG(SISSR, 0x07, 0x18);
+ ret |= SETIREG(SISSR, 0x11, 0x0f);
+
+ if (ret) continue;
+
+ for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
+ ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
+ }
+ for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
+ ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
+ }
+
+ ret |= SETIREG(SISCR, 0x49, 0xaa);
+
+ ret |= SETIREG(SISSR, 0x1f, 0x00);
+ ret |= SETIREG(SISSR, 0x20, 0xa0);
+ ret |= SETIREG(SISSR, 0x23, 0xf6);
+ ret |= SETIREG(SISSR, 0x24, 0x0d);
+ ret |= SETIREG(SISSR, 0x25, 0x33);
+
+ ret |= SETIREG(SISSR, 0x11, 0x0f);
+
+ ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
+
+ ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
+
+ if (ret) continue;
+
+ ret |= SETIREG(SISPART1, 0x00, 0x00);
+
+ ret |= GETIREG(SISSR, 0x13, &tmp8);
+ tmp8 >>= 4;
+
+ ret |= SETIREG(SISPART1, 0x02, 0x00);
+ ret |= SETIREG(SISPART1, 0x2e, 0x08);
+
+ ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
+ tmp32 &= 0x00f00000;
+ tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
+ ret |= SETIREG(SISSR, 0x25, tmp8);
+ tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
+ ret |= SETIREG(SISCR, 0x49, tmp8);
+
+ ret |= SETIREG(SISSR, 0x27, 0x1f);
+ ret |= SETIREG(SISSR, 0x31, 0x00);
+ ret |= SETIREG(SISSR, 0x32, 0x11);
+ ret |= SETIREG(SISSR, 0x33, 0x00);
+
+ if (ret) continue;
+
+ ret |= SETIREG(SISCR, 0x83, 0x00);
+
+ ret |= sisusb_set_default_mode(sisusb, 0);
+
+ ret |= SETIREGAND(SISSR, 0x21, 0xdf);
+ ret |= SETIREGOR(SISSR, 0x01, 0x20);
+ ret |= SETIREGOR(SISSR, 0x16, 0x0f);
+
+ ret |= sisusb_triggersr16(sisusb, ramtype);
+
+ /* Disable refresh */
+ ret |= SETIREGAND(SISSR, 0x17, 0xf8);
+ ret |= SETIREGOR(SISSR, 0x19, 0x03);
+
+ ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
+ ret |= sisusb_verify_mclk(sisusb);
+
+ if (ramtype <= 1) {
+ ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
+ if (iret) {
+ printk(KERN_ERR "sisusbvga[%d]: RAM size "
+ "detection failed, "
+ "assuming 8MB video RAM\n",
+ sisusb->minor);
+ ret |= SETIREG(SISSR,0x14,0x31);
+ /* TODO */
+ }
+ } else {
+ printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
+ "assuming 8MB video RAM\n",
+ sisusb->minor);
+ ret |= SETIREG(SISSR,0x14,0x31);
+ /* *** TODO *** */
+ }
+
+ /* Enable refresh */
+ ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
+ ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
+ ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
+
+ ret |= SETIREGOR(SISSR, 0x21, 0x20);
+
+ ret |= SETIREG(SISSR, 0x22, 0xfb);
+ ret |= SETIREG(SISSR, 0x21, 0xa5);
+
+ if (ret == 0)
+ break;
+ }
+
+ return ret;
+}
+
+#undef SETREG
+#undef GETREG
+#undef SETIREG
+#undef GETIREG
+#undef SETIREGOR
+#undef SETIREGAND
+#undef SETIREGANDOR
+#undef READL
+#undef WRITEL
+
+static void
+sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
+{
+ u8 tmp8, tmp82, ramtype;
+ int bw = 0;
+ char *ramtypetext1 = NULL;
+ const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
+ "DDR SDRAM", "DDR SGRAM" };
+ static const int busSDR[4] = {64, 64, 128, 128};
+ static const int busDDR[4] = {32, 32, 64, 64};
+ static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
+
+ sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
+ sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
+ sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
+ sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
+ ramtype &= 0x03;
+ switch ((tmp8 >> 2) & 0x03) {
+ case 0: ramtypetext1 = "1 ch/1 r";
+ if (tmp82 & 0x10) {
+ bw = 32;
+ } else {
+ bw = busSDR[(tmp8 & 0x03)];
+ }
+ break;
+ case 1: ramtypetext1 = "1 ch/2 r";
+ sisusb->vramsize <<= 1;
+ bw = busSDR[(tmp8 & 0x03)];
+ break;
+ case 2: ramtypetext1 = "asymmeric";
+ sisusb->vramsize += sisusb->vramsize/2;
+ bw = busDDRA[(tmp8 & 0x03)];
+ break;
+ case 3: ramtypetext1 = "2 channel";
+ sisusb->vramsize <<= 1;
+ bw = busDDR[(tmp8 & 0x03)];
+ break;
+ }
+
+ printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
+ sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
+ ramtypetext2[ramtype], bw);
+}
+
+static int
+sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
+{
+ struct sisusb_packet packet;
+ int ret;
+ u32 tmp32;
+
+ /* Do some magic */
+ packet.header = 0x001f;
+ packet.address = 0x00000324;
+ packet.data = 0x00000004;
+ ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+ packet.header = 0x001f;
+ packet.address = 0x00000364;
+ packet.data = 0x00000004;
+ ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+ packet.header = 0x001f;
+ packet.address = 0x00000384;
+ packet.data = 0x00000004;
+ ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+ packet.header = 0x001f;
+ packet.address = 0x00000100;
+ packet.data = 0x00000700;
+ ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+ packet.header = 0x000f;
+ packet.address = 0x00000004;
+ ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
+ packet.data |= 0x17;
+ ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+ /* Init BAR 0 (VRAM) */
+ ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
+ ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
+ ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
+ tmp32 &= 0x0f;
+ tmp32 |= SISUSB_PCI_MEMBASE;
+ ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
+
+ /* Init BAR 1 (MMIO) */
+ ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
+ ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
+ ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
+ tmp32 &= 0x0f;
+ tmp32 |= SISUSB_PCI_MMIOBASE;
+ ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
+
+ /* Init BAR 2 (i/o ports) */
+ ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
+ ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
+ ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
+ tmp32 &= 0x0f;
+ tmp32 |= SISUSB_PCI_IOPORTBASE;
+ ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
+
+ /* Enable memory and i/o access */
+ ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
+ tmp32 |= 0x3;
+ ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
+
+ if (ret == 0) {
+ /* Some further magic */
+ packet.header = 0x001f;
+ packet.address = 0x00000050;
+ packet.data = 0x000000ff;
+ ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+ }
+
+ return ret;
+}
+
+/* Initialize the graphics device (return 0 on success)
+ * This initializes the net2280 as well as the PCI registers
+ * of the graphics board.
+ */
+
+static int
+sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
+{
+ int ret = 0, test = 0;
+ u32 tmp32;
+
+ if (sisusb->devinit == 1) {
+ /* Read PCI BARs and see if they have been set up */
+ ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
+ if (ret) return ret;
+ if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
+
+ ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
+ if (ret) return ret;
+ if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
+
+ ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
+ if (ret) return ret;
+ if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
+ }
+
+ /* No? So reset the device */
+ if ((sisusb->devinit == 0) || (test != 3)) {
+
+ ret |= sisusb_do_init_gfxdevice(sisusb);
+
+ if (ret == 0)
+ sisusb->devinit = 1;
+
+ }
+
+ if (sisusb->devinit) {
+ /* Initialize the graphics core */
+ if (sisusb_init_gfxcore(sisusb) == 0) {
+ sisusb->gfxinit = 1;
+ sisusb_get_ramconfig(sisusb);
+ ret |= sisusb_set_default_mode(sisusb, 1);
+ ret |= sisusb_setup_screen(sisusb, 1, initscreen);
+ }
+ }
+
+ return ret;
+}
+
+/* fops */
+
+int
+sisusb_open(struct inode *inode, struct file *file)
+{
+ struct sisusb_usb_data *sisusb;
+ struct usb_interface *interface;
+ int subminor = iminor(inode);
+
+ down(&disconnect_sem);
+
+ if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
+ printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
+ subminor);
+ up(&disconnect_sem);
+ return -ENODEV;
+ }
+
+ if (!(sisusb = usb_get_intfdata(interface))) {
+ up(&disconnect_sem);
+ return -ENODEV;
+ }
+
+ down(&sisusb->lock);
+
+ if (!sisusb->present || !sisusb->ready) {
+ up(&sisusb->lock);
+ up(&disconnect_sem);
+ return -ENODEV;
+ }
+
+ if (sisusb->isopen) {
+ up(&sisusb->lock);
+ up(&disconnect_sem);
+ return -EBUSY;
+ }
+
+ if (!sisusb->devinit) {
+ if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
+ if (sisusb_init_gfxdevice(sisusb, 0)) {
+ up(&sisusb->lock);
+ up(&disconnect_sem);
+ printk(KERN_ERR
+ "sisusbvga[%d]: Failed to initialize "
+ "device\n",
+ sisusb->minor);
+ return -EIO;
+ }
+ } else {
+ up(&sisusb->lock);
+ up(&disconnect_sem);
+ printk(KERN_ERR
+ "sisusbvga[%d]: Device not attached to "
+ "USB 2.0 hub\n",
+ sisusb->minor);
+ return -EIO;
+ }
+ }
+
+ /* increment usage count for the device */
+ kref_get(&sisusb->kref);
+
+ sisusb->isopen = 1;
+
+ file->private_data = sisusb;
+
+ up(&sisusb->lock);
+
+ up(&disconnect_sem);
+
+ printk(KERN_DEBUG "sisusbvga[%d]: opened", sisusb->minor);
+
+ return 0;
+}
+
+static void
+sisusb_delete(struct kref *kref)
+{
+ struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
+
+ if (!sisusb)
+ return;
+
+ if (sisusb->sisusb_dev)
+ usb_put_dev(sisusb->sisusb_dev);
+
+ sisusb->sisusb_dev = NULL;
+ sisusb_free_buffers(sisusb);
+ sisusb_free_urbs(sisusb);
+ kfree(sisusb);
+}
+
+int
+sisusb_release(struct inode *inode, struct file *file)
+{
+ struct sisusb_usb_data *sisusb;
+ int myminor;
+
+ down(&disconnect_sem);
+
+ if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
+ up(&disconnect_sem);
+ return -ENODEV;
+ }
+
+ down(&sisusb->lock);
+
+ if (sisusb->present) {
+ /* Wait for all URBs to finish if device still present */
+ if (!sisusb_wait_all_out_complete(sisusb))
+ sisusb_kill_all_busy(sisusb);
+ }
+
+ myminor = sisusb->minor;
+
+ sisusb->isopen = 0;
+ file->private_data = NULL;
+
+ up(&sisusb->lock);
+
+ /* decrement the usage count on our device */
+ kref_put(&sisusb->kref, sisusb_delete);
+
+ up(&disconnect_sem);
+
+ printk(KERN_DEBUG "sisusbvga[%d]: released", myminor);
+
+ return 0;
+}
+
+ssize_t
+sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+{
+ struct sisusb_usb_data *sisusb;
+ ssize_t bytes_read = 0;
+ int errno = 0;
+ u8 buf8;
+ u16 buf16;
+ u32 buf32, address;
+
+ if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
+ return -ENODEV;
+
+ down(&sisusb->lock);
+
+ /* Sanity check */
+ if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
+ up(&sisusb->lock);
+ return -ENODEV;
+ }
+
+ if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
+ (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
+
+ address = (*ppos) -
+ SISUSB_PCI_PSEUDO_IOPORTBASE +
+ SISUSB_PCI_IOPORTBASE;
+
+ /* Read i/o ports
+ * Byte, word and long(32) can be read. As this
+ * emulates inX instructions, the data returned is
+ * in machine-endianness.
+ */
+ switch (count) {
+
+ case 1:
+ if (sisusb_read_memio_byte(sisusb,
+ SISUSB_TYPE_IO,
+ address, &buf8))
+ errno = -EIO;
+ else if (put_user(buf8, (u8 __user *)buffer))
+ errno = -EFAULT;
+ else
+ bytes_read = 1;
+
+ break;
+
+ case 2:
+ if (sisusb_read_memio_word(sisusb,
+ SISUSB_TYPE_IO,
+ address, &buf16))
+ errno = -EIO;
+ else if (put_user(buf16, (u16 __user *)buffer))
+ errno = -EFAULT;
+ else
+ bytes_read = 2;
+
+ break;
+
+ case 4:
+ if (sisusb_read_memio_long(sisusb,
+ SISUSB_TYPE_IO,
+ address, &buf32))
+ errno = -EIO;
+ else if (put_user(buf32, (u32 __user *)buffer))
+ errno = -EFAULT;
+ else
+ bytes_read = 4;
+
+ break;
+
+ default:
+ errno = -EIO;
+
+ }
+
+ } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
+ (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
+
+ address = (*ppos) -
+ SISUSB_PCI_PSEUDO_MEMBASE +
+ SISUSB_PCI_MEMBASE;
+
+ /* Read video ram
+ * Remember: Data delivered is never endian-corrected
+ */
+ errno = sisusb_read_mem_bulk(sisusb, address,
+ NULL, count, buffer, &bytes_read);
+
+ if (bytes_read)
+ errno = bytes_read;
+
+ } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
+ (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
+
+ address = (*ppos) -
+ SISUSB_PCI_PSEUDO_MMIOBASE +
+ SISUSB_PCI_MMIOBASE;
+
+ /* Read MMIO
+ * Remember: Data delivered is never endian-corrected
+ */
+ errno = sisusb_read_mem_bulk(sisusb, address,
+ NULL, count, buffer, &bytes_read);
+
+ if (bytes_read)
+ errno = bytes_read;
+
+ } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
+ (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
+
+ if (count != 4) {
+ up(&sisusb->lock);
+ return -EINVAL;
+ }
+
+ address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
+
+ /* Read PCI config register
+ * Return value delivered in machine endianness.
+ */
+ if (sisusb_read_pci_config(sisusb, address, &buf32))
+ errno = -EIO;
+ else if (put_user(buf32, (u32 __user *)buffer))
+ errno = -EFAULT;
+ else
+ bytes_read = 4;
+
+ } else {
+
+ errno = -EBADFD;
+
+ }
+
+ (*ppos) += bytes_read;
+
+ up(&sisusb->lock);
+
+ return errno ? errno : bytes_read;
+}
+
+ssize_t
+sisusb_write(struct file *file, const char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct sisusb_usb_data *sisusb;
+ int errno = 0;
+ ssize_t bytes_written = 0;
+ u8 buf8;
+ u16 buf16;
+ u32 buf32, address;
+
+ if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
+ return -ENODEV;
+
+ down(&sisusb->lock);
+
+ /* Sanity check */
+ if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
+ up(&sisusb->lock);
+ return -ENODEV;
+ }
+
+ if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
+ (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
+
+ address = (*ppos) -
+ SISUSB_PCI_PSEUDO_IOPORTBASE +
+ SISUSB_PCI_IOPORTBASE;
+
+ /* Write i/o ports
+ * Byte, word and long(32) can be written. As this
+ * emulates outX instructions, the data is expected
+ * in machine-endianness.
+ */
+ switch (count) {
+
+ case 1:
+ if (get_user(buf8, (u8 __user *)buffer))
+ errno = -EFAULT;
+ else if (sisusb_write_memio_byte(sisusb,
+ SISUSB_TYPE_IO,
+ address, buf8))
+ errno = -EIO;
+ else
+ bytes_written = 1;
+
+ break;
+
+ case 2:
+ if (get_user(buf16, (u16 __user *)buffer))
+ errno = -EFAULT;
+ else if (sisusb_write_memio_word(sisusb,
+ SISUSB_TYPE_IO,
+ address, buf16))
+ errno = -EIO;
+ else
+ bytes_written = 2;
+
+ break;
+
+ case 4:
+ if (get_user(buf32, (u32 __user *)buffer))
+ errno = -EFAULT;
+ else if (sisusb_write_memio_long(sisusb,
+ SISUSB_TYPE_IO,
+ address, buf32))
+ errno = -EIO;
+ else
+ bytes_written = 4;
+
+ break;
+
+ default:
+ errno = -EIO;
+ }
+
+ } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
+ (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
+
+ address = (*ppos) -
+ SISUSB_PCI_PSEUDO_MEMBASE +
+ SISUSB_PCI_MEMBASE;
+
+ /* Write video ram.
+ * Buffer is copied 1:1, therefore, on big-endian
+ * machines, the data must be swapped by userland
+ * in advance (if applicable; no swapping in 8bpp
+ * mode or if YUV data is being transferred).
+ */
+ errno = sisusb_write_mem_bulk(sisusb, address, NULL,
+ count, buffer, 0, &bytes_written);
+
+ if (bytes_written)
+ errno = bytes_written;
+
+ } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
+ (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
+
+ address = (*ppos) -
+ SISUSB_PCI_PSEUDO_MMIOBASE +
+ SISUSB_PCI_MMIOBASE;
+
+ /* Write MMIO.
+ * Buffer is copied 1:1, therefore, on big-endian
+ * machines, the data must be swapped by userland
+ * in advance.
+ */
+ errno = sisusb_write_mem_bulk(sisusb, address, NULL,
+ count, buffer, 0, &bytes_written);
+
+ if (bytes_written)
+ errno = bytes_written;
+
+ } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
+ (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
+
+ if (count != 4) {
+ up(&sisusb->lock);
+ return -EINVAL;
+ }
+
+ address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
+
+ /* Write PCI config register.
+ * Given value expected in machine endianness.
+ */
+ if (get_user(buf32, (u32 __user *)buffer))
+ errno = -EFAULT;
+ else if (sisusb_write_pci_config(sisusb, address, buf32))
+ errno = -EIO;
+ else
+ bytes_written = 4;
+
+
+ } else {
+
+ /* Error */
+ errno = -EBADFD;
+
+ }
+
+ (*ppos) += bytes_written;
+
+ up(&sisusb->lock);
+
+ return errno ? errno : bytes_written;
+}
+
+static loff_t
+sisusb_lseek(struct file *file, loff_t offset, int orig)
+{
+ struct sisusb_usb_data *sisusb;
+ loff_t ret;
+
+ if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
+ return -ENODEV;
+
+ down(&sisusb->lock);
+
+ /* Sanity check */
+ if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
+ up(&sisusb->lock);
+ return -ENODEV;
+ }
+
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ ret = file->f_pos;
+ /* never negative, no force_successful_syscall needed */
+ break;
+ case 1:
+ file->f_pos += offset;
+ ret = file->f_pos;
+ /* never negative, no force_successful_syscall needed */
+ break;
+ default:
+ /* seeking relative to "end of file" is not supported */
+ ret = -EINVAL;
+ }
+
+ up(&sisusb->lock);
+ return ret;
+}
+
+static int
+sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
+ unsigned long arg)
+{
+ int retval, port, length;
+ u32 address;
+
+ port = y->data3 -
+ SISUSB_PCI_PSEUDO_IOPORTBASE +
+ SISUSB_PCI_IOPORTBASE;
+
+ switch (y->operation) {
+ case SUCMD_GET:
+ retval = sisusb_getidxreg(sisusb, port,
+ y->data0, &y->data1);
+ if (!retval) {
+ if (copy_to_user((void __user *)arg, y,
+ sizeof(*y)))
+ retval = -EFAULT;
+ }
+ break;
+
+ case SUCMD_SET:
+ retval = sisusb_setidxreg(sisusb, port,
+ y->data0, y->data1);
+ break;
+
+ case SUCMD_SETOR:
+ retval = sisusb_setidxregor(sisusb, port,
+ y->data0, y->data1);
+ break;
+
+ case SUCMD_SETAND:
+ retval = sisusb_setidxregand(sisusb, port,
+ y->data0, y->data1);
+ break;
+
+ case SUCMD_SETANDOR:
+ retval = sisusb_setidxregandor(sisusb, port,
+ y->data0, y->data1, y->data2);
+ break;
+
+ case SUCMD_SETMASK:
+ retval = sisusb_setidxregmask(sisusb, port,
+ y->data0, y->data1, y->data2);
+ break;
+
+ case SUCMD_CLRSCR:
+ length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
+ address = y->data3 -
+ SISUSB_PCI_PSEUDO_MEMBASE +
+ SISUSB_PCI_MEMBASE;
+ retval = sisusb_clear_vram(sisusb, address, length);
+ break;
+
+ default:
+ retval = -EINVAL;
+ }
+
+ if(retval > 0)
+ retval = -EIO;
+
+ return retval;
+}
+
+static int
+sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct sisusb_usb_data *sisusb;
+ struct sisusb_info x;
+ struct sisusb_command y;
+ int retval = 0;
+ u32 __user *argp = (u32 __user *)arg;
+
+ if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
+ return -ENODEV;
+
+ down(&sisusb->lock);
+
+ /* Sanity check */
+ if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
+ retval = -ENODEV;
+ goto err_out;
+ }
+
+ switch (cmd) {
+
+ case SISUSB_GET_CONFIG_SIZE:
+
+ if (put_user(sizeof(x), argp))
+ retval = -EFAULT;
+
+ break;
+
+ case SISUSB_GET_CONFIG:
+
+ x.sisusb_id = SISUSB_ID;
+ x.sisusb_version = SISUSB_VERSION;
+ x.sisusb_revision = SISUSB_REVISION;
+ x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
+ x.sisusb_gfxinit = sisusb->gfxinit;
+ x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
+ x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
+ x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
+ x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
+ x.sisusb_vramsize = sisusb->vramsize;
+ x.sisusb_minor = sisusb->minor;
+ x.sisusb_fbdevactive= 0;
+
+ if (copy_to_user((void __user *)arg, &x, sizeof(x)))
+ retval = -EFAULT;
+
+ break;
+
+ case SISUSB_COMMAND:
+
+ if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
+ retval = -EFAULT;
+ else
+ retval = sisusb_handle_command(sisusb, &y, arg);
+
+ break;
+
+ default:
+ retval = -EINVAL;
+ break;
+ }
+
+err_out:
+ up(&sisusb->lock);
+ return retval;
+}
+
+#ifdef SISUSB_NEW_CONFIG_COMPAT
+static long
+sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+ long retval;
+
+ switch (cmd) {
+ case SISUSB_GET_CONFIG_SIZE:
+ case SISUSB_GET_CONFIG:
+ case SISUSB_COMMAND:
+ lock_kernel();
+ retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
+ unlock_kernel();
+ return retval;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+#endif
+
+static struct file_operations usb_sisusb_fops = {
+ .owner = THIS_MODULE,
+ .open = sisusb_open,
+ .release = sisusb_release,
+ .read = sisusb_read,
+ .write = sisusb_write,
+ .llseek = sisusb_lseek,
+#ifdef SISUSB_NEW_CONFIG_COMPAT
+ .compat_ioctl = sisusb_compat_ioctl,
+#endif
+ .ioctl = sisusb_ioctl
+};
+
+static struct usb_class_driver usb_sisusb_class = {
+ .name = "usb/sisusbvga%d",
+ .fops = &usb_sisusb_fops,
+ .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+ .minor_base = SISUSB_MINOR
+};
+
+static int sisusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct sisusb_usb_data *sisusb;
+ int retval = 0, i;
+ const char *memfail =
+ KERN_ERR
+ "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
+
+ printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
+ dev->devnum);
+
+ /* Allocate memory for our private */
+ if (!(sisusb = kmalloc(sizeof(*sisusb), GFP_KERNEL))) {
+ printk(KERN_ERR
+ "sisusb: Failed to allocate memory for private data\n");
+ return -ENOMEM;
+ }
+ memset(sisusb, 0, sizeof(*sisusb));
+ kref_init(&sisusb->kref);
+
+ init_MUTEX(&(sisusb->lock));
+
+ /* Register device */
+ if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
+ printk(KERN_ERR
+ "sisusb: Failed to get a minor for device %d\n",
+ dev->devnum);
+ retval = -ENODEV;
+ goto error_1;
+ }
+
+ sisusb->sisusb_dev = dev;
+ sisusb->minor = intf->minor;
+ sisusb->vrambase = SISUSB_PCI_MEMBASE;
+ sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
+ sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
+ sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
+ /* Everything else is zero */
+
+ /* Allocate buffers */
+ sisusb->ibufsize = SISUSB_IBUF_SIZE;
+ if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
+ GFP_KERNEL, &sisusb->transfer_dma_in))) {
+ printk(memfail, "input", sisusb->minor);
+ retval = -ENOMEM;
+ goto error_2;
+ }
+
+ sisusb->numobufs = 0;
+ sisusb->obufsize = SISUSB_OBUF_SIZE;
+ for (i = 0; i < NUMOBUFS; i++) {
+ if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
+ GFP_KERNEL,
+ &sisusb->transfer_dma_out[i]))) {
+ if (i == 0) {
+ printk(memfail, "output", sisusb->minor);
+ retval = -ENOMEM;
+ goto error_3;
+ }
+ break;
+ } else
+ sisusb->numobufs++;
+
+ }
+
+ /* Allocate URBs */
+ if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
+ printk(KERN_ERR
+ "sisusbvga[%d]: Failed to allocate URBs\n",
+ sisusb->minor);
+ retval = -ENOMEM;
+ goto error_3;
+ }
+ sisusb->completein = 1;
+
+ for (i = 0; i < sisusb->numobufs; i++) {
+ if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
+ printk(KERN_ERR
+ "sisusbvga[%d]: Failed to allocate URBs\n",
+ sisusb->minor);
+ retval = -ENOMEM;
+ goto error_4;
+ }
+ sisusb->urbout_context[i].sisusb = (void *)sisusb;
+ sisusb->urbout_context[i].urbindex = i;
+ sisusb->urbstatus[i] = 0;
+ }
+
+ printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
+ sisusb->minor, sisusb->numobufs);
+
+ /* Do remaining init stuff */
+
+ init_waitqueue_head(&sisusb->wait_q);
+
+ usb_set_intfdata(intf, sisusb);
+
+#ifdef SISUSB_OLD_CONFIG_COMPAT
+ {
+ int ret;
+ /* Our ioctls are all "32/64bit compatible" */
+ ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
+ ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
+ ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
+ if (ret)
+ printk(KERN_ERR
+ "sisusbvga[%d]: Error registering ioctl32 "
+ "translations\n",
+ sisusb->minor);
+ else
+ sisusb->ioctl32registered = 1;
+
+ }
+#endif
+
+ sisusb->present = 1;
+
+ if (dev->speed == USB_SPEED_HIGH) {
+ if (sisusb_init_gfxdevice(sisusb, 1))
+ printk(KERN_ERR
+ "sisusbvga[%d]: Failed to early "
+ "initialize device\n",
+ sisusb->minor);
+
+ } else
+ printk(KERN_INFO
+ "sisusbvga[%d]: Not attached to USB 2.0 hub, "
+ "deferring init\n",
+ sisusb->minor);
+
+ sisusb->ready = 1;
+
+ return 0;
+
+error_4:
+ sisusb_free_urbs(sisusb);
+error_3:
+ sisusb_free_buffers(sisusb);
+error_2:
+ usb_deregister_dev(intf, &usb_sisusb_class);
+error_1:
+ kfree(sisusb);
+ return retval;
+}
+
+static void sisusb_disconnect(struct usb_interface *intf)
+{
+ struct sisusb_usb_data *sisusb;
+ int minor;
+
+ down(&disconnect_sem);
+
+ /* This should *not* happen */
+ if (!(sisusb = usb_get_intfdata(intf))) {
+ up(&disconnect_sem);
+ return;
+ }
+
+ down(&sisusb->lock);
+
+ /* Wait for all URBs to complete and kill them in case (MUST do) */
+ if (!sisusb_wait_all_out_complete(sisusb))
+ sisusb_kill_all_busy(sisusb);
+
+ minor = sisusb->minor;
+
+ usb_set_intfdata(intf, NULL);
+
+ usb_deregister_dev(intf, &usb_sisusb_class);
+
+#ifdef SISUSB_OLD_CONFIG_COMPAT
+ if (sisusb->ioctl32registered) {
+ int ret;
+ sisusb->ioctl32registered = 0;
+ ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
+ ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
+ ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
+ if (ret) {
+ printk(KERN_ERR
+ "sisusbvga[%d]: Error unregistering "
+ "ioctl32 translations\n",
+ minor);
+ }
+ }
+#endif
+
+ sisusb->present = 0;
+ sisusb->ready = 0;
+
+ up(&sisusb->lock);
+
+ /* decrement our usage count */
+ kref_put(&sisusb->kref, sisusb_delete);
+
+ up(&disconnect_sem);
+
+ printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
+}
+
+static struct usb_device_id sisusb_table [] = {
+ { USB_DEVICE(0x0711, 0x0900) },
+ { }
+};
+
+MODULE_DEVICE_TABLE (usb, sisusb_table);
+
+static struct usb_driver sisusb_driver = {
+ .owner = THIS_MODULE,
+ .name = "sisusb",
+ .probe = sisusb_probe,
+ .disconnect = sisusb_disconnect,
+ .id_table = sisusb_table
+};
+
+static int __init usb_sisusb_init(void)
+{
+ int retval;
+
+ if (!(retval = usb_register(&sisusb_driver))) {
+ printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
+ SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
+ printk(KERN_INFO
+ "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
+ }
+
+ return retval;
+}
+
+static void __exit usb_sisusb_exit(void)
+{
+ usb_deregister(&sisusb_driver);
+}
+
+module_init(usb_sisusb_init);
+module_exit(usb_sisusb_exit);
+
+MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
+MODULE_DESCRIPTION("sisusb - Driver for Net2280/SiS315-based USB2VGA dongles");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
new file mode 100644
index 000000000000..1306d006a25a
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -0,0 +1,278 @@
+/*
+ * sisusb - usb kernel driver for Net2280/SiS315 based USB2VGA dongles
+ *
+ * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, this code is licensed under the
+ * terms of the GPL v2.
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * * notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * * notice, this list of conditions and the following disclaimer in the
+ * * documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * * derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifndef _SISUSB_H_
+#define _SISUSB_H_
+
+#ifdef CONFIG_COMPAT
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
+#include <linux/ioctl32.h>
+#define SISUSB_OLD_CONFIG_COMPAT
+#else
+#define SISUSB_NEW_CONFIG_COMPAT
+#endif
+#endif
+
+/* Version Information */
+
+#define SISUSB_VERSION 0
+#define SISUSB_REVISION 0
+#define SISUSB_PATCHLEVEL 7
+
+/* USB related */
+
+#define SISUSB_MINOR 133 /* FIXME */
+
+/* Size of the sisusb input/output buffers */
+#define SISUSB_IBUF_SIZE 0x01000
+#define SISUSB_OBUF_SIZE 0x10000 /* fixed */
+
+#define NUMOBUFS 8 /* max number of output buffers/output URBs */
+
+/* About endianness:
+ *
+ * 1) I/O ports, PCI config registers. The read/write()
+ * calls emulate inX/outX. Hence, the data is
+ * expected/delivered in machine endiannes by this
+ * driver.
+ * 2) Video memory. The data is copied 1:1. There is
+ * no swapping. Ever. This means for userland that
+ * the data has to be prepared properly. (Hint:
+ * think graphics data format, command queue,
+ * hardware cursor.)
+ * 3) MMIO. Data is copied 1:1. MMIO must be swapped
+ * properly by userland.
+ *
+ */
+
+#ifdef __BIG_ENDIAN
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \
+ do { \
+ p->header = cpu_to_le16(p->header); \
+ p->address = cpu_to_le32(p->address); \
+ p->data = cpu_to_le32(p->data); \
+ } while(0)
+#else
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)
+#endif
+
+struct sisusb_usb_data;
+
+struct sisusb_urb_context { /* urb->context for outbound bulk URBs */
+ struct sisusb_usb_data *sisusb;
+ int urbindex;
+ int *actual_length;
+};
+
+struct sisusb_usb_data {
+ struct usb_device *sisusb_dev;
+ struct usb_interface *interface;
+ struct kref kref;
+ wait_queue_head_t wait_q; /* for syncind and timeouts */
+ struct semaphore lock; /* general race avoidance */
+ unsigned int ifnum; /* interface number of the USB device */
+ int minor; /* minor (for logging clarity) */
+ int isopen; /* !=0 if open */
+ int present; /* !=0 if device is present on the bus */
+ int ready; /* !=0 if device is ready for userland */
+#ifdef SISUSB_OLD_CONFIG_COMPAT
+ int ioctl32registered;
+#endif
+ int numobufs; /* number of obufs = number of out urbs */
+ char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */
+ int obufsize, ibufsize;
+ dma_addr_t transfer_dma_out[NUMOBUFS];
+ dma_addr_t transfer_dma_in;
+ struct urb *sisurbout[NUMOBUFS];
+ struct urb *sisurbin;
+ unsigned char urbstatus[NUMOBUFS];
+ unsigned char completein;
+ struct sisusb_urb_context urbout_context[NUMOBUFS];
+ unsigned long flagb0;
+ unsigned long vrambase; /* framebuffer base */
+ unsigned int vramsize; /* framebuffer size (bytes) */
+ unsigned long mmiobase;
+ unsigned int mmiosize;
+ unsigned long ioportbase;
+ unsigned char devinit; /* device initialized? */
+ unsigned char gfxinit; /* graphics core initialized? */
+ unsigned short chipid, chipvendor;
+ unsigned short chiprevision;
+};
+
+#define to_sisusb_dev(d) container_of(d, struct sisusb_usb_data, kref)
+
+/* USB transport related */
+
+/* urbstatus */
+#define SU_URB_BUSY 1
+#define SU_URB_ALLOC 2
+
+/* Endpoints */
+
+#define SISUSB_EP_GFX_IN 0x0e /* gfx std packet out(0e)/in(8e) */
+#define SISUSB_EP_GFX_OUT 0x0e
+
+#define SISUSB_EP_GFX_BULK_OUT 0x01 /* gfx mem bulk out/in */
+#define SISUSB_EP_GFX_BULK_IN 0x02 /* ? 2 is "OUT" ? */
+
+#define SISUSB_EP_GFX_LBULK_OUT 0x03 /* gfx large mem bulk out */
+
+#define SISUSB_EP_UNKNOWN_04 0x04 /* ? 4 is "OUT" ? - unused */
+
+#define SISUSB_EP_BRIDGE_IN 0x0d /* Net2280 out(0d)/in(8d) */
+#define SISUSB_EP_BRIDGE_OUT 0x0d
+
+#define SISUSB_TYPE_MEM 0
+#define SISUSB_TYPE_IO 1
+
+struct sisusb_packet {
+ unsigned short header;
+ u32 address;
+ u32 data;
+} __attribute__((__packed__));
+
+#define CLEARPACKET(packet) memset(packet, 0, 10)
+
+/* PCI bridge related */
+
+#define SISUSB_PCI_MEMBASE 0xd0000000
+#define SISUSB_PCI_MMIOBASE 0xe4000000
+#define SISUSB_PCI_IOPORTBASE 0x0000d000
+
+#define SISUSB_PCI_PSEUDO_MEMBASE 0x10000000
+#define SISUSB_PCI_PSEUDO_MMIOBASE 0x20000000
+#define SISUSB_PCI_PSEUDO_IOPORTBASE 0x0000d000
+#define SISUSB_PCI_PSEUDO_PCIBASE 0x00010000
+
+#define SISUSB_PCI_MMIOSIZE (128*1024)
+#define SISUSB_PCI_PCONFSIZE 0x5c
+
+/* graphics core related */
+
+#define AROFFSET 0x40
+#define ARROFFSET 0x41
+#define GROFFSET 0x4e
+#define SROFFSET 0x44
+#define CROFFSET 0x54
+#define MISCROFFSET 0x4c
+#define MISCWOFFSET 0x42
+#define INPUTSTATOFFSET 0x5A
+#define PART1OFFSET 0x04
+#define PART2OFFSET 0x10
+#define PART3OFFSET 0x12
+#define PART4OFFSET 0x14
+#define PART5OFFSET 0x16
+#define CAPTUREOFFSET 0x00
+#define VIDEOOFFSET 0x02
+#define COLREGOFFSET 0x48
+#define PELMASKOFFSET 0x46
+#define VGAENABLE 0x43
+
+#define SISAR SISUSB_PCI_IOPORTBASE + AROFFSET
+#define SISARR SISUSB_PCI_IOPORTBASE + ARROFFSET
+#define SISGR SISUSB_PCI_IOPORTBASE + GROFFSET
+#define SISSR SISUSB_PCI_IOPORTBASE + SROFFSET
+#define SISCR SISUSB_PCI_IOPORTBASE + CROFFSET
+#define SISMISCR SISUSB_PCI_IOPORTBASE + MISCROFFSET
+#define SISMISCW SISUSB_PCI_IOPORTBASE + MISCWOFFSET
+#define SISINPSTAT SISUSB_PCI_IOPORTBASE + INPUTSTATOFFSET
+#define SISPART1 SISUSB_PCI_IOPORTBASE + PART1OFFSET
+#define SISPART2 SISUSB_PCI_IOPORTBASE + PART2OFFSET
+#define SISPART3 SISUSB_PCI_IOPORTBASE + PART3OFFSET
+#define SISPART4 SISUSB_PCI_IOPORTBASE + PART4OFFSET
+#define SISPART5 SISUSB_PCI_IOPORTBASE + PART5OFFSET
+#define SISCAP SISUSB_PCI_IOPORTBASE + CAPTUREOFFSET
+#define SISVID SISUSB_PCI_IOPORTBASE + VIDEOOFFSET
+#define SISCOLIDXR SISUSB_PCI_IOPORTBASE + COLREGOFFSET - 1
+#define SISCOLIDX SISUSB_PCI_IOPORTBASE + COLREGOFFSET
+#define SISCOLDATA SISUSB_PCI_IOPORTBASE + COLREGOFFSET + 1
+#define SISCOL2IDX SISPART5
+#define SISCOL2DATA SISPART5 + 1
+#define SISPEL SISUSB_PCI_IOPORTBASE + PELMASKOFFSET
+#define SISVGAEN SISUSB_PCI_IOPORTBASE + VGAENABLE
+#define SISDACA SISCOLIDX
+#define SISDACD SISCOLDATA
+
+/* ioctl related */
+
+/* Structure argument for SISUSB_GET_INFO ioctl */
+struct sisusb_info {
+ __u32 sisusb_id; /* for identifying sisusb */
+#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */
+ __u8 sisusb_version;
+ __u8 sisusb_revision;
+ __u8 sisusb_patchlevel;
+ __u8 sisusb_gfxinit; /* graphics core initialized? */
+
+ __u32 sisusb_vrambase;
+ __u32 sisusb_mmiobase;
+ __u32 sisusb_iobase;
+ __u32 sisusb_pcibase;
+
+ __u32 sisusb_vramsize; /* framebuffer size in bytes */
+
+ __u32 sisusb_minor;
+
+ __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
+
+ __u8 sisusb_reserved[32]; /* for future use */
+};
+
+struct sisusb_command {
+ __u8 operation; /* see below */
+ __u8 data0; /* operation dependent */
+ __u8 data1; /* operation dependent */
+ __u8 data2; /* operation dependent */
+ __u32 data3; /* operation dependent */
+ __u32 data4; /* for future use */
+};
+
+#define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */
+#define SUCMD_SET 0x02 /* data1 = value */
+#define SUCMD_SETOR 0x03 /* data1 = or */
+#define SUCMD_SETAND 0x04 /* data1 = and */
+#define SUCMD_SETANDOR 0x05 /* data1 = and, data2 = or */
+#define SUCMD_SETMASK 0x06 /* data1 = data, data2 = mask */
+
+#define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */
+
+#define SISUSB_COMMAND _IOWR(0xF3,0x3D,struct sisusb_command)
+#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32)
+#define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info)
+
+#endif /* SISUSB_H */
+
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index da8a43830a82..4297f4e133e0 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -144,7 +144,7 @@ write_lcd(struct file *file, const char __user *buffer,
result = usb_bulk_msg(lcd->lcd_dev,
usb_sndbulkpipe(lcd->lcd_dev, 1),
- obuf, thistime, &partial, 10 * HZ);
+ obuf, thistime, &partial, 10000);
dbg("write stats: result:%d thistime:%lu partial:%u",
result, thistime, partial);
@@ -203,7 +203,7 @@ read_lcd(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
result = usb_bulk_msg(lcd->lcd_dev,
usb_rcvbulkpipe(lcd->lcd_dev, 0),
ibuf, this_read, &partial,
- (int) (HZ * 8));
+ 8000);
dbg(KERN_DEBUG "read stats: result:%d this_read:%u partial:%u",
result, this_read, partial);
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
index 4f8bd56352b7..ee329d5e1c5e 100644
--- a/drivers/usb/misc/usbled.c
+++ b/drivers/usb/misc/usbled.c
@@ -74,7 +74,7 @@ static void change_color(struct usb_led *led)
(0x00 * 0x100) + color,
buffer,
8,
- 2 * HZ);
+ 2000);
if (retval)
dev_dbg(&led->udev->dev, "retval = %d\n", retval);
kfree(buffer);
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 38eb2993fc3c..0928ffc990d7 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -472,7 +472,7 @@ static int get_altsetting (struct usbtest_dev *dev)
retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0),
USB_REQ_GET_INTERFACE, USB_DIR_IN|USB_RECIP_INTERFACE,
0, iface->altsetting [0].desc.bInterfaceNumber,
- dev->buf, 1, HZ * USB_CTRL_GET_TIMEOUT);
+ dev->buf, 1, USB_CTRL_GET_TIMEOUT);
switch (retval) {
case 1:
return dev->buf [0];
@@ -602,7 +602,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0),
USB_REQ_GET_CONFIGURATION,
USB_DIR_IN | USB_RECIP_DEVICE,
- 0, 0, dev->buf, 1, HZ * USB_CTRL_GET_TIMEOUT);
+ 0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);
if (retval != 1 || dev->buf [0] != expected) {
dev_dbg (&iface->dev,
"get config --> %d (%d)\n", retval,
@@ -1173,7 +1173,7 @@ static int test_halt (int ep, struct urb *urb)
retval = usb_control_msg (urb->dev, usb_sndctrlpipe (urb->dev, 0),
USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT,
USB_ENDPOINT_HALT, ep,
- NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval < 0) {
dbg ("ep %02x couldn't set halt, %d", ep, retval);
return retval;
@@ -1263,7 +1263,7 @@ static int ctrl_out (struct usbtest_dev *dev,
buf [j] = i + j;
retval = usb_control_msg (udev, usb_sndctrlpipe (udev,0),
0x5b, USB_DIR_OUT|USB_TYPE_VENDOR,
- 0, 0, buf, len, HZ * USB_CTRL_SET_TIMEOUT);
+ 0, 0, buf, len, USB_CTRL_SET_TIMEOUT);
if (retval != len) {
what = "write";
break;
@@ -1272,7 +1272,7 @@ static int ctrl_out (struct usbtest_dev *dev,
/* read it back -- assuming nothing intervened!! */
retval = usb_control_msg (udev, usb_rcvctrlpipe (udev,0),
0x5c, USB_DIR_IN|USB_TYPE_VENDOR,
- 0, 0, buf, len, HZ * USB_CTRL_GET_TIMEOUT);
+ 0, 0, buf, len, USB_CTRL_GET_TIMEOUT);
if (retval != len) {
what = "read";
break;
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index de91f8bafe62..faa74436de52 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -75,7 +75,7 @@ static int get_1284_register(struct parport *pp, unsigned char reg, unsigned cha
if (!usbdev)
return -1;
- ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), 3, 0xc0, ((unsigned int)reg) << 8, 0, priv->reg, 7, HZ);
+ ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), 3, 0xc0, ((unsigned int)reg) << 8, 0, priv->reg, 7, 1000);
if (ret != 7) {
printk(KERN_DEBUG "uss720: get_1284_register(%d) failed, status 0x%x expected 7\n",
(unsigned int)reg, ret);
@@ -105,7 +105,7 @@ static int set_1284_register(struct parport *pp, unsigned char reg, unsigned cha
if (!usbdev)
return -1;
- ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev,0), 4, 0x40, (((unsigned int)reg) << 8) | val, 0, NULL, 0, HZ);
+ ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev,0), 4, 0x40, (((unsigned int)reg) << 8) | val, 0, NULL, 0, 1000);
if (ret) {
printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x) failed, status 0x%x\n",
(unsigned int)reg, (unsigned int)val, ret);
@@ -374,7 +374,7 @@ static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf,
return 0;
if (change_mode(pp, ECR_EPP))
return 0;
- i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buf, length, &rlen, HZ*20);
+ i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buf, length, &rlen, 20000);
if (i)
printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buf, length, rlen);
change_mode(pp, ECR_PS2);
@@ -435,7 +435,7 @@ static size_t parport_uss720_ecp_write_data(struct parport *pp, const void *buff
return 0;
if (change_mode(pp, ECR_ECP))
return 0;
- i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, HZ*20);
+ i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, 20000);
if (i)
printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buffer, len, rlen);
change_mode(pp, ECR_PS2);
@@ -453,7 +453,7 @@ static size_t parport_uss720_ecp_read_data(struct parport *pp, void *buffer, siz
return 0;
if (change_mode(pp, ECR_ECP))
return 0;
- i = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen, HZ*20);
+ i = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen, 20000);
if (i)
printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %Zu rlen %u\n", buffer, len, rlen);
change_mode(pp, ECR_PS2);
@@ -486,7 +486,7 @@ static size_t parport_uss720_write_compat(struct parport *pp, const void *buffer
return 0;
if (change_mode(pp, ECR_PPF))
return 0;
- i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, HZ*20);
+ i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, 20000);
if (i)
printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buffer, len, rlen);
change_mode(pp, ECR_PS2);
diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig
new file mode 100644
index 000000000000..4e6152aa5f19
--- /dev/null
+++ b/drivers/usb/mon/Kconfig
@@ -0,0 +1,22 @@
+#
+# USB Monitor configuration
+#
+
+# In normal life, it makes little sense to have usbmon as a module, and in fact
+# it is harmful, because there is no way to autoload the module.
+# The 'm' option is allowed for hackers who debug the usbmon itself,
+# and for those who have usbcore as a module.
+config USB_MON
+ tristate "USB Monitor"
+ depends on USB
+ default y
+ help
+ If you say Y here, a component which captures the USB traffic
+ between peripheral-specific drivers and HC drivers will be built.
+ The USB_MON is similar in spirit and may be compatible with Dave
+ Harding's USBMon.
+
+ This is somewhat experimental at this time, but it should be safe,
+ as long as you aren't building this as a module and then removing it.
+
+ If unsure, say Y. Do not say M.
diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile
new file mode 100644
index 000000000000..3cff8d444bb1
--- /dev/null
+++ b/drivers/usb/mon/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for USB Core files and filesystem
+#
+
+usbmon-objs := mon_main.o mon_stat.o mon_text.o
+
+obj-$(CONFIG_USB_MON) += usbmon.o
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
new file mode 100644
index 000000000000..aa9d00808e4e
--- /dev/null
+++ b/drivers/usb/mon/mon_main.c
@@ -0,0 +1,377 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * mon_main.c: Main file, module initiation and exit, registrations, etc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/debugfs.h>
+#include <linux/smp_lock.h>
+
+#include "usb_mon.h"
+#include "../core/hcd.h"
+
+static void mon_submit(struct usb_bus *ubus, struct urb *urb);
+static void mon_complete(struct usb_bus *ubus, struct urb *urb);
+static void mon_stop(struct mon_bus *mbus);
+static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
+static void mon_bus_drop(struct kref *r);
+static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
+
+DECLARE_MUTEX(mon_lock);
+
+static struct dentry *mon_dir; /* /dbg/usbmon */
+static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */
+
+/*
+ * Link a reader into the bus.
+ *
+ * This must be called with mon_lock taken because of mbus->ref.
+ */
+void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r)
+{
+ unsigned long flags;
+ struct usb_bus *ubus;
+
+ spin_lock_irqsave(&mbus->lock, flags);
+ if (mbus->nreaders == 0) {
+ ubus = mbus->u_bus;
+ if (ubus->monitored) {
+ /*
+ * Something is really broken, refuse to go on and
+ * possibly corrupt ops pointers or worse.
+ */
+ printk(KERN_ERR TAG ": bus %d is already monitored\n",
+ ubus->busnum);
+ spin_unlock_irqrestore(&mbus->lock, flags);
+ return;
+ }
+ ubus->monitored = 1;
+ }
+ mbus->nreaders++;
+ list_add_tail(&r->r_link, &mbus->r_list);
+ spin_unlock_irqrestore(&mbus->lock, flags);
+
+ kref_get(&mbus->ref);
+}
+
+/*
+ * Unlink reader from the bus.
+ *
+ * This is called with mon_lock taken, so we can decrement mbus->ref.
+ */
+void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mbus->lock, flags);
+ list_del(&r->r_link);
+ --mbus->nreaders;
+ if (mbus->nreaders == 0)
+ mon_stop(mbus);
+ spin_unlock_irqrestore(&mbus->lock, flags);
+
+ kref_put(&mbus->ref, mon_bus_drop);
+}
+
+/*
+ */
+static void mon_submit(struct usb_bus *ubus, struct urb *urb)
+{
+ struct mon_bus *mbus;
+ unsigned long flags;
+ struct list_head *pos;
+ struct mon_reader *r;
+
+ mbus = ubus->mon_bus;
+ if (mbus == NULL)
+ goto out_unlocked;
+
+ spin_lock_irqsave(&mbus->lock, flags);
+ if (mbus->nreaders == 0)
+ goto out_locked;
+
+ list_for_each (pos, &mbus->r_list) {
+ r = list_entry(pos, struct mon_reader, r_link);
+ r->rnf_submit(r->r_data, urb);
+ }
+
+ spin_unlock_irqrestore(&mbus->lock, flags);
+ return;
+
+out_locked:
+ spin_unlock_irqrestore(&mbus->lock, flags);
+out_unlocked:
+ return;
+}
+
+/*
+ */
+static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int err)
+{
+ struct mon_bus *mbus;
+
+ mbus = ubus->mon_bus;
+ if (mbus == NULL)
+ goto out_unlocked;
+
+ /*
+ * XXX Capture the error code and the 'E' event.
+ */
+
+ return;
+
+out_unlocked:
+ return;
+}
+
+/*
+ */
+static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+{
+ struct mon_bus *mbus;
+ unsigned long flags;
+ struct list_head *pos;
+ struct mon_reader *r;
+
+ mbus = ubus->mon_bus;
+ if (mbus == NULL) {
+ /*
+ * This should not happen.
+ * At this point we do not even know the bus number...
+ */
+ printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
+ urb->pipe);
+ return;
+ }
+
+ spin_lock_irqsave(&mbus->lock, flags);
+ list_for_each (pos, &mbus->r_list) {
+ r = list_entry(pos, struct mon_reader, r_link);
+ r->rnf_complete(r->r_data, urb);
+ }
+ spin_unlock_irqrestore(&mbus->lock, flags);
+}
+
+/* int (*unlink_urb) (struct urb *urb, int status); */
+
+/*
+ * Stop monitoring.
+ * Obviously this must be well locked, so no need to play with mb's.
+ */
+static void mon_stop(struct mon_bus *mbus)
+{
+ struct usb_bus *ubus = mbus->u_bus;
+
+ /*
+ * A stop can be called for a dissolved mon_bus in case of
+ * a reader staying across an rmmod foo_hcd.
+ */
+ if (ubus != NULL) {
+ ubus->monitored = 0;
+ mb();
+ }
+}
+
+/*
+ * Add a USB bus (usually by a modprobe foo-hcd)
+ *
+ * This does not return an error code because the core cannot care less
+ * if monitoring is not established.
+ */
+static void mon_bus_add(struct usb_bus *ubus)
+{
+ mon_bus_init(mon_dir, ubus);
+}
+
+/*
+ * Remove a USB bus (either from rmmod foo-hcd or from a hot-remove event).
+ */
+static void mon_bus_remove(struct usb_bus *ubus)
+{
+ struct mon_bus *mbus = ubus->mon_bus;
+
+ down(&mon_lock);
+ list_del(&mbus->bus_link);
+ debugfs_remove(mbus->dent_t);
+ debugfs_remove(mbus->dent_s);
+
+ mon_dissolve(mbus, ubus);
+ kref_put(&mbus->ref, mon_bus_drop);
+ up(&mon_lock);
+}
+
+/*
+ * Ops
+ */
+static struct usb_mon_operations mon_ops_0 = {
+ .urb_submit = mon_submit,
+ .urb_submit_error = mon_submit_error,
+ .urb_complete = mon_complete,
+ .bus_add = mon_bus_add,
+ .bus_remove = mon_bus_remove,
+};
+
+/*
+ * Tear usb_bus and mon_bus apart.
+ */
+static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
+{
+
+ /*
+ * Never happens, but...
+ */
+ if (ubus->monitored) {
+ printk(KERN_ERR TAG ": bus %d is dissolved while monitored\n",
+ ubus->busnum);
+ ubus->monitored = 0;
+ mb();
+ }
+
+ ubus->mon_bus = NULL;
+ mbus->u_bus = NULL;
+ mb();
+ // usb_bus_put(ubus);
+}
+
+/*
+ */
+static void mon_bus_drop(struct kref *r)
+{
+ struct mon_bus *mbus = container_of(r, struct mon_bus, ref);
+ kfree(mbus);
+}
+
+/*
+ * Initialize a bus for us:
+ * - allocate mon_bus
+ * - refcount USB bus struct
+ * - link
+ */
+static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
+{
+ struct dentry *d;
+ struct mon_bus *mbus;
+ enum { NAMESZ = 10 };
+ char name[NAMESZ];
+ int rc;
+
+ if ((mbus = kmalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
+ goto err_alloc;
+ memset(mbus, 0, sizeof(struct mon_bus));
+ kref_init(&mbus->ref);
+ spin_lock_init(&mbus->lock);
+ INIT_LIST_HEAD(&mbus->r_list);
+
+ /*
+ * This usb_bus_get here is superfluous, because we receive
+ * a notification if usb_bus is about to be removed.
+ */
+ // usb_bus_get(ubus);
+ mbus->u_bus = ubus;
+ ubus->mon_bus = mbus;
+
+ rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+ if (rc <= 0 || rc >= NAMESZ)
+ goto err_print_t;
+ d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
+ if (d == NULL)
+ goto err_create_t;
+ mbus->dent_t = d;
+
+ rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
+ if (rc <= 0 || rc >= NAMESZ)
+ goto err_print_s;
+ d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
+ if (d == NULL)
+ goto err_create_s;
+ mbus->dent_s = d;
+
+ down(&mon_lock);
+ list_add_tail(&mbus->bus_link, &mon_buses);
+ up(&mon_lock);
+ return;
+
+err_create_s:
+err_print_s:
+ debugfs_remove(mbus->dent_t);
+err_create_t:
+err_print_t:
+ kfree(mbus);
+err_alloc:
+ return;
+}
+
+static int __init mon_init(void)
+{
+ struct usb_bus *ubus;
+ struct dentry *mondir;
+
+ mondir = debugfs_create_dir("usbmon", NULL);
+ if (IS_ERR(mondir)) {
+ printk(KERN_NOTICE TAG ": debugs is not available\n");
+ return -ENODEV;
+ }
+ if (mondir == NULL) {
+ printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
+ return -ENODEV;
+ }
+ mon_dir = mondir;
+
+ if (usb_mon_register(&mon_ops_0) != 0) {
+ printk(KERN_NOTICE TAG ": unable to register with the core\n");
+ debugfs_remove(mondir);
+ return -ENODEV;
+ }
+ // MOD_INC_USE_COUNT(which_module?);
+
+ down(&usb_bus_list_lock);
+ list_for_each_entry (ubus, &usb_bus_list, bus_list) {
+ mon_bus_init(mondir, ubus);
+ }
+ up(&usb_bus_list_lock);
+ return 0;
+}
+
+static void __exit mon_exit(void)
+{
+ struct mon_bus *mbus;
+ struct list_head *p;
+
+ usb_mon_deregister();
+
+ down(&mon_lock);
+ while (!list_empty(&mon_buses)) {
+ p = mon_buses.next;
+ mbus = list_entry(p, struct mon_bus, bus_link);
+ list_del(p);
+
+ debugfs_remove(mbus->dent_t);
+ debugfs_remove(mbus->dent_s);
+
+ /*
+ * This never happens, because the open/close paths in
+ * file level maintain module use counters and so rmmod fails
+ * before reaching here. However, better be safe...
+ */
+ if (mbus->nreaders) {
+ printk(KERN_ERR TAG
+ ": Outstanding opens (%d) on usb%d, leaking...\n",
+ mbus->nreaders, mbus->u_bus->busnum);
+ atomic_set(&mbus->ref.refcount, 2); /* Force leak */
+ }
+
+ mon_dissolve(mbus, mbus->u_bus);
+ kref_put(&mbus->ref, mon_bus_drop);
+ }
+ up(&mon_lock);
+
+ debugfs_remove(mon_dir);
+}
+
+module_init(mon_init);
+module_exit(mon_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c
new file mode 100644
index 000000000000..6e4b165d070a
--- /dev/null
+++ b/drivers/usb/mon/mon_stat.c
@@ -0,0 +1,74 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is the 's' or 'stat' reader which debugs usbmon itself.
+ * Note that this code blows through locks, so make sure that
+ * /dbg/usbmon/0s is well protected from non-root users.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+#define STAT_BUF_SIZE 80
+
+struct snap {
+ int slen;
+ char str[STAT_BUF_SIZE];
+};
+
+static int mon_stat_open(struct inode *inode, struct file *file)
+{
+ struct mon_bus *mbus;
+ struct snap *sp;
+
+ if ((sp = kmalloc(sizeof(struct snap), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ mbus = inode->u.generic_ip;
+
+ sp->slen = snprintf(sp->str, STAT_BUF_SIZE,
+ "nreaders %d text_lost %u\n",
+ mbus->nreaders, mbus->cnt_text_lost);
+
+ file->private_data = sp;
+ return 0;
+}
+
+static ssize_t mon_stat_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct snap *sp = file->private_data;
+ loff_t pos = *ppos;
+ int cnt;
+
+ if (pos < 0 || pos >= sp->slen)
+ return 0;
+ if (nbytes == 0)
+ return 0;
+ if ((cnt = sp->slen - pos) > nbytes)
+ cnt = nbytes;
+ if (copy_to_user(buf, sp->str + pos, cnt))
+ return -EFAULT;
+ *ppos = pos + cnt;
+ return cnt;
+}
+
+static int mon_stat_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+struct file_operations mon_fops_stat = {
+ .owner = THIS_MODULE,
+ .open = mon_stat_open,
+ .llseek = no_llseek,
+ .read = mon_stat_read,
+ /* .write = mon_stat_write, */
+ /* .poll = mon_stat_poll, */
+ /* .ioctl = mon_stat_ioctl, */
+ .release = mon_stat_release,
+};
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
new file mode 100644
index 000000000000..8eff8f92c15f
--- /dev/null
+++ b/drivers/usb/mon/mon_text.c
@@ -0,0 +1,395 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is a text format reader.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/time.h>
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+/*
+ * No, we do not want arbitrarily long data strings.
+ * Use the binary interface if you want to capture bulk data!
+ */
+#define DATA_MAX 32
+
+/*
+ * This limit exists to prevent OOMs when the user process stops reading.
+ */
+#define EVENT_MAX 25
+
+#define PRINTF_DFL 120
+
+struct mon_event_text {
+ struct list_head e_link;
+ int type; /* submit, complete, etc. */
+ unsigned int pipe; /* Pipe */
+ unsigned long id; /* From pointer, most of the time */
+ unsigned int tstamp;
+ int length; /* Depends on type: xfer length or act length */
+ int status;
+ char data_flag;
+ unsigned char data[DATA_MAX];
+};
+
+#define SLAB_NAME_SZ 30
+struct mon_reader_text {
+ kmem_cache_t *e_slab;
+ int nevents;
+ struct list_head e_list;
+ struct mon_reader r; /* In C, parent class can be placed anywhere */
+
+ wait_queue_head_t wait;
+ int printf_size;
+ char *printf_buf;
+ struct semaphore printf_lock;
+
+ char slab_name[SLAB_NAME_SZ];
+};
+
+static void mon_text_ctor(void *, kmem_cache_t *, unsigned long);
+static void mon_text_dtor(void *, kmem_cache_t *, unsigned long);
+
+/*
+ * mon_text_submit
+ * mon_text_complete
+ *
+ * May be called from an interrupt.
+ *
+ * This is called with the whole mon_bus locked, so no additional lock.
+ */
+
+static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
+ int len, char ev_type)
+{
+ int pipe = urb->pipe;
+ unsigned char *data;
+
+ /*
+ * The check to see if it's safe to poke at data has an enormous
+ * number of corner cases, but it seems that the following is
+ * more or less safe.
+ *
+ * We do not even try to look transfer_buffer, because it can
+ * contain non-NULL garbage in case the upper level promised to
+ * set DMA for the HCD.
+ */
+ if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
+ return 'D';
+
+ if (len <= 0)
+ return 'L';
+
+ if ((data = urb->transfer_buffer) == NULL)
+ return 'Z'; /* '0' would be not as pretty. */
+
+ /*
+ * Bulk is easy to shortcut reliably.
+ * XXX Control needs setup packet taken.
+ * XXX Other pipe types need consideration. Currently, we overdo it
+ * and collect garbage for them: better more than less.
+ */
+ if (usb_pipebulk(pipe) || usb_pipecontrol(pipe)) {
+ if (usb_pipein(pipe)) {
+ if (ev_type == 'S')
+ return '<';
+ } else {
+ if (ev_type == 'C')
+ return '>';
+ }
+ }
+
+ if (len >= DATA_MAX)
+ len = DATA_MAX;
+ memcpy(ep->data, urb->transfer_buffer, len);
+ return 0;
+}
+
+static inline unsigned int mon_get_timestamp(void)
+{
+ struct timeval tval;
+ unsigned int stamp;
+
+ do_gettimeofday(&tval);
+ stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s. */
+ stamp = stamp * 1000000 + tval.tv_usec;
+ return stamp;
+}
+
+static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
+ char ev_type)
+{
+ struct mon_event_text *ep;
+ unsigned int stamp;
+
+ stamp = mon_get_timestamp();
+
+ if (rp->nevents >= EVENT_MAX ||
+ (ep = kmem_cache_alloc(rp->e_slab, SLAB_ATOMIC)) == NULL) {
+ rp->r.m_bus->cnt_text_lost++;
+ return;
+ }
+
+ ep->type = ev_type;
+ ep->pipe = urb->pipe;
+ ep->id = (unsigned long) urb;
+ ep->tstamp = stamp;
+ ep->length = (ev_type == 'S') ?
+ urb->transfer_buffer_length : urb->actual_length;
+ /* Collecting status makes debugging sense for submits, too */
+ ep->status = urb->status;
+
+ ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type);
+
+ rp->nevents++;
+ list_add_tail(&ep->e_link, &rp->e_list);
+ wake_up(&rp->wait);
+}
+
+static void mon_text_submit(void *data, struct urb *urb)
+{
+ struct mon_reader_text *rp = data;
+ mon_text_event(rp, urb, 'S');
+}
+
+static void mon_text_complete(void *data, struct urb *urb)
+{
+ struct mon_reader_text *rp = data;
+ mon_text_event(rp, urb, 'C');
+}
+
+/*
+ * Fetch next event from the circular buffer.
+ */
+static struct mon_event_text *mon_text_fetch(struct mon_reader_text *rp,
+ struct mon_bus *mbus)
+{
+ struct list_head *p;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mbus->lock, flags);
+ if (list_empty(&rp->e_list)) {
+ spin_unlock_irqrestore(&mbus->lock, flags);
+ return NULL;
+ }
+ p = rp->e_list.next;
+ list_del(p);
+ --rp->nevents;
+ spin_unlock_irqrestore(&mbus->lock, flags);
+ return list_entry(p, struct mon_event_text, e_link);
+}
+
+/*
+ */
+static int mon_text_open(struct inode *inode, struct file *file)
+{
+ struct mon_bus *mbus;
+ struct usb_bus *ubus;
+ struct mon_reader_text *rp;
+ int rc;
+
+ down(&mon_lock);
+ mbus = inode->u.generic_ip;
+ ubus = mbus->u_bus;
+
+ rp = kmalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
+ if (rp == NULL) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ memset(rp, 0, sizeof(struct mon_reader_text));
+ INIT_LIST_HEAD(&rp->e_list);
+ init_waitqueue_head(&rp->wait);
+ init_MUTEX(&rp->printf_lock);
+
+ rp->printf_size = PRINTF_DFL;
+ rp->printf_buf = kmalloc(rp->printf_size, GFP_KERNEL);
+ if (rp->printf_buf == NULL) {
+ rc = -ENOMEM;
+ goto err_alloc_pr;
+ }
+
+ rp->r.m_bus = mbus;
+ rp->r.r_data = rp;
+ rp->r.rnf_submit = mon_text_submit;
+ rp->r.rnf_complete = mon_text_complete;
+
+ snprintf(rp->slab_name, SLAB_NAME_SZ, "mon%dt_%lx", ubus->busnum,
+ (long)rp);
+ rp->e_slab = kmem_cache_create(rp->slab_name,
+ sizeof(struct mon_event_text), sizeof(long), 0,
+ mon_text_ctor, mon_text_dtor);
+ if (rp->e_slab == NULL) {
+ rc = -ENOMEM;
+ goto err_slab;
+ }
+
+ mon_reader_add(mbus, &rp->r);
+
+ file->private_data = rp;
+ up(&mon_lock);
+ return 0;
+
+// err_busy:
+// kmem_cache_destroy(rp->e_slab);
+err_slab:
+ kfree(rp->printf_buf);
+err_alloc_pr:
+ kfree(rp);
+err_alloc:
+ up(&mon_lock);
+ return rc;
+}
+
+/*
+ * For simplicity, we read one record in one system call and throw out
+ * what does not fit. This means that the following does not work:
+ * dd if=/dbg/usbmon/0t bs=10
+ * Also, we do not allow seeks and do not bother advancing the offset.
+ */
+static ssize_t mon_text_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct mon_reader_text *rp = file->private_data;
+ struct mon_bus *mbus = rp->r.m_bus;
+ DECLARE_WAITQUEUE(waita, current);
+ struct mon_event_text *ep;
+ int cnt, limit;
+ char *pbuf;
+ int data_len, i;
+
+ add_wait_queue(&rp->wait, &waita);
+ set_current_state(TASK_INTERRUPTIBLE);
+ while ((ep = mon_text_fetch(rp, mbus)) == NULL) {
+ if (file->f_flags & O_NONBLOCK) {
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&rp->wait, &waita);
+ return -EWOULDBLOCK; /* Same as EAGAIN in Linux */
+ }
+ /*
+ * We do not count nwaiters, because ->release is supposed
+ * to be called when all openers are gone only.
+ */
+ schedule();
+ if (signal_pending(current)) {
+ remove_wait_queue(&rp->wait, &waita);
+ return -EINTR;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&rp->wait, &waita);
+
+ down(&rp->printf_lock);
+ cnt = 0;
+ pbuf = rp->printf_buf;
+ limit = rp->printf_size;
+
+ cnt += snprintf(pbuf + cnt, limit - cnt,
+ "%lx %u %c %08x %d %d",
+ ep->id, ep->tstamp, ep->type, ep->pipe, ep->status, ep->length);
+
+ if ((data_len = ep->length) > 0) {
+ if (ep->data_flag == 0) {
+ cnt += snprintf(pbuf + cnt, limit - cnt, " =");
+ if (data_len >= DATA_MAX)
+ data_len = DATA_MAX;
+ for (i = 0; i < data_len; i++) {
+ if (i % 4 == 0) {
+ cnt += snprintf(pbuf + cnt, limit - cnt,
+ " ");
+ }
+ cnt += snprintf(pbuf + cnt, limit - cnt,
+ "%02x", ep->data[i]);
+ }
+ cnt += snprintf(pbuf + cnt, limit - cnt, "\n");
+ } else {
+ cnt += snprintf(pbuf + cnt, limit - cnt,
+ " %c\n", ep->data_flag);
+ }
+ } else {
+ cnt += snprintf(pbuf + cnt, limit - cnt, "\n");
+ }
+
+ if (copy_to_user(buf, rp->printf_buf, cnt))
+ cnt = -EFAULT;
+ up(&rp->printf_lock);
+ kmem_cache_free(rp->e_slab, ep);
+ return cnt;
+}
+
+static int mon_text_release(struct inode *inode, struct file *file)
+{
+ struct mon_reader_text *rp = file->private_data;
+ struct mon_bus *mbus;
+ /* unsigned long flags; */
+ struct list_head *p;
+ struct mon_event_text *ep;
+
+ down(&mon_lock);
+ mbus = inode->u.generic_ip;
+
+ if (mbus->nreaders <= 0) {
+ printk(KERN_ERR TAG ": consistency error on close\n");
+ up(&mon_lock);
+ return 0;
+ }
+ mon_reader_del(mbus, &rp->r);
+
+ /*
+ * In theory, e_list is protected by mbus->lock. However,
+ * after mon_reader_del has finished, the following is the case:
+ * - we are not on reader list anymore, so new events won't be added;
+ * - whole mbus may be dropped if it was orphaned.
+ * So, we better not touch mbus.
+ */
+ /* spin_lock_irqsave(&mbus->lock, flags); */
+ while (!list_empty(&rp->e_list)) {
+ p = rp->e_list.next;
+ ep = list_entry(p, struct mon_event_text, e_link);
+ list_del(p);
+ --rp->nevents;
+ kmem_cache_free(rp->e_slab, ep);
+ }
+ /* spin_unlock_irqrestore(&mbus->lock, flags); */
+
+ kmem_cache_destroy(rp->e_slab);
+ kfree(rp->printf_buf);
+ kfree(rp);
+
+ up(&mon_lock);
+ return 0;
+}
+
+struct file_operations mon_fops_text = {
+ .owner = THIS_MODULE,
+ .open = mon_text_open,
+ .llseek = no_llseek,
+ .read = mon_text_read,
+ /* .write = mon_text_write, */
+ /* .poll = mon_text_poll, */
+ /* .ioctl = mon_text_ioctl, */
+ .release = mon_text_release,
+};
+
+/*
+ * Slab interface: constructor.
+ */
+static void mon_text_ctor(void *mem, kmem_cache_t *slab, unsigned long sflags)
+{
+ /*
+ * Nothing to initialize. No, really!
+ * So, we fill it with garbage to emulate a reused object.
+ */
+ memset(mem, 0xe5, sizeof(struct mon_event_text));
+}
+
+static void mon_text_dtor(void *mem, kmem_cache_t *slab, unsigned long sflags)
+{
+ ;
+}
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
new file mode 100644
index 000000000000..ed35c18a5c44
--- /dev/null
+++ b/drivers/usb/mon/usb_mon.h
@@ -0,0 +1,51 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ */
+
+#ifndef __USB_MON_H
+#define __USB_MON_H
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/kref.h>
+/* #include <linux/usb.h> */ /* We use struct pointers only in this header */
+
+#define TAG "usbmon"
+
+struct mon_bus {
+ struct list_head bus_link;
+ spinlock_t lock;
+ struct dentry *dent_s; /* Debugging file */
+ struct dentry *dent_t; /* Text interface file */
+ struct usb_bus *u_bus;
+
+ /* Ref */
+ int nreaders; /* Under mon_lock AND mbus->lock */
+ struct list_head r_list; /* Chain of readers (usually one) */
+ struct kref ref; /* Under mon_lock */
+
+ /* Stats */
+ unsigned int cnt_text_lost;
+};
+
+/*
+ * An instance of a process which opened a file (but can fork later)
+ */
+struct mon_reader {
+ struct list_head r_link;
+ struct mon_bus *m_bus;
+ void *r_data; /* Use container_of instead? */
+
+ void (*rnf_submit)(void *data, struct urb *urb);
+ void (*rnf_complete)(void *data, struct urb *urb);
+};
+
+void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
+void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
+
+extern struct semaphore mon_lock;
+
+extern struct file_operations mon_fops_text;
+extern struct file_operations mon_fops_stat;
+
+#endif /* __USB_MON_H */
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
index d64409e85472..db64c908d4a7 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -260,13 +260,13 @@ comment "USB Network Adapters"
depends on USB_USBNET
config USB_AX8817X
- boolean "ASIX AX88172 Based USB 2.0 Ethernet Devices"
+ boolean "ASIX AX88xxx Based USB 2.0 Ethernet Devices"
depends on USB_USBNET && NET_ETHERNET
select CRC32
select MII
default y
help
- This option adds support for ASIX AX88172 based USB 2.0
+ This option adds support for ASIX AX88xxx based USB 2.0
10/100 Ethernet devices.
This driver should work with at least the following devices:
@@ -287,4 +287,21 @@ config USB_AX8817X
This driver creates an interface named "ethX", where X depends on
what other networking devices you have in use.
+config USB_ZD1201
+ tristate "USB ZD1201 based Wireless device support"
+ depends on NET_RADIO
+ select FW_LOADER
+ ---help---
+ Say Y if you want to use wireless LAN adapters based on the ZyDAS
+ ZD1201 chip.
+
+ This driver makes the adapter appear as a normal Ethernet interface,
+ typically on wlan0.
+
+ The zd1201 device requires external firmware to be loaded.
+ This can be found at http://linux-lc100020.sourceforge.net/
+
+ To compile this driver as a module, choose M here: the
+ module will be called zd1201.
+
endmenu
diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile
index 5eec1ed7e40a..16f352195512 100644
--- a/drivers/usb/net/Makefile
+++ b/drivers/usb/net/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_USB_KAWETH) += kaweth.o
obj-$(CONFIG_USB_PEGASUS) += pegasus.o
obj-$(CONFIG_USB_RTL8150) += rtl8150.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
+obj-$(CONFIG_USB_ZD1201) += zd1201.o
+
+CFLAGS_zd1201.o = -Idrivers/net/wireless/
diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c
index af883ae40d65..095d00732af7 100644
--- a/drivers/usb/net/catc.c
+++ b/drivers/usb/net/catc.c
@@ -457,7 +457,7 @@ static int catc_ctrl_msg(struct catc *catc, u8 dir, u8 request, u16 value, u16 i
{
int retval = usb_control_msg(catc->usbdev,
dir ? usb_rcvctrlpipe(catc->usbdev, 0) : usb_sndctrlpipe(catc->usbdev, 0),
- request, 0x40 | dir, value, index, buf, len, HZ);
+ request, 0x40 | dir, value, index, buf, len, 1000);
return retval < 0 ? retval : 0;
}
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index 2a83b0c33c29..8c5b4ab5be32 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -58,6 +58,7 @@
#include <linux/ethtool.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
+#include <linux/wait.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <asm/byteorder.h>
@@ -1180,31 +1181,21 @@ static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
// Starts urb and waits for completion or timeout
static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
{
- DECLARE_WAITQUEUE(wait, current);
struct usb_api_data awd;
int status;
init_waitqueue_head(&awd.wqh);
awd.done = 0;
- add_wait_queue(&awd.wqh, &wait);
urb->context = &awd;
status = usb_submit_urb(urb, GFP_NOIO);
if (status) {
// something went wrong
usb_free_urb(urb);
- remove_wait_queue(&awd.wqh, &wait);
return status;
}
- while (timeout && !awd.done) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- timeout = schedule_timeout(timeout);
- }
-
- remove_wait_queue(&awd.wqh, &wait);
-
- if (!timeout) {
+ if (!wait_event_timeout(awd.wqh, awd.done, timeout)) {
// timeout
kaweth_warn("usb_control/bulk_msg: timeout");
usb_kill_urb(urb); // remove urb safely
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index 542481e979e2..113dbf468ffa 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2003 Petko Manolov (petkan@users.sourceforge.net)
+ * Copyright (c) 1999-2005 Petko Manolov (petkan@users.sourceforge.net)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -47,7 +47,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.5.12 (2005/01/13)"
+#define DRIVER_VERSION "v0.6.12 (2005/01/13)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
@@ -301,20 +301,20 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
if (i < REG_TIMEOUT) {
get_registers(pegasus, PhyData, 2, &regdi);
*regd = le16_to_cpu(regdi);
- return 0;
+ return 1;
}
warn("%s: failed", __FUNCTION__);
- return 1;
+ return 0;
}
static int mdio_read(struct net_device *dev, int phy_id, int loc)
{
pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev);
- int res;
+ __le16 res;
- read_mii_word(pegasus, phy_id, loc, (u16 *) & res);
- return res & 0xffff;
+ read_mii_word(pegasus, phy_id, loc, &res);
+ return (int)res;
}
static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
@@ -636,7 +636,7 @@ goon:
return;
- tl_sched:
+tl_sched:
tasklet_schedule(&pegasus->rx_tl);
}
@@ -845,14 +845,14 @@ static inline void get_interrupt_interval(pegasus_t * pegasus)
static void set_carrier(struct net_device *net)
{
pegasus_t *pegasus = netdev_priv(net);
- short tmp;
+ __le16 tmp;
- read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
+ if (read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp))
+ return;
if (tmp & BMSR_LSTATUS)
netif_carrier_on(net);
else
netif_carrier_off(net);
-
}
static void free_all_urbs(pegasus_t * pegasus)
@@ -997,8 +997,7 @@ pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return set_register(pegasus, WakeupControl, reg78);
}
-static inline void
-pegasus_reset_wol(struct net_device *dev)
+static inline void pegasus_reset_wol(struct net_device *dev)
{
struct ethtool_wolinfo wol;
@@ -1009,10 +1008,17 @@ pegasus_reset_wol(struct net_device *dev)
static int
pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
- pegasus_t *pegasus = netdev_priv(dev);
+ pegasus_t *pegasus;
+
+ if (in_atomic())
+ return 0;
+
+ pegasus = netdev_priv(dev);
mii_ethtool_gset(&pegasus->mii, ecmd);
+
return 0;
}
+
static int
pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
@@ -1149,6 +1155,20 @@ static inline void setup_pegasus_II(pegasus_t * pegasus)
set_register(pegasus, Reg81, 2);
}
+
+struct workqueue_struct *pegasus_workqueue = NULL;
+#define CARRIER_CHECK_DELAY (2 * HZ)
+
+void check_carrier(void *data)
+{
+ pegasus_t *pegasus = data;
+ set_carrier(pegasus->net);
+ if (!(pegasus->flags & PEGASUS_UNPLUG)) {
+ queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
+ CARRIER_CHECK_DELAY);
+ }
+}
+
static int pegasus_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -1175,6 +1195,8 @@ static int pegasus_probe(struct usb_interface *intf,
tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus);
+ INIT_WORK(&pegasus->carrier_check, check_carrier, pegasus);
+
pegasus->usb = dev;
pegasus->net = net;
SET_MODULE_OWNER(net);
@@ -1212,12 +1234,14 @@ static int pegasus_probe(struct usb_interface *intf,
dev_warn(&intf->dev, "can't locate MII phy, using default\n");
pegasus->phy = 1;
}
+ pegasus->mii.phy_id = pegasus->phy;
usb_set_intfdata(intf, pegasus);
SET_NETDEV_DEV(net, &intf->dev);
pegasus_reset_wol(net);
res = register_netdev(net);
if (res)
goto out3;
+ queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, CARRIER_CHECK_DELAY);
pr_info("%s: %s\n", net->name, usb_dev_id[dev_index].name);
return 0;
@@ -1239,11 +1263,12 @@ static void pegasus_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
if (!pegasus) {
- warn("unregistering non-existant device");
+ warn("unregistering non-existent device");
return;
}
pegasus->flags |= PEGASUS_UNPLUG;
+ cancel_delayed_work(&pegasus->carrier_check);
unregister_netdev(pegasus->net);
usb_put_dev(interface_to_usbdev(intf));
free_all_urbs(pegasus);
@@ -1253,7 +1278,7 @@ static void pegasus_disconnect(struct usb_interface *intf)
free_netdev(pegasus->net);
}
-static int pegasus_suspend (struct usb_interface *intf, u32 state)
+static int pegasus_suspend (struct usb_interface *intf, pm_message_t state)
{
struct pegasus *pegasus = usb_get_intfdata(intf);
@@ -1281,11 +1306,15 @@ static struct usb_driver pegasus_driver = {
static int __init pegasus_init(void)
{
pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION);
+ pegasus_workqueue = create_singlethread_workqueue("pegasus");
+ if (!pegasus_workqueue)
+ return -ENOMEM;
return usb_register(&pegasus_driver);
}
static void __exit pegasus_exit(void)
{
+ destroy_workqueue(pegasus_workqueue);
usb_deregister(&pegasus_driver);
}
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index f043fc382dcc..db427f772e04 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -96,6 +96,7 @@ typedef struct pegasus {
int dev_index;
int intr_interval;
struct tasklet_struct rx_tl;
+ struct work_struct carrier_check;
struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
struct sk_buff *rx_pool[RX_SKBS];
struct sk_buff *rx_skb;
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index 2ecba51582b5..8fb223385f2f 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -195,14 +195,14 @@ static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
{
return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
- indx, 0, data, size, HZ / 2);
+ indx, 0, data, size, 500);
}
static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
{
return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
- indx, 0, data, size, HZ / 2);
+ indx, 0, data, size, 500);
}
static void ctrl_callback(struct urb *urb, struct pt_regs *regs)
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
index 9c8d8c25d60c..a59446558b07 100644
--- a/drivers/usb/net/usbnet.c
+++ b/drivers/usb/net/usbnet.c
@@ -2,7 +2,8 @@
* USB Networking Links
* Copyright (C) 2000-2003 by David Brownell <dbrownell@users.sourceforge.net>
* Copyright (C) 2002 Pavel Machek <pavel@ucw.cz>
- * Copyright (C) 2003 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
* Copyright (c) 2002-2003 TiVo Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -109,6 +110,7 @@
* (Neil Bortnak)
* 03-nov-2004 Trivial patch for KC2190 (KC-190) chip. (Jonathan McDowell)
*
+ * 01-feb-2005 AX88772 support (Phil Chang & Dave Hollis)
*-------------------------------------------------------------------------*/
// #define DEBUG // error path messages, extra info
@@ -164,8 +166,7 @@
#define THROTTLE_JIFFIES (HZ/8)
// for vendor-specific control operations
-#define CONTROL_TIMEOUT_MS (500) /* msec */
-#define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000)
+#define CONTROL_TIMEOUT_MS 500
// between wakeups
#define UNLINK_TIMEOUT_MS 3
@@ -222,6 +223,8 @@ struct driver_info {
#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */
#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */
+#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */
+
/* init device ... can sleep, or cause probe() failure */
int (*bind)(struct usbnet *, struct usb_interface *);
@@ -274,9 +277,6 @@ module_param (msg_level, int, 0);
MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)");
-#define RUN_CONTEXT (in_irq () ? "in_irq" \
- : (in_interrupt () ? "in_interrupt" : "can sleep"))
-
#ifdef DEBUG
#define devdbg(usbnet, fmt, arg...) \
printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
@@ -435,6 +435,8 @@ static const struct driver_info an2720_info = {
#define AX_CMD_SET_HW_MII 0x0a
#define AX_CMD_READ_EEPROM 0x0b
#define AX_CMD_WRITE_EEPROM 0x0c
+#define AX_CMD_WRITE_ENABLE 0x0d
+#define AX_CMD_WRITE_DISABLE 0x0e
#define AX_CMD_WRITE_RX_CTL 0x10
#define AX_CMD_READ_IPG012 0x11
#define AX_CMD_WRITE_IPG0 0x12
@@ -447,6 +449,10 @@ static const struct driver_info an2720_info = {
#define AX_CMD_READ_MONITOR_MODE 0x1c
#define AX_CMD_WRITE_MONITOR_MODE 0x1d
#define AX_CMD_WRITE_GPIOS 0x1f
+#define AX_CMD_SW_RESET 0x20
+#define AX_CMD_SW_PHY_STATUS 0x21
+#define AX_CMD_SW_PHY_SELECT 0x22
+#define AX88772_CMD_READ_NODE_ID 0x13
#define AX_MONITOR_MODE 0x01
#define AX_MONITOR_LINK 0x02
@@ -458,6 +464,23 @@ static const struct driver_info an2720_info = {
#define AX_INTERRUPT_BUFSIZE 8
+#define AX_EEPROM_LEN 0x40
+
+#define AX_SWRESET_CLEAR 0x00
+#define AX_SWRESET_RR 0x01
+#define AX_SWRESET_RT 0x02
+#define AX_SWRESET_PRTE 0x04
+#define AX_SWRESET_PRL 0x08
+#define AX_SWRESET_BZ 0x10
+#define AX_SWRESET_IPRL 0x20
+#define AX_SWRESET_IPPD 0x40
+
+#define AX88772_IPG0_DEFAULT 0x15
+#define AX88772_IPG1_DEFAULT 0x0c
+#define AX88772_IPG2_DEFAULT 0x12
+
+#define AX_EEPROM_MAGIC 0xdeadbeef
+
/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
struct ax8817x_data {
u8 multi_filter[AX_MCAST_FILTER_SIZE];
@@ -477,7 +500,7 @@ static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
index,
data,
size,
- CONTROL_TIMEOUT_JIFFIES);
+ CONTROL_TIMEOUT_MS);
}
static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
@@ -492,7 +515,7 @@ static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
index,
data,
size,
- CONTROL_TIMEOUT_JIFFIES);
+ CONTROL_TIMEOUT_MS);
}
static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
@@ -514,18 +537,16 @@ static void ax8817x_interrupt_complete(struct urb *urb, struct pt_regs *regs)
int link;
if (urb->status < 0) {
- printk(KERN_DEBUG "ax8817x_interrupt_complete() failed with %d",
+ devdbg(dev,"ax8817x_interrupt_complete() failed with %d",
urb->status);
} else {
- if (data->int_buf[5] == 0x90) {
- link = data->int_buf[2] & 0x01;
- if (netif_carrier_ok(dev->net) != link) {
- if (link)
- netif_carrier_on(dev->net);
- else
- netif_carrier_off(dev->net);
- devdbg(dev, "ax8817x - Link Status is: %d", link);
- }
+ link = data->int_buf[2] & 0x01;
+ if (netif_carrier_ok(dev->net) != link) {
+ if (link)
+ netif_carrier_on(dev->net);
+ else
+ netif_carrier_off(dev->net);
+ devdbg(dev, "ax8817x - Link Status is: %d", link);
}
usb_submit_urb(data->int_urb, GFP_ATOMIC);
}
@@ -674,6 +695,11 @@ static int ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolin
return 0;
}
+static int ax8817x_get_eeprom_len(struct net_device *net)
+{
+ return AX_EEPROM_LEN;
+}
+
static int ax8817x_get_eeprom(struct net_device *net,
struct ethtool_eeprom *eeprom, u8 *data)
{
@@ -687,13 +713,15 @@ static int ax8817x_get_eeprom(struct net_device *net,
if (eeprom->len % 2)
return -EINVAL;
+ eeprom->magic = AX_EEPROM_MAGIC;
+
/* ax8817x returns 2 bytes from eeprom on read */
for (i=0; i < eeprom->len / 2; i++) {
if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM,
eeprom->offset + i, 0, 2, &ebuf[i]) < 0)
return -EINVAL;
}
- return i * 2;
+ return 0;
}
static void ax8817x_get_drvinfo (struct net_device *net,
@@ -728,6 +756,7 @@ static struct ethtool_ops ax8817x_ethtool_ops = {
.set_msglevel = usbnet_set_msglevel,
.get_wol = ax8817x_get_wol,
.set_wol = ax8817x_set_wol,
+ .get_eeprom_len = ax8817x_get_eeprom_len,
.get_eeprom = ax8817x_get_eeprom,
.get_settings = ax8817x_get_settings,
.set_settings = ax8817x_set_settings,
@@ -735,27 +764,26 @@ static struct ethtool_ops ax8817x_ethtool_ops = {
static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf)
{
- int ret;
- u8 buf[6];
+ int ret = 0;
+ void *buf;
int i;
unsigned long gpio_bits = dev->driver_info->data;
struct ax8817x_data *data = (struct ax8817x_data *)dev->data;
- dev->in = usb_rcvbulkpipe(dev->udev, 3);
- dev->out = usb_sndbulkpipe(dev->udev, 2);
+ get_endpoints(dev,intf);
- // allocate irq urb
if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == NULL) {
dbg ("%s: cannot allocate interrupt URB",
dev->net->name);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out1;
}
if ((data->int_buf = kmalloc(AX_INTERRUPT_BUFSIZE, GFP_KERNEL)) == NULL) {
dbg ("%s: cannot allocate memory for interrupt buffer",
dev->net->name);
- usb_free_urb(data->int_urb);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out1;
}
memset(data->int_buf, 0, AX_INTERRUPT_BUFSIZE);
@@ -765,36 +793,43 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf)
ax8817x_interrupt_complete, dev,
dev->udev->speed == USB_SPEED_HIGH ? 8 : 100);
+ buf = kmalloc(ETH_ALEN, GFP_KERNEL);
+ if(!buf) {
+ ret = -ENOMEM;
+ goto out2;
+ }
+
/* Toggle the GPIOs in a manufacturer/model specific way */
for (i = 2; i >= 0; i--) {
if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
(gpio_bits >> (i * 8)) & 0xff, 0, 0,
buf)) < 0)
- return ret;
+ goto out3;
msleep(5);
}
if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf)) < 0) {
dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret);
- return ret;
+ goto out3;
}
/* Get the MAC address */
memset(buf, 0, ETH_ALEN);
if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf)) < 0) {
dbg("read AX_CMD_READ_NODE_ID failed: %d", ret);
- return ret;
+ goto out3;
}
memcpy(dev->net->dev_addr, buf, ETH_ALEN);
/* Get the PHY id */
if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) {
dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret);
- return ret;
+ goto out3;
} else if (ret < 2) {
/* this should always return 2 bytes */
dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", ret);
- return -EIO;
+ ret = -EIO;
+ goto out3;
}
/* Initialize MII structure */
@@ -803,7 +838,7 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf)
dev->mii.mdio_write = ax8817x_mdio_write;
dev->mii.phy_id_mask = 0x3f;
dev->mii.reg_num_mask = 0x1f;
- dev->mii.phy_id = buf[1];
+ dev->mii.phy_id = *((u8 *)buf + 1);
dev->net->set_multicast_list = ax8817x_set_multicast;
dev->net->ethtool_ops = &ax8817x_ethtool_ops;
@@ -816,11 +851,17 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf)
if((ret = usb_submit_urb(data->int_urb, GFP_KERNEL)) < 0) {
dbg("Failed to submit interrupt URB: %02x", ret);
- usb_free_urb(data->int_urb);
- return ret;
+ goto out2;
}
return 0;
+out3:
+ kfree(buf);
+out2:
+ kfree(data->int_buf);
+out1:
+ usb_free_urb(data->int_urb);
+ return ret;
}
static void ax8817x_unbind(struct usbnet *dev, struct usb_interface *intf)
@@ -832,6 +873,290 @@ static void ax8817x_unbind(struct usbnet *dev, struct usb_interface *intf)
kfree(data->int_buf);
}
+static struct ethtool_ops ax88772_ethtool_ops = {
+ .get_drvinfo = ax8817x_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_wol = ax8817x_get_wol,
+ .set_wol = ax8817x_set_wol,
+ .get_eeprom_len = ax8817x_get_eeprom_len,
+ .get_eeprom = ax8817x_get_eeprom,
+ .get_settings = ax8817x_get_settings,
+ .set_settings = ax8817x_set_settings,
+};
+
+static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ int ret;
+ void *buf;
+ struct ax8817x_data *data = (struct ax8817x_data *)dev->data;
+
+ get_endpoints(dev,intf);
+
+ if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == 0) {
+ dbg ("Cannot allocate interrupt URB");
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ if ((data->int_buf = kmalloc(AX_INTERRUPT_BUFSIZE, GFP_KERNEL)) == NULL) {
+ dbg ("Cannot allocate memory for interrupt buffer");
+ ret = -ENOMEM;
+ goto out1;
+ }
+ memset(data->int_buf, 0, AX_INTERRUPT_BUFSIZE);
+
+ usb_fill_int_urb (data->int_urb, dev->udev,
+ usb_rcvintpipe (dev->udev, 1),
+ data->int_buf, AX_INTERRUPT_BUFSIZE,
+ ax8817x_interrupt_complete, dev,
+ dev->udev->speed == USB_SPEED_HIGH ? 8 : 100);
+
+ buf = kmalloc(6, GFP_KERNEL);
+ if(!buf) {
+ dbg ("Cannot allocate memory for buffer");
+ ret = -ENOMEM;
+ goto out2;
+ }
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
+ 0x00B0, 0, 0, buf)) < 0)
+ goto out3;
+
+ msleep(5);
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0x0001, 0, 0, buf)) < 0) {
+ dbg("Select PHY #1 failed: %d", ret);
+ goto out3;
+ }
+
+ if ((ret =
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, 0, 0, buf)) < 0) {
+ dbg("Failed to power down internal PHY: %d", ret);
+ goto out3;
+ }
+
+ msleep(150);
+ if ((ret =
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, 0, 0, buf)) < 0) {
+ dbg("Failed to perform software reset: %d", ret);
+ goto out3;
+ }
+
+ msleep(150);
+ if ((ret =
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) {
+ dbg("Failed to set Internal/External PHY reset control: %d", ret);
+ goto out3;
+ }
+
+ msleep(150);
+ if ((ret =
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0000, 0, 0,
+ buf)) < 0) {
+ dbg("Failed to reset RX_CTL: %d", ret);
+ goto out3;
+ }
+
+ /* Get the MAC address */
+ memset(buf, 0, ETH_ALEN);
+ if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)) < 0) {
+ dbg("Failed to read MAC address: %d", ret);
+ goto out3;
+ }
+ memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, buf)) < 0) {
+ dbg("Enabling software MII failed: %d", ret);
+ goto out3;
+ }
+
+ if (((ret =
+ ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, 0x0010, 2, 2, buf)) < 0)
+ || (*((u16 *)buf) != 0x003b)) {
+ dbg("Read PHY register 2 must be 0x3b00: %d", ret);
+ goto out3;
+ }
+
+ /* Initialize MII structure */
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = ax8817x_mdio_read;
+ dev->mii.mdio_write = ax8817x_mdio_write;
+ dev->mii.phy_id_mask = 0xff;
+ dev->mii.reg_num_mask = 0xff;
+
+ /* Get the PHY id */
+ if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) {
+ dbg("Error reading PHY ID: %02x", ret);
+ goto out3;
+ } else if (ret < 2) {
+ /* this should always return 2 bytes */
+ dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x",
+ ret);
+ ret = -EIO;
+ goto out3;
+ }
+ dev->mii.phy_id = *((u8 *)buf + 1);
+
+ if ((ret =
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, 0, 0, buf)) < 0) {
+ dbg("Set external PHY reset pin level: %d", ret);
+ goto out3;
+ }
+ msleep(150);
+ if ((ret =
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) {
+ dbg("Set Internal/External PHY reset control: %d", ret);
+ goto out3;
+ }
+ msleep(150);
+
+
+ dev->net->set_multicast_list = ax8817x_set_multicast;
+ dev->net->ethtool_ops = &ax88772_ethtool_ops;
+
+ ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR,
+ cpu_to_le16(BMCR_RESET));
+ ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA));
+ mii_nway_restart(&dev->mii);
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, 0x0336, 0, 0, buf)) < 0) {
+ dbg("Write medium mode register: %d", ret);
+ goto out3;
+ }
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,AX88772_IPG2_DEFAULT, 0, buf)) < 0) {
+ dbg("Write IPG,IPG1,IPG2 failed: %d", ret);
+ goto out3;
+ }
+ if ((ret =
+ ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) {
+ dbg("Failed to set hardware MII: %02x", ret);
+ goto out3;
+ }
+
+ /* Set RX_CTL to default values with 2k buffer, and enable cactus */
+ if ((ret =
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0,
+ buf)) < 0) {
+ dbg("Reset RX_CTL failed: %d", ret);
+ goto out3;
+ }
+
+ if((ret = usb_submit_urb(data->int_urb, GFP_KERNEL)) < 0) {
+ dbg("Failed to submit interrupt URB: %02x", ret);
+ goto out3;
+ }
+
+ kfree(buf);
+
+ return 0;
+
+out3:
+ kfree(buf);
+out2:
+ kfree(data->int_buf);
+out1:
+ usb_free_urb(data->int_urb);
+
+ return ret;
+}
+
+static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ u32 *header;
+ char *packet;
+ struct sk_buff *ax_skb;
+ u16 size;
+
+ header = (u32 *) skb->data;
+ le32_to_cpus(header);
+ packet = (char *)(header + 1);
+
+ skb_pull(skb, 4);
+
+ while (skb->len > 0) {
+ if ((short)(*header & 0x0000ffff) !=
+ ~((short)((*header & 0xffff0000) >> 16))) {
+ devdbg(dev,"header length data is error");
+ }
+ /* get the packet length */
+ size = (u16) (*header & 0x0000ffff);
+
+ if ((skb->len) - ((size + 1) & 0xfffe) == 0)
+ return 2;
+ if (size > ETH_FRAME_LEN) {
+ devdbg(dev,"invalid rx length %d", size);
+ return 0;
+ }
+ ax_skb = skb_clone(skb, GFP_ATOMIC);
+ if (ax_skb) {
+ ax_skb->len = size;
+ ax_skb->data = packet;
+ ax_skb->tail = packet + size;
+ skb_return(dev, ax_skb);
+ } else {
+ return 0;
+ }
+
+ skb_pull(skb, (size + 1) & 0xfffe);
+
+ if (skb->len == 0)
+ break;
+
+ header = (u32 *) skb->data;
+ le32_to_cpus(header);
+ packet = (char *)(header + 1);
+ skb_pull(skb, 4);
+ }
+
+ if (skb->len < 0) {
+ devdbg(dev,"invalid rx length %d", skb->len);
+ return 0;
+ }
+ return 1;
+}
+
+static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+ int flags)
+{
+ int padlen;
+ int headroom = skb_headroom(skb);
+ int tailroom = skb_tailroom(skb);
+ u32 *packet_len;
+ u32 *padbytes_ptr;
+
+ padlen = ((skb->len + 4) % 512) ? 0 : 4;
+
+ if ((!skb_cloned(skb))
+ && ((headroom + tailroom) >= (4 + padlen))) {
+ if ((headroom < 4) || (tailroom < padlen)) {
+ skb->data = memmove(skb->head + 4, skb->data, skb->len);
+ skb->tail = skb->data + skb->len;
+ }
+ } else {
+ struct sk_buff *skb2;
+ skb2 = skb_copy_expand(skb, 4, padlen, flags);
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ if (!skb)
+ return NULL;
+ }
+
+ packet_len = (u32 *) skb_push(skb, 4);
+
+ packet_len = (u32 *) skb->data;
+ *packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+
+ if ((skb->len % 512) == 0) {
+ padbytes_ptr = (u32 *) skb->tail;
+ *padbytes_ptr = 0xffff0000;
+ skb_put(skb, padlen);
+ }
+ return skb;
+}
+
static const struct driver_info ax8817x_info = {
.description = "ASIX AX8817x USB 2.0 Ethernet",
.bind = ax8817x_bind,
@@ -864,6 +1189,16 @@ static const struct driver_info hawking_uf200_info = {
.data = 0x001f1d1f,
};
+static const struct driver_info ax88772_info = {
+ .description = "ASIX AX88772 USB 2.0 Ethernet",
+ .bind = ax88772_bind,
+ .unbind = ax8817x_unbind,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = ax88772_rx_fixup,
+ .tx_fixup = ax88772_tx_fixup,
+ .data = 0x00130103,
+};
+
#endif /* CONFIG_USB_AX8817X */
@@ -911,45 +1246,14 @@ static const struct driver_info belkin_info = {
#ifdef NEED_GENERIC_CDC
-/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
-struct header_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
-
- u16 bcdCDC;
-} __attribute__ ((packed));
-
-/* "Union Functional Descriptor" from CDC spec 5.2.3.X */
-struct union_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
-
- u8 bMasterInterface0;
- u8 bSlaveInterface0;
- /* ... and there could be other slave interfaces */
-} __attribute__ ((packed));
-
-/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
-struct ether_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
-
- u8 iMACAddress;
- u32 bmEthernetStatistics;
- __le16 wMaxSegmentSize;
- __le16 wNumberMCFilters;
- u8 bNumberPowerFilters;
-} __attribute__ ((packed));
+#include <linux/usb_cdc.h>
struct cdc_state {
- struct header_desc *header;
- struct union_desc *u;
- struct ether_desc *ether;
- struct usb_interface *control;
- struct usb_interface *data;
+ struct usb_cdc_header_desc *header;
+ struct usb_cdc_union_desc *u;
+ struct usb_cdc_ether_desc *ether;
+ struct usb_interface *control;
+ struct usb_interface *data;
};
static struct usb_driver usbnet_driver;
@@ -1004,7 +1308,7 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf)
* CDC Ethernet achieves with a simple descriptor.
*/
switch (buf [2]) {
- case 0x00: /* Header, mostly useless */
+ case USB_CDC_HEADER_TYPE:
if (info->header) {
dev_dbg (&intf->dev, "extra CDC header\n");
goto bad_desc;
@@ -1016,7 +1320,7 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf)
goto bad_desc;
}
break;
- case 0x06: /* Union (groups interfaces) */
+ case USB_CDC_UNION_TYPE:
if (info->u) {
dev_dbg (&intf->dev, "extra CDC union\n");
goto bad_desc;
@@ -1065,7 +1369,7 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf)
goto bad_desc;
}
break;
- case 0x0F: /* Ethernet Networking */
+ case USB_CDC_ETHERNET_TYPE:
if (info->ether) {
dev_dbg (&intf->dev, "extra CDC ether\n");
goto bad_desc;
@@ -1169,7 +1473,7 @@ static u8 nibble (unsigned char c)
}
static inline int
-get_ethernet_addr (struct usbnet *dev, struct ether_desc *e)
+get_ethernet_addr (struct usbnet *dev, struct usb_cdc_ether_desc *e)
{
int tmp, i;
unsigned char buf [13];
@@ -1321,7 +1625,7 @@ static inline int gl_control_write (struct usbnet *dev, u8 request, u16 value)
0, // index
0, // data buffer
0, // size
- CONTROL_TIMEOUT_JIFFIES);
+ CONTROL_TIMEOUT_MS);
return retval;
}
@@ -1602,9 +1906,9 @@ static const struct driver_info genelink_info = {
*/
struct nc_header { // packed:
- u16 hdr_len; // sizeof nc_header (LE, all)
- u16 packet_len; // payload size (including ethhdr)
- u16 packet_id; // detects dropped packets
+ __le16 hdr_len; // sizeof nc_header (LE, all)
+ __le16 packet_len; // payload size (including ethhdr)
+ __le16 packet_id; // detects dropped packets
#define MIN_HEADER 6
// all else is optional, and must start with:
@@ -1615,7 +1919,7 @@ struct nc_header { // packed:
#define PAD_BYTE ((unsigned char)0xAC)
struct nc_trailer {
- u16 packet_id;
+ __le16 packet_id;
} __attribute__((__packed__));
// packets may use FLAG_FRAMING_NC and optional pad
@@ -1658,7 +1962,7 @@ nc_vendor_read (struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr)
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, regnum,
retval_ptr, sizeof *retval_ptr,
- CONTROL_TIMEOUT_JIFFIES);
+ CONTROL_TIMEOUT_MS);
if (status > 0)
status = 0;
if (!status)
@@ -1682,7 +1986,7 @@ nc_vendor_write (struct usbnet *dev, u8 req, u8 regnum, u16 value)
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, regnum,
NULL, 0, // data is in setup packet
- CONTROL_TIMEOUT_JIFFIES);
+ CONTROL_TIMEOUT_MS);
}
static inline void
@@ -1973,6 +2277,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
{
struct nc_header *header;
struct nc_trailer *trailer;
+ u16 hdr_len, packet_len;
if (!(skb->len & 0x01)
|| MIN_FRAMED > skb->len
@@ -1986,50 +2291,50 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
}
header = (struct nc_header *) skb->data;
- le16_to_cpus (&header->hdr_len);
- le16_to_cpus (&header->packet_len);
- if (FRAMED_SIZE (header->packet_len) > MAX_PACKET) {
+ hdr_len = le16_to_cpup (&header->hdr_len);
+ packet_len = le16_to_cpup (&header->packet_len);
+ if (FRAMED_SIZE (packet_len) > MAX_PACKET) {
dev->stats.rx_frame_errors++;
- dbg ("packet too big, %d", header->packet_len);
+ dbg ("packet too big, %d", packet_len);
nc_ensure_sync (dev);
return 0;
- } else if (header->hdr_len < MIN_HEADER) {
+ } else if (hdr_len < MIN_HEADER) {
dev->stats.rx_frame_errors++;
- dbg ("header too short, %d", header->hdr_len);
+ dbg ("header too short, %d", hdr_len);
nc_ensure_sync (dev);
return 0;
- } else if (header->hdr_len > MIN_HEADER) {
+ } else if (hdr_len > MIN_HEADER) {
// out of band data for us?
- dbg ("header OOB, %d bytes",
- header->hdr_len - MIN_HEADER);
+ dbg ("header OOB, %d bytes", hdr_len - MIN_HEADER);
nc_ensure_sync (dev);
// switch (vendor/product ids) { ... }
}
- skb_pull (skb, header->hdr_len);
+ skb_pull (skb, hdr_len);
trailer = (struct nc_trailer *)
(skb->data + skb->len - sizeof *trailer);
skb_trim (skb, skb->len - sizeof *trailer);
- if ((header->packet_len & 0x01) == 0) {
- if (skb->data [header->packet_len] != PAD_BYTE) {
+ if ((packet_len & 0x01) == 0) {
+ if (skb->data [packet_len] != PAD_BYTE) {
dev->stats.rx_frame_errors++;
dbg ("bad pad");
return 0;
}
skb_trim (skb, skb->len - 1);
}
- if (skb->len != header->packet_len) {
+ if (skb->len != packet_len) {
dev->stats.rx_frame_errors++;
dbg ("bad packet len %d (expected %d)",
- skb->len, header->packet_len);
+ skb->len, packet_len);
nc_ensure_sync (dev);
return 0;
}
if (header->packet_id != get_unaligned (&trailer->packet_id)) {
dev->stats.rx_fifo_errors++;
dbg ("(2+ dropped) rx packet_id mismatch 0x%x 0x%x",
- header->packet_id, trailer->packet_id);
+ le16_to_cpu (header->packet_id),
+ le16_to_cpu (trailer->packet_id));
return 0;
}
#if 0
@@ -2125,7 +2430,7 @@ pl_vendor_req (struct usbnet *dev, u8 req, u8 val, u8 index)
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
val, index,
NULL, 0,
- CONTROL_TIMEOUT_JIFFIES);
+ CONTROL_TIMEOUT_MS);
}
static inline int
@@ -2402,14 +2707,20 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
size = RNDIS_MAX_TRANSFER;
else
#endif
+#ifdef CONFIG_USB_AX8817X
+ if (dev->driver_info->flags & FLAG_FRAMING_AX)
+ size = 2048;
+ else
+#endif
size = (sizeof (struct ethhdr) + dev->net->mtu);
- if ((skb = alloc_skb (size, flags)) == NULL) {
+ if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) {
devdbg (dev, "no rx skb");
defer_kevent (dev, EVENT_RX_MEMORY);
usb_free_urb (urb);
return;
}
+ skb_reserve (skb, NET_IP_ALIGN);
entry = (struct skb_data *) skb->cb;
entry->urb = urb;
@@ -2677,6 +2988,8 @@ static int usbnet_open (struct net_device *net)
framing = "Zaurus";
else if (dev->driver_info->flags & FLAG_FRAMING_RN)
framing = "RNDIS";
+ else if (dev->driver_info->flags & FLAG_FRAMING_AX)
+ framing = "ASIX";
else
framing = "simple";
@@ -3197,6 +3510,32 @@ out:
return status;
}
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PM
+
+static int usbnet_suspend (struct usb_interface *intf, u32 state)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+
+ netif_device_detach (dev->net);
+ return 0;
+}
+
+static int usbnet_resume (struct usb_interface *intf)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+
+ netif_device_attach (dev->net);
+ return 0;
+}
+
+#else /* !CONFIG_PM */
+
+#define usbnet_suspend NULL
+#define usbnet_resume NULL
+
+#endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
@@ -3290,6 +3629,10 @@ static const struct usb_device_id products [] = {
// goodway corp usb gwusb2e
USB_DEVICE (0x1631, 0x6200),
.driver_info = (unsigned long) &ax8817x_info,
+}, {
+ // ASIX AX88772 10/100
+ USB_DEVICE (0x0b95, 0x7720),
+ .driver_info = (unsigned long) &ax88772_info,
},
#endif
@@ -3374,6 +3717,7 @@ static const struct usb_device_id products [] = {
.driver_info = (unsigned long) &blob_info,
}, {
// Linux Ethernet/RNDIS gadget on pxa210/25x/26x
+ // e.g. Gumstix, current OpenZaurus, ...
USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203),
.driver_info = (unsigned long) &linuxdev_info,
},
@@ -3386,72 +3730,64 @@ static const struct usb_device_id products [] = {
*
* PXA-2xx based models are also lying-about-cdc.
*
+ * NOTE: OpenZaurus versions with 2.6 kernels won't use these entries,
+ * unlike the older ones with 2.4 "embedix" kernels.
+ *
* NOTE: These entries do double-duty, serving as blacklist entries
* whenever Zaurus support isn't enabled, but CDC Ethernet is.
*/
+#define ZAURUS_MASTER_INTERFACE \
+ .bInterfaceClass = USB_CLASS_COMM, \
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8004,
- /* match the master interface */
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = 6 /* Ethernet model */,
- .bInterfaceProtocol = 0,
+ ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_STRONGARM_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8005, /* A-300 */
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = 6 /* Ethernet model */,
- .bInterfaceProtocol = 0x00,
+ ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8006, /* B-500/SL-5600 */
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = 6 /* Ethernet model */,
- .bInterfaceProtocol = 0x00,
+ ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8007, /* C-700 */
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = 6 /* Ethernet model */,
- .bInterfaceProtocol = 0x00,
+ ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x9031, /* C-750 C-760 */
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = 6 /* Ethernet model */,
- .bInterfaceProtocol = 0x00,
+ ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x9032, /* SL-6000 */
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = 6 /* Ethernet model */,
- .bInterfaceProtocol = 0x00,
+ ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x9050, /* C-860 */
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = 6 /* Ethernet model */,
- .bInterfaceProtocol = 0x00,
+ ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
},
@@ -3463,9 +3799,7 @@ static const struct usb_device_id products [] = {
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x07B4,
.idProduct = 0x0F02, /* R-1000 */
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = 6 /* Ethernet model */,
- .bInterfaceProtocol = 0x00,
+ ZAURUS_MASTER_INTERFACE,
.driver_info = OLYMPUS_MXL_INFO,
},
#endif
@@ -3480,7 +3814,8 @@ static const struct usb_device_id products [] = {
* NOTE: this match must come AFTER entries working around
* bugs/quirks in a given product (like Zaurus, above).
*/
- USB_INTERFACE_INFO (USB_CLASS_COMM, 6 /* Ethernet model */, 0),
+ USB_INTERFACE_INFO (USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
+ USB_CDC_PROTO_NONE),
.driver_info = (unsigned long) &cdc_info,
},
#endif
@@ -3495,6 +3830,8 @@ static struct usb_driver usbnet_driver = {
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
+ .suspend = usbnet_suspend,
+ .resume = usbnet_resume,
};
/* Default ethtool_ops assigned. Devices can override in their bind() routine */
diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c
new file mode 100644
index 000000000000..6b3301e013a2
--- /dev/null
+++ b/drivers/usb/net/zd1201.c
@@ -0,0 +1,1905 @@
+/*
+ * Driver for ZyDAS zd1201 based wireless USB devices.
+ *
+ * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * Parts of this driver have been derived from a wlan-ng version
+ * modified by ZyDAS. They also made documentation available, thanks!
+ * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <linux/string.h>
+#include <linux/if_arp.h>
+#include <linux/firmware.h>
+#include <ieee802_11.h>
+#include "zd1201.h"
+
+static struct usb_device_id zd1201_table[] = {
+ {USB_DEVICE(0x0586, 0x3400)}, /* Peabird Wireless USB Adapter */
+ {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 Wireless USB Adapter */
+ {USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */
+ {USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb adapter */
+ {}
+};
+
+static int ap = 0; /* Are we an AP or a normal station? */
+
+#define ZD1201_VERSION "0.15"
+
+MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
+MODULE_DESCRIPTION("Driver for ZyDAS ZD1201 based USB Wireless adapters");
+MODULE_VERSION(ZD1201_VERSION);
+MODULE_LICENSE("GPL");
+module_param(ap, int, 0);
+MODULE_PARM_DESC(ap, "If non-zero Access Point firmware will be loaded");
+MODULE_DEVICE_TABLE(usb, zd1201_table);
+
+
+int zd1201_fw_upload(struct usb_device *dev, int apfw)
+{
+ const struct firmware *fw_entry;
+ char* data;
+ unsigned long len;
+ int err;
+ unsigned char ret;
+ char *buf;
+ char *fwfile;
+
+ if (apfw)
+ fwfile = "zd1201-ap.fw";
+ else
+ fwfile = "zd1201.fw";
+
+ err = request_firmware(&fw_entry, fwfile, &dev->dev);
+ if (err) {
+ dev_err(&dev->dev, "Failed to load %s firmware file!\n", fwfile);
+ dev_err(&dev->dev, "Make sure the hotplug firmware loader is installed.\n");
+ dev_err(&dev->dev, "Goto http://linux-lc100020.sourceforge.net for more info\n");
+ return err;
+ }
+
+ data = fw_entry->data;
+ len = fw_entry->size;
+
+ buf = kmalloc(1024, GFP_ATOMIC);
+ if (!buf)
+ goto exit;
+
+ while (len > 0) {
+ int translen = (len > 1024) ? 1024 : len;
+ memcpy(buf, data, translen);
+
+ err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0,
+ USB_DIR_OUT | 0x40, 0, 0, buf, translen,
+ ZD1201_FW_TIMEOUT);
+ if (err < 0)
+ goto exit;
+
+ len -= translen;
+ data += translen;
+ }
+
+ err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x2,
+ USB_DIR_OUT | 0x40, 0, 0, NULL, 0, ZD1201_FW_TIMEOUT);
+ if (err < 0)
+ goto exit;
+
+ err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4,
+ USB_DIR_IN | 0x40, 0,0, &ret, sizeof(ret), ZD1201_FW_TIMEOUT);
+ if (err < 0)
+ goto exit;
+
+ if (ret & 0x80) {
+ err = -EIO;
+ goto exit;
+ }
+
+ err = 0;
+exit:
+ if (buf)
+ kfree(buf);
+ release_firmware(fw_entry);
+ return err;
+}
+
+void zd1201_usbfree(struct urb *urb, struct pt_regs *regs)
+{
+ struct zd1201 *zd = urb->context;
+
+ switch(urb->status) {
+ case -EILSEQ:
+ case -ENODEV:
+ case -ETIMEDOUT:
+ case -ENOENT:
+ case -EPIPE:
+ case -EOVERFLOW:
+ case -ESHUTDOWN:
+ dev_warn(&zd->usb->dev, "%s: urb failed: %d\n",
+ zd->dev->name, urb->status);
+ }
+
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ return;
+}
+
+/* cmdreq message:
+ u32 type
+ u16 cmd
+ u16 parm0
+ u16 parm1
+ u16 parm2
+ u8 pad[4]
+
+ total: 4 + 2 + 2 + 2 + 2 + 4 = 16
+*/
+int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0, int parm1, int parm2)
+{
+ unsigned char *command;
+ int ret;
+ struct urb *urb;
+
+ command = kmalloc(16, GFP_ATOMIC);
+ if (!command)
+ return -ENOMEM;
+
+ *((__le32*)command) = cpu_to_le32(ZD1201_USB_CMDREQ);
+ *((__le16*)&command[4]) = cpu_to_le16(cmd);
+ *((__le16*)&command[6]) = cpu_to_le16(parm0);
+ *((__le16*)&command[8]) = cpu_to_le16(parm1);
+ *((__le16*)&command[10])= cpu_to_le16(parm2);
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ kfree(command);
+ return -ENOMEM;
+ }
+ usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2),
+ command, 16, zd1201_usbfree, zd);
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret) {
+ kfree(command);
+ usb_free_urb(urb);
+ }
+
+ return ret;
+}
+
+/* Callback after sending out a packet */
+void zd1201_usbtx(struct urb *urb, struct pt_regs *regs)
+{
+ struct zd1201 *zd = urb->context;
+ netif_wake_queue(zd->dev);
+ return;
+}
+
+/* Incomming data */
+void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
+{
+ struct zd1201 *zd = urb->context;
+ int free = 0;
+ unsigned char *data = urb->transfer_buffer;
+ struct sk_buff *skb;
+ unsigned char type;
+
+ if (!zd) {
+ free = 1;
+ goto exit;
+ }
+
+ switch(urb->status) {
+ case -EILSEQ:
+ case -ENODEV:
+ case -ETIMEDOUT:
+ case -ENOENT:
+ case -EPIPE:
+ case -EOVERFLOW:
+ case -ESHUTDOWN:
+ dev_warn(&zd->usb->dev, "%s: rx urb failed: %d\n",
+ zd->dev->name, urb->status);
+ free = 1;
+ goto exit;
+ }
+
+ if (urb->status != 0 || urb->actual_length == 0)
+ goto resubmit;
+
+ type = data[0];
+ if (type == ZD1201_PACKET_EVENTSTAT || type == ZD1201_PACKET_RESOURCE) {
+ memcpy(zd->rxdata, data, urb->actual_length);
+ zd->rxlen = urb->actual_length;
+ zd->rxdatas = 1;
+ wake_up(&zd->rxdataq);
+ }
+ /* Info frame */
+ if (type == ZD1201_PACKET_INQUIRE) {
+ int i = 0;
+ unsigned short infotype, framelen, copylen;
+ framelen = le16_to_cpu(*(__le16*)&data[4]);
+ infotype = le16_to_cpu(*(__le16*)&data[6]);
+
+ if (infotype == ZD1201_INF_LINKSTATUS) {
+ short linkstatus;
+
+ linkstatus = le16_to_cpu(*(__le16*)&data[8]);
+ switch(linkstatus) {
+ case 1:
+ netif_carrier_on(zd->dev);
+ break;
+ case 2:
+ netif_carrier_off(zd->dev);
+ break;
+ case 3:
+ netif_carrier_off(zd->dev);
+ break;
+ case 4:
+ netif_carrier_on(zd->dev);
+ break;
+ default:
+ netif_carrier_off(zd->dev);
+ }
+ goto resubmit;
+ }
+ if (infotype == ZD1201_INF_ASSOCSTATUS) {
+ short status = le16_to_cpu(*(__le16*)(data+8));
+ int event;
+ union iwreq_data wrqu;
+
+ switch (status) {
+ case ZD1201_ASSOCSTATUS_STAASSOC:
+ case ZD1201_ASSOCSTATUS_REASSOC:
+ event = IWEVREGISTERED;
+ break;
+ case ZD1201_ASSOCSTATUS_DISASSOC:
+ case ZD1201_ASSOCSTATUS_ASSOCFAIL:
+ case ZD1201_ASSOCSTATUS_AUTHFAIL:
+ default:
+ event = IWEVEXPIRED;
+ }
+ memcpy(wrqu.addr.sa_data, data+10, ETH_ALEN);
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+
+ /* Send event to user space */
+ wireless_send_event(zd->dev, event, &wrqu, NULL);
+
+ goto resubmit;
+ }
+ if (infotype == ZD1201_INF_AUTHREQ) {
+ union iwreq_data wrqu;
+
+ memcpy(wrqu.addr.sa_data, data+8, ETH_ALEN);
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+ /* There isn't a event that trully fits this request.
+ We assume that userspace will be smart enough to
+ see a new station being expired and sends back a
+ authstation ioctl to authorize it. */
+ wireless_send_event(zd->dev, IWEVEXPIRED, &wrqu, NULL);
+ goto resubmit;
+ }
+ /* Other infotypes are handled outside this handler */
+ zd->rxlen = 0;
+ while (i < urb->actual_length) {
+ copylen = le16_to_cpu(*(__le16*)&data[i+2]);
+ /* Sanity check, sometimes we get junk */
+ if (copylen+zd->rxlen > sizeof(zd->rxdata))
+ break;
+ memcpy(zd->rxdata+zd->rxlen, data+i+4, copylen);
+ zd->rxlen += copylen;
+ i += 64;
+ }
+ if (i >= urb->actual_length) {
+ zd->rxdatas = 1;
+ wake_up(&zd->rxdataq);
+ }
+ goto resubmit;
+ }
+ /* Actual data */
+ if (data[urb->actual_length-1] == ZD1201_PACKET_RXDATA) {
+ int datalen = urb->actual_length-1;
+ unsigned short len, fc, seq;
+ struct hlist_node *node;
+
+ len = ntohs(*(__be16 *)&data[datalen-2]);
+ if (len>datalen)
+ len=datalen;
+ fc = le16_to_cpu(*(__le16 *)&data[datalen-16]);
+ seq = le16_to_cpu(*(__le16 *)&data[datalen-24]);
+
+ if(zd->monitor) {
+ if (datalen < 24)
+ goto resubmit;
+ if (!(skb = dev_alloc_skb(datalen+24)))
+ goto resubmit;
+
+ memcpy(skb_put(skb, 2), &data[datalen-16], 2);
+ memcpy(skb_put(skb, 2), &data[datalen-2], 2);
+ memcpy(skb_put(skb, 6), &data[datalen-14], 6);
+ memcpy(skb_put(skb, 6), &data[datalen-22], 6);
+ memcpy(skb_put(skb, 6), &data[datalen-8], 6);
+ memcpy(skb_put(skb, 2), &data[datalen-24], 2);
+ memcpy(skb_put(skb, len), data, len);
+ skb->dev = zd->dev;
+ skb->dev->last_rx = jiffies;
+ skb->protocol = eth_type_trans(skb, zd->dev);
+ zd->stats.rx_packets++;
+ zd->stats.rx_bytes += skb->len;
+ netif_rx(skb);
+ goto resubmit;
+ }
+
+ if ((seq & IEEE802_11_SCTL_FRAG) ||
+ (fc & IEEE802_11_FCTL_MOREFRAGS)) {
+ struct zd1201_frag *frag = NULL;
+ char *ptr;
+
+ if (datalen<14)
+ goto resubmit;
+ if ((seq & IEEE802_11_SCTL_FRAG) == 0) {
+ frag = kmalloc(sizeof(struct zd1201_frag*),
+ GFP_ATOMIC);
+ if (!frag)
+ goto resubmit;
+ skb = dev_alloc_skb(IEEE802_11_DATA_LEN +14+2);
+ if (!skb) {
+ kfree(frag);
+ goto resubmit;
+ }
+ frag->skb = skb;
+ frag->seq = seq & IEEE802_11_SCTL_SEQ;
+ skb_reserve(skb, 2);
+ memcpy(skb_put(skb, 12), &data[datalen-14], 12);
+ memcpy(skb_put(skb, 2), &data[6], 2);
+ memcpy(skb_put(skb, len), data+8, len);
+ hlist_add_head(&frag->fnode, &zd->fraglist);
+ goto resubmit;
+ }
+ hlist_for_each_entry(frag, node, &zd->fraglist, fnode)
+ if(frag->seq == (seq&IEEE802_11_SCTL_SEQ))
+ break;
+ if (!frag)
+ goto resubmit;
+ skb = frag->skb;
+ ptr = skb_put(skb, len);
+ if (ptr)
+ memcpy(ptr, data+8, len);
+ if (fc & IEEE802_11_FCTL_MOREFRAGS)
+ goto resubmit;
+ hlist_del_init(&frag->fnode);
+ kfree(frag);
+ /* Fallthrough */
+ } else {
+ if (datalen<14)
+ goto resubmit;
+ skb = dev_alloc_skb(len + 14 + 2);
+ if (!skb)
+ goto resubmit;
+ skb_reserve(skb, 2);
+ memcpy(skb_put(skb, 12), &data[datalen-14], 12);
+ memcpy(skb_put(skb, 2), &data[6], 2);
+ memcpy(skb_put(skb, len), data+8, len);
+ }
+ skb->dev = zd->dev;
+ skb->dev->last_rx = jiffies;
+ skb->protocol = eth_type_trans(skb, zd->dev);
+ zd->stats.rx_packets++;
+ zd->stats.rx_bytes += skb->len;
+ netif_rx(skb);
+ }
+resubmit:
+ memset(data, 0, ZD1201_RXSIZE);
+
+ urb->status = 0;
+ urb->dev = zd->usb;
+ if(usb_submit_urb(urb, GFP_ATOMIC))
+ free = 1;
+
+exit:
+ if (free) {
+ zd->rxlen = 0;
+ zd->rxdatas = 1;
+ wake_up(&zd->rxdataq);
+ kfree(urb->transfer_buffer);
+ }
+ return;
+}
+
+static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata,
+ unsigned int riddatalen)
+{
+ int err;
+ int i = 0;
+ int code;
+ int rid_fid;
+ int length;
+ unsigned char *pdata;
+
+ zd->rxdatas = 0;
+ err = zd1201_docmd(zd, ZD1201_CMDCODE_ACCESS, rid, 0, 0);
+ if (err)
+ return err;
+
+ wait_event_interruptible(zd->rxdataq, zd->rxdatas);
+ if (!zd->rxlen)
+ return -EIO;
+
+ code = le16_to_cpu(*(__le16*)(&zd->rxdata[4]));
+ rid_fid = le16_to_cpu(*(__le16*)(&zd->rxdata[6]));
+ length = le16_to_cpu(*(__le16*)(&zd->rxdata[8]));
+ if (length > zd->rxlen)
+ length = zd->rxlen-6;
+
+ /* If access bit is not on, then error */
+ if ((code & ZD1201_ACCESSBIT) != ZD1201_ACCESSBIT || rid_fid != rid )
+ return -EINVAL;
+
+ /* Not enough buffer for allocating data */
+ if (riddatalen != (length - 4)) {
+ dev_dbg(&zd->usb->dev, "riddatalen mismatches, expected=%u, (packet=%u) length=%u, rid=0x%04X, rid_fid=0x%04X\n",
+ riddatalen, zd->rxlen, length, rid, rid_fid);
+ return -ENODATA;
+ }
+
+ zd->rxdatas = 0;
+ /* Issue SetRxRid commnd */
+ err = zd1201_docmd(zd, ZD1201_CMDCODE_SETRXRID, rid, 0, length);
+ if (err)
+ return err;
+
+ /* Receive RID record from resource packets */
+ wait_event_interruptible(zd->rxdataq, zd->rxdatas);
+ if (!zd->rxlen)
+ return -EIO;
+
+ if (zd->rxdata[zd->rxlen - 1] != ZD1201_PACKET_RESOURCE) {
+ dev_dbg(&zd->usb->dev, "Packet type mismatch: 0x%x not 0x3\n",
+ zd->rxdata[zd->rxlen-1]);
+ return -EINVAL;
+ }
+
+ /* Set the data pointer and received data length */
+ pdata = zd->rxdata;
+ length = zd->rxlen;
+
+ do {
+ int actual_length;
+
+ actual_length = (length > 64) ? 64 : length;
+
+ if(pdata[0] != 0x3) {
+ dev_dbg(&zd->usb->dev, "Rx Resource packet type error: %02X\n",
+ pdata[0]);
+ return -EINVAL;
+ }
+
+ if (actual_length != 64) {
+ /* Trim the last packet type byte */
+ actual_length--;
+ }
+
+ /* Skip the 4 bytes header (RID length and RID) */
+ if(i == 0) {
+ pdata += 8;
+ actual_length -= 8;
+ }
+ else {
+ pdata += 4;
+ actual_length -= 4;
+ }
+
+ memcpy(riddata, pdata, actual_length);
+ riddata += actual_length;
+ pdata += actual_length;
+ length -= 64;
+ i++;
+ } while (length > 0);
+
+ return 0;
+}
+
+/*
+ * resreq:
+ * byte type
+ * byte sequence
+ * u16 reserved
+ * byte data[12]
+ * total: 16
+ */
+static int zd1201_setconfig(struct zd1201 *zd, int rid, void *buf, int len, int wait)
+{
+ int err;
+ unsigned char *request;
+ int reqlen;
+ char seq=0;
+ struct urb *urb;
+ unsigned int gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC;
+
+ len += 4; /* first 4 are for header */
+
+ zd->rxdatas = 0;
+ zd->rxlen = 0;
+ for (seq=0; len > 0; seq++) {
+ request = kmalloc(16, gfp_mask);
+ if (!request)
+ return -ENOMEM;
+ urb = usb_alloc_urb(0, gfp_mask);
+ if (!urb) {
+ kfree(request);
+ return -ENOMEM;
+ }
+ memset(request, 0, 16);
+ reqlen = len>12 ? 12 : len;
+ request[0] = ZD1201_USB_RESREQ;
+ request[1] = seq;
+ request[2] = 0;
+ request[3] = 0;
+ if (request[1] == 0) {
+ /* add header */
+ *(__le16*)&request[4] = cpu_to_le16((len-2+1)/2);
+ *(__le16*)&request[6] = cpu_to_le16(rid);
+ memcpy(request+8, buf, reqlen-4);
+ buf += reqlen-4;
+ } else {
+ memcpy(request+4, buf, reqlen);
+ buf += reqlen;
+ }
+
+ len -= reqlen;
+
+ usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb,
+ zd->endp_out2), request, 16, zd1201_usbfree, zd);
+ err = usb_submit_urb(urb, gfp_mask);
+ if (err)
+ goto err;
+ }
+
+ request = kmalloc(16, gfp_mask);
+ if (!request)
+ return -ENOMEM;
+ urb = usb_alloc_urb(0, gfp_mask);
+ if (!urb) {
+ kfree(request);
+ return -ENOMEM;
+ }
+ *((__le32*)request) = cpu_to_le32(ZD1201_USB_CMDREQ);
+ *((__le16*)&request[4]) =
+ cpu_to_le16(ZD1201_CMDCODE_ACCESS|ZD1201_ACCESSBIT);
+ *((__le16*)&request[6]) = cpu_to_le16(rid);
+ *((__le16*)&request[8]) = cpu_to_le16(0);
+ *((__le16*)&request[10]) = cpu_to_le16(0);
+ usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2),
+ request, 16, zd1201_usbfree, zd);
+ err = usb_submit_urb(urb, gfp_mask);
+ if (err)
+ goto err;
+
+ if (wait) {
+ wait_event_interruptible(zd->rxdataq, zd->rxdatas);
+ if (!zd->rxlen || le16_to_cpu(*(__le16*)&zd->rxdata[6]) != rid) {
+ dev_dbg(&zd->usb->dev, "wrong or no RID received\n");
+ }
+ }
+
+ return 0;
+err:
+ kfree(request);
+ usb_free_urb(urb);
+ return err;
+}
+
+static inline int zd1201_getconfig16(struct zd1201 *zd, int rid, short *val)
+{
+ int err;
+ __le16 zdval;
+
+ err = zd1201_getconfig(zd, rid, &zdval, sizeof(__le16));
+ if (err)
+ return err;
+ *val = le16_to_cpu(zdval);
+ return 0;
+}
+
+static inline int zd1201_setconfig16(struct zd1201 *zd, int rid, short val)
+{
+ __le16 zdval = cpu_to_le16(val);
+ return (zd1201_setconfig(zd, rid, &zdval, sizeof(__le16), 1));
+}
+
+int zd1201_drvr_start(struct zd1201 *zd)
+{
+ int err, i;
+ short max;
+ __le16 zdmax;
+ unsigned char *buffer;
+
+ buffer = kmalloc(ZD1201_RXSIZE, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ memset(buffer, 0, ZD1201_RXSIZE);
+
+ usb_fill_bulk_urb(zd->rx_urb, zd->usb,
+ usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE,
+ zd1201_usbrx, zd);
+
+ err = usb_submit_urb(zd->rx_urb, GFP_KERNEL);
+ if (err)
+ goto err_buffer;
+
+ err = zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);
+ if (err)
+ goto err_urb;
+
+ err = zd1201_getconfig(zd, ZD1201_RID_CNFMAXTXBUFFERNUMBER, &zdmax,
+ sizeof(__le16));
+ if (err)
+ goto err_urb;
+
+ max = le16_to_cpu(zdmax);
+ for (i=0; i<max; i++) {
+ err = zd1201_docmd(zd, ZD1201_CMDCODE_ALLOC, 1514, 0, 0);
+ if (err)
+ goto err_urb;
+ }
+
+ return 0;
+
+err_urb:
+ usb_kill_urb(zd->rx_urb);
+ return err;
+err_buffer:
+ kfree(buffer);
+ return err;
+}
+
+/* Magic alert: The firmware doesn't seem to like the MAC state being
+ * toggled in promisc (aka monitor) mode.
+ * (It works a number of times, but will halt eventually)
+ * So we turn it of before disabling and on after enabling if needed.
+ */
+static int zd1201_enable(struct zd1201 *zd)
+{
+ int err;
+
+ if (zd->mac_enabled)
+ return 0;
+
+ err = zd1201_docmd(zd, ZD1201_CMDCODE_ENABLE, 0, 0, 0);
+ if (!err);
+ zd->mac_enabled = 1;
+
+ if (zd->monitor)
+ err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 1);
+
+ return err;
+}
+
+static int zd1201_disable(struct zd1201 *zd)
+{
+ int err;
+
+ if (!zd->mac_enabled)
+ return 0;
+ if (zd->monitor) {
+ err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0);
+ if (err);
+ return err;
+ }
+
+ err = zd1201_docmd(zd, ZD1201_CMDCODE_DISABLE, 0, 0, 0);
+ if (!err)
+ zd->mac_enabled = 0;
+ return err;
+}
+
+static int zd1201_mac_reset(struct zd1201 *zd)
+{
+ if (!zd->mac_enabled)
+ return 0;
+ zd1201_disable(zd);
+ return zd1201_enable(zd);
+}
+
+static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen)
+{
+ int err, val;
+ char buf[IW_ESSID_MAX_SIZE+2];
+
+ err = zd1201_disable(zd);
+ if (err)
+ return err;
+
+ val = ZD1201_CNFAUTHENTICATION_OPENSYSTEM;
+ val |= ZD1201_CNFAUTHENTICATION_SHAREDKEY;
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, val);
+ if (err)
+ return err;
+
+ *(__le16 *)buf = cpu_to_le16(essidlen);
+ memcpy(buf+2, essid, essidlen);
+ if (!zd->ap) { /* Normal station */
+ err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf,
+ IW_ESSID_MAX_SIZE+2, 1);
+ if (err)
+ return err;
+ } else { /* AP */
+ err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNSSID, buf,
+ IW_ESSID_MAX_SIZE+2, 1);
+ if (err)
+ return err;
+ }
+
+ err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR,
+ zd->dev->dev_addr, zd->dev->addr_len, 1);
+ if (err)
+ return err;
+
+ err = zd1201_enable(zd);
+ if (err)
+ return err;
+
+ msleep(100);
+ return 0;
+}
+
+static int zd1201_net_open(struct net_device *dev)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+ /* Start MAC with wildcard if no essid set */
+ if (!zd->mac_enabled)
+ zd1201_join(zd, zd->essid, zd->essidlen);
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static int zd1201_net_stop(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+
+ return 0;
+}
+
+/*
+ RFC 1042 encapsulates Ethernet frames in 802.11 frames
+ by prefixing them with 0xaa, 0xaa, 0x03) followed by a SNAP OID of 0
+ (0x00, 0x00, 0x00). Zd requires an additionnal padding, copy
+ of ethernet addresses, length of the standard RFC 1042 packet
+ and a command byte (which is nul for tx).
+
+ tx frame (from Wlan NG):
+ RFC 1042:
+ llc 0xAA 0xAA 0x03 (802.2 LLC)
+ snap 0x00 0x00 0x00 (Ethernet encapsulated)
+ type 2 bytes, Ethernet type field
+ payload (minus eth header)
+ Zydas specific:
+ padding 1B if (skb->len+8+1)%64==0
+ Eth MAC addr 12 bytes, Ethernet MAC addresses
+ length 2 bytes, RFC 1042 packet length
+ (llc+snap+type+payload)
+ zd 1 null byte, zd1201 packet type
+ */
+static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ unsigned char *txbuf = zd->txdata;
+ int txbuflen, pad = 0, err;
+ struct urb *urb = zd->tx_urb;
+
+ if (!zd->mac_enabled || zd->monitor) {
+ zd->stats.tx_dropped++;
+ kfree_skb(skb);
+ return 0;
+ }
+ netif_stop_queue(dev);
+
+ txbuflen = skb->len + 8 + 1;
+ if (txbuflen%64 == 0) {
+ pad = 1;
+ txbuflen++;
+ }
+ txbuf[0] = 0xAA;
+ txbuf[1] = 0xAA;
+ txbuf[2] = 0x03;
+ txbuf[3] = 0x00; /* rfc1042 */
+ txbuf[4] = 0x00;
+ txbuf[5] = 0x00;
+
+ memcpy(txbuf+6, skb->data+12, skb->len-12);
+ if (pad)
+ txbuf[skb->len-12+6]=0;
+ memcpy(txbuf+skb->len-12+6+pad, skb->data, 12);
+ *(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6);
+ txbuf[txbuflen-1] = 0;
+
+ usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out),
+ txbuf, txbuflen, zd1201_usbtx, zd);
+
+ err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC);
+ if (err) {
+ zd->stats.tx_errors++;
+ netif_start_queue(dev);
+ return err;
+ }
+ zd->stats.tx_packets++;
+ zd->stats.tx_bytes += skb->len;
+ dev->trans_start = jiffies;
+ kfree_skb(skb);
+
+ return 0;
+}
+
+static void zd1201_tx_timeout(struct net_device *dev)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+ if (!zd)
+ return;
+ dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n",
+ dev->name);
+ zd->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
+ usb_unlink_urb(zd->tx_urb);
+ zd->stats.tx_errors++;
+ /* Restart the timeout to quiet the watchdog: */
+ dev->trans_start = jiffies;
+}
+
+static int zd1201_set_mac_address(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ int err;
+
+ if (!zd)
+ return -ENODEV;
+
+ err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR,
+ addr->sa_data, dev->addr_len, 1);
+ if (err)
+ return err;
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ return zd1201_mac_reset(zd);
+}
+
+static struct net_device_stats *zd1201_get_stats(struct net_device *dev)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+ return &zd->stats;
+}
+
+static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+ return &zd->iwstats;
+}
+
+static void zd1201_set_multicast(struct net_device *dev)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct dev_mc_list *mc = dev->mc_list;
+ unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI];
+ int i;
+
+ if (dev->mc_count > ZD1201_MAXMULTI)
+ return;
+
+ for (i=0; i<dev->mc_count; i++) {
+ memcpy(reqbuf+i*ETH_ALEN, mc->dmi_addr, ETH_ALEN);
+ mc = mc->next;
+ }
+ zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf,
+ dev->mc_count*ETH_ALEN, 0);
+
+}
+
+static int zd1201_config_commit(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *data, char *essid)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+ return zd1201_mac_reset(zd);
+}
+
+static int zd1201_get_name(struct net_device *dev,
+ struct iw_request_info *info, char *name, char *extra)
+{
+ strcpy(name, "IEEE 802.11b");
+
+ return 0;
+}
+
+static int zd1201_set_freq(struct net_device *dev,
+ struct iw_request_info *info, struct iw_freq *freq, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short channel = 0;
+ int err;
+
+ if (freq->e == 0)
+ channel = freq->m;
+ else {
+ if (freq->m >= 2482)
+ channel = 14;
+ if (freq->m >= 2407)
+ channel = (freq->m-2407)/5;
+ }
+
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel);
+ if (err)
+ return err;
+
+ zd1201_mac_reset(zd);
+
+ return 0;
+}
+
+static int zd1201_get_freq(struct net_device *dev,
+ struct iw_request_info *info, struct iw_freq *freq, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short channel;
+ int err;
+
+ err = zd1201_getconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, &channel);
+ if (err)
+ return err;
+ freq->e = 0;
+ freq->m = channel;
+
+ return 0;
+}
+
+static int zd1201_set_mode(struct net_device *dev,
+ struct iw_request_info *info, __u32 *mode, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short porttype, monitor = 0;
+ unsigned char buffer[IW_ESSID_MAX_SIZE+2];
+ int err;
+
+ if (zd->ap) {
+ if (*mode != IW_MODE_MASTER)
+ return -EINVAL;
+ return 0;
+ }
+
+ err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0);
+ if (err)
+ return err;
+ zd->dev->type = ARPHRD_ETHER;
+ switch(*mode) {
+ case IW_MODE_MONITOR:
+ monitor = 1;
+ zd->dev->type = ARPHRD_IEEE80211;
+ /* Make sure we are no longer associated with by
+ setting an 'impossible' essid.
+ (otherwise we mess up firmware)
+ */
+ zd1201_join(zd, "\0-*#\0", 5);
+ /* Put port in pIBSS */
+ case 8: /* No pseudo-IBSS in wireless extensions (yet) */
+ porttype = ZD1201_PORTTYPE_PSEUDOIBSS;
+ break;
+ case IW_MODE_ADHOC:
+ porttype = ZD1201_PORTTYPE_IBSS;
+ break;
+ case IW_MODE_INFRA:
+ porttype = ZD1201_PORTTYPE_BSS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype);
+ if (err)
+ return err;
+ if (zd->monitor && !monitor) {
+ zd1201_disable(zd);
+ *(__le16 *)buffer = cpu_to_le16(zd->essidlen);
+ memcpy(buffer+2, zd->essid, zd->essidlen);
+ err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID,
+ buffer, IW_ESSID_MAX_SIZE+2, 1);
+ if (err)
+ return err;
+ }
+ zd->monitor=monitor;
+ /* If monitor mode is set we don't actually turn it on here since it
+ * is done during mac reset anyway (see zd1201_mac_enable).
+ */
+
+ zd1201_mac_reset(zd);
+
+ return 0;
+}
+
+static int zd1201_get_mode(struct net_device *dev,
+ struct iw_request_info *info, __u32 *mode, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short porttype;
+ int err;
+
+ err = zd1201_getconfig16(zd, ZD1201_RID_CNFPORTTYPE, &porttype);
+ if (err)
+ return err;
+ switch(porttype) {
+ case ZD1201_PORTTYPE_IBSS:
+ *mode = IW_MODE_ADHOC;
+ break;
+ case ZD1201_PORTTYPE_BSS:
+ *mode = IW_MODE_INFRA;
+ break;
+ case ZD1201_PORTTYPE_WDS:
+ *mode = IW_MODE_REPEAT;
+ break;
+ case ZD1201_PORTTYPE_PSEUDOIBSS:
+ *mode = 8;/* No Pseudo-IBSS... */
+ break;
+ case ZD1201_PORTTYPE_AP:
+ *mode = IW_MODE_MASTER;
+ break;
+ default:
+ dev_dbg(&zd->usb->dev, "Unknown porttype: %d\n",
+ porttype);
+ *mode = IW_MODE_AUTO;
+ }
+ if (zd->monitor)
+ *mode = IW_MODE_MONITOR;
+
+ return 0;
+}
+
+static int zd1201_get_range(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *wrq, char *extra)
+{
+ struct iw_range *range = (struct iw_range *)extra;
+
+ wrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = WIRELESS_EXT;
+
+ range->max_qual.qual = 128;
+ range->max_qual.level = 128;
+ range->max_qual.noise = 128;
+ range->max_qual.updated = 7;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = ZD1201_NUMKEYS;
+
+ range->num_bitrates = 4;
+ range->bitrate[0] = 1000000;
+ range->bitrate[1] = 2000000;
+ range->bitrate[2] = 5500000;
+ range->bitrate[3] = 11000000;
+
+ range->min_rts = 0;
+ range->min_frag = ZD1201_FRAGMIN;
+ range->max_rts = ZD1201_RTSMAX;
+ range->min_frag = ZD1201_FRAGMAX;
+
+ return 0;
+}
+
+/* Little bit of magic here: we only get the quality if we poll
+ * for it, and we never get an actual request to trigger such
+ * a poll. Therefore we 'asume' that the user will soon ask for
+ * the stats after asking the bssid.
+ */
+static int zd1201_get_wap(struct net_device *dev,
+ struct iw_request_info *info, struct sockaddr *ap_addr, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ unsigned char buffer[6];
+
+ if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) {
+ /* Unfortunatly the quality and noise reported is useless.
+ they seem to be accumulators that increase until you
+ read them, unless we poll on a fixed interval we can't
+ use them
+ */
+ /*zd->iwstats.qual.qual = le16_to_cpu(((__le16 *)buffer)[0]);*/
+ zd->iwstats.qual.level = le16_to_cpu(((__le16 *)buffer)[1]);
+ /*zd->iwstats.qual.noise = le16_to_cpu(((__le16 *)buffer)[2]);*/
+ zd->iwstats.qual.updated = 2;
+ }
+
+ return zd1201_getconfig(zd,ZD1201_RID_CURRENTBSSID,ap_addr->sa_data,6);
+}
+
+static int zd1201_set_scan(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *srq, char *extra)
+{
+ /* We do everything in get_scan */
+ return 0;
+}
+
+static int zd1201_get_scan(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *srq, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ int err, i, j, enabled_save;
+ struct iw_event iwe;
+ char *cev = extra;
+ char *end_buf = extra + IW_SCAN_MAX_DATA;
+
+ /* No scanning in AP mode */
+ if (zd->ap)
+ return -EOPNOTSUPP;
+
+ /* Scan doesn't seem to work if disabled */
+ enabled_save = zd->mac_enabled;
+ zd1201_enable(zd);
+
+ zd->rxdatas = 0;
+ err = zd1201_docmd(zd, ZD1201_CMDCODE_INQUIRE,
+ ZD1201_INQ_SCANRESULTS, 0, 0);
+ if (err)
+ return err;
+
+ wait_event_interruptible(zd->rxdataq, zd->rxdatas);
+ if (!zd->rxlen)
+ return -EIO;
+
+ if (le16_to_cpu(*(__le16*)&zd->rxdata[2]) != ZD1201_INQ_SCANRESULTS)
+ return -EIO;
+
+ for(i=8; i<zd->rxlen; i+=62) {
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6);
+ cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.length = zd->rxdata[i+16];
+ iwe.u.data.flags = 1;
+ cev = iwe_stream_add_point(cev, end_buf, &iwe, zd->rxdata+i+18);
+
+ iwe.cmd = SIOCGIWMODE;
+ if (zd->rxdata[i+14]&0x01)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_ADHOC;
+ cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN);
+
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = zd->rxdata[i+0];
+ iwe.u.freq.e = 0;
+ cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_FREQ_LEN);
+
+ iwe.cmd = SIOCGIWRATE;
+ iwe.u.bitrate.fixed = 0;
+ iwe.u.bitrate.disabled = 0;
+ for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) {
+ iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000;
+ cev=iwe_stream_add_event(cev, end_buf, &iwe,
+ IW_EV_PARAM_LEN);
+ }
+
+ iwe.cmd = SIOCGIWENCODE;
+ iwe.u.data.length = 0;
+ if (zd->rxdata[i+14]&0x10)
+ iwe.u.data.flags = IW_ENCODE_ENABLED;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ cev = iwe_stream_add_point(cev, end_buf, &iwe, NULL);
+
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.qual = zd->rxdata[i+4];
+ iwe.u.qual.noise= zd->rxdata[i+2]/10-100;
+ iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100;
+ iwe.u.qual.updated = 7;
+ cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN);
+ }
+
+ if (!enabled_save)
+ zd1201_disable(zd);
+
+ srq->length = cev - extra;
+ srq->flags = 0;
+
+ return 0;
+}
+
+static int zd1201_set_essid(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *data, char *essid)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+ if (data->length > IW_ESSID_MAX_SIZE)
+ return -EINVAL;
+ if (data->length < 1)
+ data->length = 1;
+ zd->essidlen = data->length-1;
+ memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1);
+ memcpy(zd->essid, essid, data->length);
+ return zd1201_join(zd, zd->essid, zd->essidlen);
+}
+
+static int zd1201_get_essid(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *data, char *essid)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+
+ memcpy(essid, zd->essid, zd->essidlen);
+ data->flags = 1;
+ data->length = zd->essidlen;
+
+ return 0;
+}
+
+static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *data, char *nick)
+{
+ strcpy(nick, "zd1201");
+ data->flags = 1;
+ data->length = strlen(nick);
+ return 0;
+}
+
+static int zd1201_set_rate(struct net_device *dev,
+ struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short rate;
+ int err;
+
+ switch (rrq->value) {
+ case 1000000:
+ rate = ZD1201_RATEB1;
+ break;
+ case 2000000:
+ rate = ZD1201_RATEB2;
+ break;
+ case 5500000:
+ rate = ZD1201_RATEB5;
+ break;
+ case 11000000:
+ default:
+ rate = ZD1201_RATEB11;
+ break;
+ }
+ if (!rrq->fixed) { /* Also enable all lower bitrates */
+ rate |= rate-1;
+ }
+
+ err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, rate);
+ if (err)
+ return err;
+
+ return zd1201_mac_reset(zd);
+}
+
+static int zd1201_get_rate(struct net_device *dev,
+ struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short rate;
+ int err;
+
+ err = zd1201_getconfig16(zd, ZD1201_RID_CURRENTTXRATE, &rate);
+ if (err)
+ return err;
+
+ switch(rate) {
+ case 1:
+ rrq->value = 1000000;
+ break;
+ case 2:
+ rrq->value = 2000000;
+ break;
+ case 5:
+ rrq->value = 5500000;
+ break;
+ case 11:
+ rrq->value = 11000000;
+ break;
+ default:
+ rrq->value = 0;
+ }
+ rrq->fixed = 0;
+ rrq->disabled = 0;
+
+ return 0;
+}
+
+static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ int err;
+ short val = rts->value;
+
+ if (rts->disabled || !rts->fixed)
+ val = ZD1201_RTSMAX;
+ if (val > ZD1201_RTSMAX)
+ return -EINVAL;
+ if (val < 0)
+ return -EINVAL;
+
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, val);
+ if (err)
+ return err;
+ return zd1201_mac_reset(zd);
+}
+
+static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short rtst;
+ int err;
+
+ err = zd1201_getconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, &rtst);
+ if (err)
+ return err;
+ rts->value = rtst;
+ rts->disabled = (rts->value == ZD1201_RTSMAX);
+ rts->fixed = 1;
+
+ return 0;
+}
+
+static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *frag, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ int err;
+ short val = frag->value;
+
+ if (frag->disabled || !frag->fixed)
+ val = ZD1201_FRAGMAX;
+ if (val > ZD1201_FRAGMAX)
+ return -EINVAL;
+ if (val < ZD1201_FRAGMIN)
+ return -EINVAL;
+ if (val & 1)
+ return -EINVAL;
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, val);
+ if (err)
+ return err;
+ return zd1201_mac_reset(zd);
+}
+
+static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *frag, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short fragt;
+ int err;
+
+ err = zd1201_getconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, &fragt);
+ if (err)
+ return err;
+ frag->value = fragt;
+ frag->disabled = (frag->value == ZD1201_FRAGMAX);
+ frag->fixed = 1;
+
+ return 0;
+}
+
+static int zd1201_set_retry(struct net_device *dev,
+ struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+ return 0;
+}
+
+static int zd1201_get_retry(struct net_device *dev,
+ struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+ return 0;
+}
+
+static int zd1201_set_encode(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *erq, char *key)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short i;
+ int err, rid;
+
+ if (erq->length > ZD1201_MAXKEYLEN)
+ return -EINVAL;
+
+ i = (erq->flags & IW_ENCODE_INDEX)-1;
+ if (i == -1) {
+ err = zd1201_getconfig16(zd,ZD1201_RID_CNFDEFAULTKEYID,&i);
+ if (err)
+ return err;
+ } else {
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, i);
+ if (err)
+ return err;
+ }
+
+ if (i < 0 || i >= ZD1201_NUMKEYS)
+ return -EINVAL;
+
+ rid = ZD1201_RID_CNFDEFAULTKEY0 + i;
+ err = zd1201_setconfig(zd, rid, key, erq->length, 1);
+ if (err)
+ return err;
+ zd->encode_keylen[i] = erq->length;
+ memcpy(zd->encode_keys[i], key, erq->length);
+
+ i=0;
+ if (!(erq->flags & IW_ENCODE_DISABLED & IW_ENCODE_MODE)) {
+ i |= 0x01;
+ zd->encode_enabled = 1;
+ } else
+ zd->encode_enabled = 0;
+ if (erq->flags & IW_ENCODE_RESTRICTED & IW_ENCODE_MODE) {
+ i |= 0x02;
+ zd->encode_restricted = 1;
+ } else
+ zd->encode_restricted = 0;
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFWEBFLAGS, i);
+ if (err)
+ return err;
+
+ if (zd->encode_enabled)
+ i = ZD1201_CNFAUTHENTICATION_SHAREDKEY;
+ else
+ i = ZD1201_CNFAUTHENTICATION_OPENSYSTEM;
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, i);
+ if (err)
+ return err;
+
+ return zd1201_mac_reset(zd);
+}
+
+static int zd1201_get_encode(struct net_device *dev,
+ struct iw_request_info *info, struct iw_point *erq, char *key)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short i;
+ int err;
+
+ if (zd->encode_enabled)
+ erq->flags = IW_ENCODE_ENABLED;
+ else
+ erq->flags = IW_ENCODE_DISABLED;
+ if (zd->encode_restricted)
+ erq->flags |= IW_ENCODE_RESTRICTED;
+ else
+ erq->flags |= IW_ENCODE_OPEN;
+
+ i = (erq->flags & IW_ENCODE_INDEX) -1;
+ if (i == -1) {
+ err = zd1201_getconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, &i);
+ if (err)
+ return err;
+ }
+ if (i<0 || i>= ZD1201_NUMKEYS)
+ return -EINVAL;
+
+ erq->flags |= i+1;
+
+ erq->length = zd->encode_keylen[i];
+ memcpy(key, zd->encode_keys[i], erq->length);
+
+ return 0;
+}
+
+static int zd1201_set_power(struct net_device *dev,
+ struct iw_request_info *info, struct iw_param *vwrq, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short enabled, duration, level;
+ int err;
+
+ enabled = vwrq->disabled ? 0 : 1;
+ if (enabled) {
+ if (vwrq->flags & IW_POWER_PERIOD) {
+ duration = vwrq->value;
+ err = zd1201_setconfig16(zd,
+ ZD1201_RID_CNFMAXSLEEPDURATION, duration);
+ if (err)
+ return err;
+ goto out;
+ }
+ if (vwrq->flags & IW_POWER_TIMEOUT) {
+ err = zd1201_getconfig16(zd,
+ ZD1201_RID_CNFMAXSLEEPDURATION, &duration);
+ if (err)
+ return err;
+ level = vwrq->value * 4 / duration;
+ if (level > 4)
+ level = 4;
+ if (level < 0)
+ level = 0;
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMEPS,
+ level);
+ if (err)
+ return err;
+ goto out;
+ }
+ return -EINVAL;
+ }
+out:
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMENABLED, enabled);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int zd1201_get_power(struct net_device *dev,
+ struct iw_request_info *info, struct iw_param *vwrq, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short enabled, level, duration;
+ int err;
+
+ err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMENABLED, &enabled);
+ if (err)
+ return err;
+ err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMEPS, &level);
+ if (err)
+ return err;
+ err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXSLEEPDURATION, &duration);
+ if (err)
+ return err;
+ vwrq->disabled = enabled ? 0 : 1;
+ if (vwrq->flags & IW_POWER_TYPE) {
+ if (vwrq->flags & IW_POWER_PERIOD) {
+ vwrq->value = duration;
+ vwrq->flags = IW_POWER_PERIOD;
+ } else {
+ vwrq->value = duration * level / 4;
+ vwrq->flags = IW_POWER_TIMEOUT;
+ }
+ }
+ if (vwrq->flags & IW_POWER_MODE) {
+ if (enabled && level)
+ vwrq->flags = IW_POWER_UNICAST_R;
+ else
+ vwrq->flags = IW_POWER_ALL_R;
+ }
+
+ return 0;
+}
+
+
+static const iw_handler zd1201_iw_handler[] =
+{
+ (iw_handler) zd1201_config_commit, /* SIOCSIWCOMMIT */
+ (iw_handler) zd1201_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) zd1201_set_freq, /* SIOCSIWFREQ */
+ (iw_handler) zd1201_get_freq, /* SIOCGIWFREQ */
+ (iw_handler) zd1201_set_mode, /* SIOCSIWMODE */
+ (iw_handler) zd1201_get_mode, /* SIOCGIWMODE */
+ (iw_handler) NULL, /* SIOCSIWSENS */
+ (iw_handler) NULL, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* SIOCSIWRANGE */
+ (iw_handler) zd1201_get_range, /* SIOCGIWRANGE */
+ (iw_handler) NULL, /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* SIOCSIWSTATS */
+ (iw_handler) NULL, /* SIOCGIWSTATS */
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL/*zd1201_set_wap*/, /* SIOCSIWAP */
+ (iw_handler) zd1201_get_wap, /* SIOCGIWAP */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* SIOCGIWAPLIST */
+ (iw_handler) zd1201_set_scan, /* SIOCSIWSCAN */
+ (iw_handler) zd1201_get_scan, /* SIOCGIWSCAN */
+ (iw_handler) zd1201_set_essid, /* SIOCSIWESSID */
+ (iw_handler) zd1201_get_essid, /* SIOCGIWESSID */
+ (iw_handler) NULL, /* SIOCSIWNICKN */
+ (iw_handler) zd1201_get_nick, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) zd1201_set_rate, /* SIOCSIWRATE */
+ (iw_handler) zd1201_get_rate, /* SIOCGIWRATE */
+ (iw_handler) zd1201_set_rts, /* SIOCSIWRTS */
+ (iw_handler) zd1201_get_rts, /* SIOCGIWRTS */
+ (iw_handler) zd1201_set_frag, /* SIOCSIWFRAG */
+ (iw_handler) zd1201_get_frag, /* SIOCGIWFRAG */
+ (iw_handler) NULL, /* SIOCSIWTXPOW */
+ (iw_handler) NULL, /* SIOCGIWTXPOW */
+ (iw_handler) zd1201_set_retry, /* SIOCSIWRETRY */
+ (iw_handler) zd1201_get_retry, /* SIOCGIWRETRY */
+ (iw_handler) zd1201_set_encode, /* SIOCSIWENCODE */
+ (iw_handler) zd1201_get_encode, /* SIOCGIWENCODE */
+ (iw_handler) zd1201_set_power, /* SIOCSIWPOWER */
+ (iw_handler) zd1201_get_power, /* SIOCGIWPOWER */
+};
+
+static int zd1201_set_hostauth(struct net_device *dev,
+ struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ int err;
+
+ if (!zd->ap)
+ return -EOPNOTSUPP;
+
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFHOSTAUTH, rrq->value);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int zd1201_get_hostauth(struct net_device *dev,
+ struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short hostauth;
+ int err;
+
+ if (!zd->ap)
+ return -EOPNOTSUPP;
+
+ err = zd1201_getconfig16(zd, ZD1201_RID_CNFHOSTAUTH, &hostauth);
+ if (err)
+ return err;
+ rrq->value = hostauth;
+ rrq->fixed = 1;
+
+ return 0;
+}
+
+static int zd1201_auth_sta(struct net_device *dev,
+ struct iw_request_info *info, struct sockaddr *sta, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ unsigned char buffer[10];
+
+ if (!zd->ap)
+ return -EOPNOTSUPP;
+
+ memcpy(buffer, sta->sa_data, ETH_ALEN);
+ *(short*)(buffer+6) = 0; /* 0==success, 1==failure */
+ *(short*)(buffer+8) = 0;
+
+ return zd1201_setconfig(zd, ZD1201_RID_AUTHENTICATESTA, buffer, 10, 1);
+}
+
+static int zd1201_set_maxassoc(struct net_device *dev,
+ struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ int err;
+
+ if (!zd->ap)
+ return -EOPNOTSUPP;
+
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, rrq->value);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int zd1201_get_maxassoc(struct net_device *dev,
+ struct iw_request_info *info, struct iw_param *rrq, char *extra)
+{
+ struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ short maxassoc;
+ int err;
+
+ if (!zd->ap)
+ return -EOPNOTSUPP;
+
+ err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, &maxassoc);
+ if (err)
+ return err;
+ rrq->value = maxassoc;
+ rrq->fixed = 1;
+
+ return 0;
+}
+
+static const iw_handler zd1201_private_handler[] = {
+ (iw_handler) zd1201_set_hostauth, /* ZD1201SIWHOSTAUTH */
+ (iw_handler) zd1201_get_hostauth, /* ZD1201GIWHOSTAUTH */
+ (iw_handler) zd1201_auth_sta, /* ZD1201SIWAUTHSTA */
+ (iw_handler) NULL, /* nothing to get */
+ (iw_handler) zd1201_set_maxassoc, /* ZD1201SIMAXASSOC */
+ (iw_handler) zd1201_get_maxassoc, /* ZD1201GIMAXASSOC */
+};
+
+static const struct iw_priv_args zd1201_private_args[] = {
+ { ZD1201SIWHOSTAUTH, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE, "sethostauth" },
+ { ZD1201GIWHOSTAUTH, IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostauth" },
+ { ZD1201SIWAUTHSTA, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE, "authstation" },
+ { ZD1201SIWMAXASSOC, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE, "setmaxassoc" },
+ { ZD1201GIWMAXASSOC, IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmaxassoc" },
+};
+
+static const struct iw_handler_def zd1201_iw_handlers = {
+ .num_standard = sizeof(zd1201_iw_handler)/sizeof(iw_handler),
+ .num_private = sizeof(zd1201_private_handler)/sizeof(iw_handler),
+ .num_private_args = sizeof(zd1201_private_args)/sizeof(struct iw_priv_args),
+ .standard = (iw_handler *)zd1201_iw_handler,
+ .private = (iw_handler *)zd1201_private_handler,
+ .private_args = (struct iw_priv_args *) zd1201_private_args,
+};
+
+int zd1201_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+ struct zd1201 *zd;
+ struct usb_device *usb;
+ int i, err;
+ short porttype;
+ char buf[IW_ESSID_MAX_SIZE+2];
+
+ usb = interface_to_usbdev(interface);
+
+ zd = kmalloc(sizeof(struct zd1201), GFP_KERNEL);
+ if (!zd) {
+ return -ENOMEM;
+ }
+ memset(zd, 0, sizeof(struct zd1201));
+ zd->ap = ap;
+ zd->usb = usb;
+ zd->removed = 0;
+ init_waitqueue_head(&zd->rxdataq);
+ INIT_HLIST_HEAD(&zd->fraglist);
+
+ err = zd1201_fw_upload(usb, zd->ap);
+ if (err) {
+ dev_err(&usb->dev, "zd1201 firmware upload failed: %d\n", err);
+ goto err_zd;
+ }
+
+ zd->endp_in = 1;
+ zd->endp_out = 1;
+ zd->endp_out2 = 2;
+ zd->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ zd->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!zd->rx_urb || !zd->tx_urb)
+ goto err_zd;
+
+ for(i = 0; i<100; i++)
+ udelay(1000);
+
+ err = zd1201_drvr_start(zd);
+ if (err)
+ goto err_zd;
+
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXDATALEN, 2312);
+ if (err)
+ goto err_start;
+
+ err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL,
+ ZD1201_RATEB1 | ZD1201_RATEB2 | ZD1201_RATEB5 | ZD1201_RATEB11);
+ if (err)
+ goto err_start;
+
+ zd->dev = alloc_etherdev(0);
+ if (!zd->dev)
+ goto err_start;
+
+ zd->dev->priv = zd;
+ zd->dev->open = zd1201_net_open;
+ zd->dev->stop = zd1201_net_stop;
+ zd->dev->get_stats = zd1201_get_stats;
+ zd->dev->get_wireless_stats = zd1201_get_wireless_stats;
+ zd->dev->wireless_handlers =
+ (struct iw_handler_def *)&zd1201_iw_handlers;
+ zd->dev->hard_start_xmit = zd1201_hard_start_xmit;
+ zd->dev->watchdog_timeo = ZD1201_TX_TIMEOUT;
+ zd->dev->tx_timeout = zd1201_tx_timeout;
+ zd->dev->set_multicast_list = zd1201_set_multicast;
+ zd->dev->set_mac_address = zd1201_set_mac_address;
+ strcpy(zd->dev->name, "wlan%d");
+
+ err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR,
+ zd->dev->dev_addr, zd->dev->addr_len);
+ if (err)
+ goto err_net;
+
+ /* Set wildcard essid to match zd->essid */
+ *(__le16 *)buf = cpu_to_le16(0);
+ err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf,
+ IW_ESSID_MAX_SIZE+2, 1);
+ if (err)
+ goto err_net;
+
+ if (zd->ap)
+ porttype = ZD1201_PORTTYPE_AP;
+ else
+ porttype = ZD1201_PORTTYPE_BSS;
+ err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype);
+ if (err)
+ goto err_net;
+
+ err = register_netdev(zd->dev);
+ if (err)
+ goto err_net;
+ dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n",
+ zd->dev->name);
+
+ usb_set_intfdata(interface, zd);
+ return 0;
+
+err_net:
+ free_netdev(zd->dev);
+err_start:
+ /* Leave the device in reset state */
+ zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);
+err_zd:
+ if (zd->tx_urb)
+ usb_free_urb(zd->tx_urb);
+ if (zd->rx_urb)
+ usb_free_urb(zd->rx_urb);
+ kfree(zd);
+ return err;
+}
+
+void zd1201_disconnect(struct usb_interface *interface)
+{
+ struct zd1201 *zd=(struct zd1201 *)usb_get_intfdata(interface);
+ struct hlist_node *node, *node2;
+ struct zd1201_frag *frag;
+
+ if (!zd)
+ return;
+ usb_set_intfdata(interface, NULL);
+ if (zd->dev) {
+ unregister_netdev(zd->dev);
+ free_netdev(zd->dev);
+ }
+
+ hlist_for_each_entry_safe(frag, node, node2, &zd->fraglist, fnode) {
+ hlist_del_init(&frag->fnode);
+ kfree_skb(frag->skb);
+ kfree(frag);
+ }
+
+ if (zd->tx_urb) {
+ usb_kill_urb(zd->tx_urb);
+ usb_free_urb(zd->tx_urb);
+ }
+ if (zd->rx_urb) {
+ usb_kill_urb(zd->rx_urb);
+ usb_free_urb(zd->rx_urb);
+ }
+ kfree(zd);
+}
+
+struct usb_driver zd1201_usb = {
+ .owner = THIS_MODULE,
+ .name = "zd1201",
+ .probe = zd1201_probe,
+ .disconnect = zd1201_disconnect,
+ .id_table = zd1201_table,
+};
+
+static int __init zd1201_init(void)
+{
+ return usb_register(&zd1201_usb);
+}
+
+static void __exit zd1201_cleanup(void)
+{
+ usb_deregister(&zd1201_usb);
+}
+
+module_init(zd1201_init);
+module_exit(zd1201_cleanup);
diff --git a/drivers/usb/net/zd1201.h b/drivers/usb/net/zd1201.h
new file mode 100644
index 000000000000..4386956a5c1c
--- /dev/null
+++ b/drivers/usb/net/zd1201.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * Parts of this driver have been derived from a wlan-ng version
+ * modified by ZyDAS.
+ * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
+ */
+
+#ifndef _INCLUDE_ZD1201_H_
+#define _INCLUDE_ZD1201_H_
+
+#define ZD1201_NUMKEYS 4
+#define ZD1201_MAXKEYLEN 13
+#define ZD1201_MAXMULTI 16
+#define ZD1201_FRAGMAX 2500
+#define ZD1201_FRAGMIN 256
+#define ZD1201_RTSMAX 2500
+
+#define ZD1201_RXSIZE 3000
+
+struct zd1201 {
+ struct usb_device *usb;
+ int removed;
+ struct net_device *dev;
+ struct net_device_stats stats;
+ struct iw_statistics iwstats;
+
+ int endp_in;
+ int endp_out;
+ int endp_out2;
+ struct urb *rx_urb;
+ struct urb *tx_urb;
+
+ unsigned char rxdata[ZD1201_RXSIZE];
+ int rxlen;
+ wait_queue_head_t rxdataq;
+ int rxdatas;
+ struct hlist_head fraglist;
+ unsigned char txdata[ZD1201_RXSIZE];
+
+ int ap;
+ char essid[IW_ESSID_MAX_SIZE+1];
+ int essidlen;
+ int mac_enabled;
+ int monitor;
+ int encode_enabled;
+ int encode_restricted;
+ unsigned char encode_keys[ZD1201_NUMKEYS][ZD1201_MAXKEYLEN];
+ int encode_keylen[ZD1201_NUMKEYS];
+};
+
+struct zd1201_frag {
+ struct hlist_node fnode;
+ int seq;
+ struct sk_buff *skb;
+};
+
+#define ZD1201SIWHOSTAUTH SIOCIWFIRSTPRIV
+#define ZD1201GIWHOSTAUTH ZD1201SIWHOSTAUTH+1
+#define ZD1201SIWAUTHSTA SIOCIWFIRSTPRIV+2
+#define ZD1201SIWMAXASSOC SIOCIWFIRSTPRIV+4
+#define ZD1201GIWMAXASSOC ZD1201SIWMAXASSOC+1
+
+#define ZD1201_FW_TIMEOUT (1000)
+
+#define ZD1201_TX_TIMEOUT (2000)
+
+#define ZD1201_USB_CMDREQ 0
+#define ZD1201_USB_RESREQ 1
+
+#define ZD1201_CMDCODE_INIT 0x00
+#define ZD1201_CMDCODE_ENABLE 0x01
+#define ZD1201_CMDCODE_DISABLE 0x02
+#define ZD1201_CMDCODE_ALLOC 0x0a
+#define ZD1201_CMDCODE_INQUIRE 0x11
+#define ZD1201_CMDCODE_SETRXRID 0x17
+#define ZD1201_CMDCODE_ACCESS 0x21
+
+#define ZD1201_PACKET_EVENTSTAT 0x0
+#define ZD1201_PACKET_RXDATA 0x1
+#define ZD1201_PACKET_INQUIRE 0x2
+#define ZD1201_PACKET_RESOURCE 0x3
+
+#define ZD1201_ACCESSBIT 0x0100
+
+#define ZD1201_RID_CNFPORTTYPE 0xfc00
+#define ZD1201_RID_CNFOWNMACADDR 0xfc01
+#define ZD1201_RID_CNFDESIREDSSID 0xfc02
+#define ZD1201_RID_CNFOWNCHANNEL 0xfc03
+#define ZD1201_RID_CNFOWNSSID 0xfc04
+#define ZD1201_RID_CNFMAXDATALEN 0xfc07
+#define ZD1201_RID_CNFPMENABLED 0xfc09
+#define ZD1201_RID_CNFPMEPS 0xfc0a
+#define ZD1201_RID_CNFMAXSLEEPDURATION 0xfc0c
+#define ZD1201_RID_CNFDEFAULTKEYID 0xfc23
+#define ZD1201_RID_CNFDEFAULTKEY0 0xfc24
+#define ZD1201_RID_CNFDEFAULTKEY1 0xfc25
+#define ZD1201_RID_CNFDEFAULTKEY2 0xfc26
+#define ZD1201_RID_CNFDEFAULTKEY3 0xfc27
+#define ZD1201_RID_CNFWEBFLAGS 0xfc28
+#define ZD1201_RID_CNFAUTHENTICATION 0xfc2a
+#define ZD1201_RID_CNFMAXASSOCSTATIONS 0xfc2b
+#define ZD1201_RID_CNFHOSTAUTH 0xfc2e
+#define ZD1201_RID_CNFGROUPADDRESS 0xfc80
+#define ZD1201_RID_CNFFRAGTHRESHOLD 0xfc82
+#define ZD1201_RID_CNFRTSTHRESHOLD 0xfc83
+#define ZD1201_RID_TXRATECNTL 0xfc84
+#define ZD1201_RID_PROMISCUOUSMODE 0xfc85
+#define ZD1201_RID_CNFBASICRATES 0xfcb3
+#define ZD1201_RID_AUTHENTICATESTA 0xfce3
+#define ZD1201_RID_CURRENTBSSID 0xfd42
+#define ZD1201_RID_COMMSQUALITY 0xfd43
+#define ZD1201_RID_CURRENTTXRATE 0xfd44
+#define ZD1201_RID_CNFMAXTXBUFFERNUMBER 0xfda0
+#define ZD1201_RID_CURRENTCHANNEL 0xfdc1
+
+#define ZD1201_INQ_SCANRESULTS 0xf101
+
+#define ZD1201_INF_LINKSTATUS 0xf200
+#define ZD1201_INF_ASSOCSTATUS 0xf201
+#define ZD1201_INF_AUTHREQ 0xf202
+
+#define ZD1201_ASSOCSTATUS_STAASSOC 0x1
+#define ZD1201_ASSOCSTATUS_REASSOC 0x2
+#define ZD1201_ASSOCSTATUS_DISASSOC 0x3
+#define ZD1201_ASSOCSTATUS_ASSOCFAIL 0x4
+#define ZD1201_ASSOCSTATUS_AUTHFAIL 0x5
+
+#define ZD1201_PORTTYPE_IBSS 0
+#define ZD1201_PORTTYPE_BSS 1
+#define ZD1201_PORTTYPE_WDS 2
+#define ZD1201_PORTTYPE_PSEUDOIBSS 3
+#define ZD1201_PORTTYPE_AP 6
+
+#define ZD1201_RATEB1 1
+#define ZD1201_RATEB2 2
+#define ZD1201_RATEB5 4 /* 5.5 really, but 5 is shorter :) */
+#define ZD1201_RATEB11 8
+
+#define ZD1201_CNFAUTHENTICATION_OPENSYSTEM 0
+#define ZD1201_CNFAUTHENTICATION_SHAREDKEY 1
+
+#endif /* _INCLUDE_ZD1201_H_ */
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index a16502e474fe..86994d117c44 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -158,7 +158,7 @@ struct belkin_sa_private {
* ***************************************************************************
*/
-#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+#define WDR_TIMEOUT 5000 /* default urb timeout */
/* assumes that struct usb_serial *serial is available */
#define BSA_USB_CMD(c,v) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), \
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 3a367f547f00..46a204cd40e1 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -4,7 +4,7 @@
* Copyright (C) 2001 REINER SCT
* Author: Matthias Bruestle
*
- * Contact: linux-usb@sii.li (see MAINTAINERS)
+ * Contact: support@reiner-sct.com (see MAINTAINERS)
*
* This program is largely derived from work by the linux-usb group
* and associated source files. Please see the usb/serial files for
@@ -20,6 +20,11 @@
*
* In case of problems, please write to the contact e-mail address
* mentioned above.
+ *
+ * Please note that later models of the cyberjack reader family are
+ * supported by a libusb-based userspace device driver.
+ *
+ * Homepage: http://www.reiner-sct.de/support/treiber_cyberjack.php#linux
*/
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 58d5019d8236..db8f472d9e3f 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -57,9 +57,10 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
-#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/serial.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
#include "usb-serial.h"
#include "cypress_m8.h"
@@ -1013,8 +1014,7 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
cypress_serial_control(port, baud_mask, data_bits, stop_bits, parity_enable,
parity_type, 0, CYPRESS_SET_CONFIG);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(50*HZ/1000); /* give some time between change and read (50ms) */
+ msleep(50); /* give some time between change and read (50ms) */
/* we perform a CYPRESS_GET_CONFIG so that the current settings are filled into the private structure
* this should confirm that all is working if it returns what we just set */
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
index 93c803b00b65..1e419c8d7392 100644
--- a/drivers/usb/serial/ezusb.c
+++ b/drivers/usb/serial/ezusb.c
@@ -38,7 +38,7 @@ int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *da
return -ENOMEM;
}
memcpy (transfer_buffer, data, length);
- result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 3*HZ);
+ result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 3000);
kfree (transfer_buffer);
return result;
}
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 8e75ea1eaeda..5b575ec7bdce 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -296,6 +296,7 @@ static struct usb_device_id id_table_8U232AM [] = {
{ USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_ALT_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
@@ -381,6 +382,7 @@ static struct usb_device_id id_table_FT232BM [] = {
{ USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_ALT_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) },
@@ -515,6 +517,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_ALT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
@@ -852,7 +855,7 @@ static struct usb_serial_device_type ftdi_HE_TIRA1_device = {
-#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+#define WDR_TIMEOUT 5000 /* default urb timeout */
/* High and low are for DTR, RTS etc etc */
#define HIGH 1
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index dbb756437d79..be5d60bf90b9 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -26,6 +26,7 @@
#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
+#define FTDI_8U232AM_ALT_ALT_PID 0xf3c0 /* FTDI's second alternate PID for above */
#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */
#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index b194420025ef..a4662d7b3378 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -261,6 +261,7 @@
#include <linux/spinlock.h>
#include <linux/serial.h>
#include <linux/ioctl.h>
+#include <linux/wait.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
#include "usb-serial.h"
@@ -971,7 +972,7 @@ static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs)
/* we have completed the command */
edge_port->commandPending = FALSE;
- wake_up_interruptible(&edge_port->wait_command);
+ wake_up(&edge_port->wait_command);
}
@@ -991,7 +992,6 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
struct usb_serial *serial;
struct edgeport_serial *edge_serial;
int response;
- int timeout;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -1073,10 +1073,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
}
/* now wait for the port to be completely opened */
- timeout = OPEN_TIMEOUT;
- while (timeout && edge_port->openPending == TRUE) {
- timeout = interruptible_sleep_on_timeout (&edge_port->wait_open, timeout);
- }
+ wait_event_timeout(edge_port->wait_open, (edge_port->openPending != TRUE), OPEN_TIMEOUT);
if (edge_port->open == FALSE) {
/* open timed out */
@@ -1128,9 +1125,10 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
************************************************************************/
static void block_until_chase_response(struct edgeport_port *edge_port)
{
+ DEFINE_WAIT(wait);
__u16 lastCredits;
int timeout = 1*HZ;
- int wait = 10;
+ int loop = 10;
while (1) {
// Save Last credits
@@ -1148,12 +1146,14 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
}
// Block the thread for a while
- interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout);
+ prepare_to_wait(&edge_port->wait_chase, &wait, TASK_UNINTERRUPTIBLE);
+ schedule_timeout(timeout);
+ finish_wait(&edge_port->wait_chase, &wait);
if (lastCredits == edge_port->txCredits) {
// No activity.. count down.
- wait--;
- if (wait == 0) {
+ loop--;
+ if (loop == 0) {
edge_port->chaseResponsePending = FALSE;
dbg("%s - Chase TIMEOUT", __FUNCTION__);
return;
@@ -1161,7 +1161,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
} else {
// Reset timout value back to 10 seconds
dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits);
- wait = 10;
+ loop = 10;
}
}
}
@@ -1179,10 +1179,11 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
************************************************************************/
static void block_until_tx_empty (struct edgeport_port *edge_port)
{
+ DEFINE_WAIT(wait);
struct TxFifo *fifo = &edge_port->txfifo;
__u32 lastCount;
int timeout = HZ/10;
- int wait = 30;
+ int loop = 30;
while (1) {
// Save Last count
@@ -1195,20 +1196,22 @@ static void block_until_tx_empty (struct edgeport_port *edge_port)
}
// Block the thread for a while
- interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout);
+ prepare_to_wait (&edge_port->wait_chase, &wait, TASK_UNINTERRUPTIBLE);
+ schedule_timeout(timeout);
+ finish_wait(&edge_port->wait_chase, &wait);
dbg("%s wait", __FUNCTION__);
if (lastCount == fifo->count) {
// No activity.. count down.
- wait--;
- if (wait == 0) {
+ loop--;
+ if (loop == 0) {
dbg("%s - TIMEOUT", __FUNCTION__);
return;
}
} else {
// Reset timout value back to seconds
- wait = 30;
+ loop = 30;
}
}
}
@@ -1836,12 +1839,12 @@ static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct
*****************************************************************************/
static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
{
+ DEFINE_WAIT(wait);
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct async_icount cnow;
struct async_icount cprev;
struct serial_icounter_struct icount;
-
dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
switch (cmd) {
@@ -1868,7 +1871,9 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
cprev = edge_port->icount;
while (1) {
- interruptible_sleep_on(&edge_port->delta_msr_wait);
+ prepare_to_wait(&edge_port->delta_msr_wait, &wait, TASK_INTERRUPTIBLE);
+ schedule();
+ finish_wait(&edge_port->delta_msr_wait, &wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
@@ -2108,7 +2113,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
// We could choose to do something else when Byte3 says Timeout on Chase from Edgeport,
// like wait longer in block_until_chase_response, but for now we don't.
edge_port->chaseResponsePending = FALSE;
- wake_up_interruptible (&edge_port->wait_chase);
+ wake_up (&edge_port->wait_chase);
return;
case IOSP_EXT_STATUS_RX_CHECK_RSP:
@@ -2131,7 +2136,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
/* we have completed the open */
edge_port->openPending = FALSE;
edge_port->open = TRUE;
- wake_up_interruptible(&edge_port->wait_open);
+ wake_up(&edge_port->wait_open);
return;
}
@@ -2500,9 +2505,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
// wait for command to finish
timeout = COMMAND_TIMEOUT;
#if 0
- while (timeout && edge_port->commandPending == TRUE) {
- timeout = interruptible_sleep_on_timeout (&edge_port->wait_command, timeout);
- }
+ wait_event (&edge_port->wait_command, (edge_port->commandPending == FALSE));
if (edge_port->commandPending == TRUE) {
/* command timed out */
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index b9846a5ae636..6c96fdaec36e 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -273,7 +273,7 @@ static int TIReadVendorRequestSync (struct usb_device *dev,
index,
data,
size,
- HZ);
+ 1000);
if (status < 0)
return status;
if (status != size) {
@@ -303,8 +303,7 @@ static int TISendVendorRequestSync (struct usb_device *dev,
index,
data,
size,
- HZ);
-
+ 1000);
if (status < 0)
return status;
if (status != size) {
@@ -985,7 +984,7 @@ static int TISendBulkTransferSync (struct usb_serial *serial, void *buffer, int
buffer,
length,
num_sent,
- HZ);
+ 1000);
return status;
}
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 4ffe6e4ac531..3bd69c4ef24b 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -662,7 +662,7 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
while (retries--) {
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
- 0x1, 0, NULL, 0, HZ / 10 + 1);
+ 0x1, 0, NULL, 0, 100);
if (result == 0) {
return 0;
}
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 20977939271c..ef6a67fc2288 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -232,7 +232,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
0, /* index */
NULL,
0,
- 100*HZ);
+ 100000);
if (result < 0)
dev_err(&port->dev, "Init of modem failed (error = %d)", result);
@@ -260,7 +260,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
0, /* index */
NULL,
0,
- 100*HZ);
+ 100000);
if (result < 0)
dev_err(&port->dev, "Enabling bulk RxRead failed (error = %d)", result);
@@ -273,7 +273,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
0,
buf_flow_init,
0x10,
- 200*HZ);
+ 200000);
if (result < 0)
dev_err(&port->dev, "initial flowcontrol failed (error = %d)", result);
@@ -287,7 +287,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
0,
NULL,
0,
- 200*HZ);
+ 200000);
if (result < 0)
dev_err(&port->dev, "setting dtr failed (error = %d)", result);
@@ -300,7 +300,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
0,
NULL,
0,
- 200*HZ);
+ 200000);
if (result < 0)
dev_err(&port->dev, "setting dtr failed (error = %d)", result);
@@ -327,7 +327,7 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
0,
NULL,
0,
- 200*HZ);
+ 200000);
if (result < 0)
dev_err(&port->dev, "dropping dtr failed (error = %d)", result);
@@ -339,7 +339,7 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
0,
NULL,
0,
- 200*HZ);
+ 200000);
if (result < 0)
dev_err(&port->dev, "dropping rts failed (error = %d)", result);
@@ -352,7 +352,7 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
0,
NULL,
0,
- 200*HZ);
+ 200000);
if (result < 0)
dev_err(&port->dev, "purge failed (error = %d)", result);
@@ -365,7 +365,7 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
0, /* index */
NULL,
0,
- 100*HZ);
+ 100000);
if (result < 0)
dev_err(&port->dev, "Disabling bulk RxRead failed (error = %d)", result);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 3003cd04300e..59f234df5f89 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -189,7 +189,7 @@ static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev,
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
IU_REQ_GET_CLASS_DESC,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, ifnum, desc, sizeof(*desc), HZ);
+ 0, ifnum, desc, sizeof(*desc), 1000);
dbg("%s - ret=%d", __FUNCTION__, ret);
if (ret < sizeof(*desc)) {
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index eaa290bbf40d..7fd0aa9eccf6 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -205,7 +205,7 @@ static void keyspan_pda_request_unthrottle( struct usb_serial *serial )
0, /* index */
NULL,
0,
- 2*HZ);
+ 2000);
if (result < 0)
dbg("%s - error %d from usb_control_msg",
__FUNCTION__, result);
@@ -330,7 +330,7 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
0, /* index */
NULL, /* &data */
0, /* size */
- 2*HZ); /* timeout */
+ 2000); /* timeout */
return(rc);
}
@@ -348,7 +348,7 @@ static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state
result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
4, /* set break */
USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
- value, 0, NULL, 0, 2*HZ);
+ value, 0, NULL, 0, 2000);
if (result < 0)
dbg("%s - error %d from usb_control_msg",
__FUNCTION__, result);
@@ -416,7 +416,7 @@ static int keyspan_pda_get_modem_info(struct usb_serial *serial,
rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
3, /* get pins */
USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
- 0, 0, &data, 1, 2*HZ);
+ 0, 0, &data, 1, 2000);
if (rc > 0)
*value = data;
return rc;
@@ -430,7 +430,7 @@ static int keyspan_pda_set_modem_info(struct usb_serial *serial,
rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
3, /* set pins */
USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT,
- value, 0, NULL, 0, 2*HZ);
+ value, 0, NULL, 0, 2000);
return rc;
}
@@ -545,7 +545,7 @@ static int keyspan_pda_write(struct usb_serial_port *port,
0, /* index */
&room,
1,
- 2*HZ);
+ 2000);
if (rc < 0) {
dbg(" roomquery failed");
goto exit;
@@ -653,7 +653,7 @@ static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
0, /* index */
&room,
1,
- 2*HZ);
+ 2000);
if (rc < 0) {
dbg("%s - roomquery failed", __FUNCTION__);
goto error;
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 2e261c73cfcd..df9c183385f0 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -178,7 +178,7 @@ struct klsi_105_private {
*/
-#define KLSI_TIMEOUT (HZ * 5 ) /* default urb timeout */
+#define KLSI_TIMEOUT 5000 /* default urb timeout */
static int klsi_105_chg_port_settings(struct usb_serial_port *port,
struct klsi_105_port_settings *settings)
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index a61fecf5cdd1..425ea7d2c6f7 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -166,7 +166,7 @@ struct mct_u232_private {
* Handle vendor specific USB requests
*/
-#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+#define WDR_TIMEOUT 5000 /* default urb timeout */
/*
* Later day 2.6.0-test kernels have new baud rates like B230400 which
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index dc18427cf4e4..98054876cca2 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -1580,7 +1580,7 @@ static int ti_command_out_sync(struct ti_device *tdev, __u8 command,
status = usb_control_msg(tdev->td_serial->dev,
usb_sndctrlpipe(tdev->td_serial->dev, 0), command,
(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT),
- value, moduleid, data, size, HZ);
+ value, moduleid, data, size, 1000);
if (status == size)
status = 0;
@@ -1600,7 +1600,7 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command,
status = usb_control_msg(tdev->td_serial->dev,
usb_rcvctrlpipe(tdev->td_serial->dev, 0), command,
(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN),
- value, moduleid, data, size, HZ);
+ value, moduleid, data, size, 1000);
if (status == size)
status = 0;
@@ -1685,7 +1685,7 @@ static int ti_download_firmware(struct ti_device *tdev,
dbg("%s - downloading firmware", __FUNCTION__);
for (pos = 0; pos < buffer_size; pos += done) {
len = min(buffer_size - pos, TI_DOWNLOAD_MAX_PACKET_SIZE);
- status = usb_bulk_msg(dev, pipe, buffer+pos, len, &done, HZ);
+ status = usb_bulk_msg(dev, pipe, buffer+pos, len, &done, 1000);
if (status)
break;
}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 6c0d51638824..39a8886c5a20 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -891,7 +891,7 @@ static int clie_3_5_startup (struct usb_serial *serial)
/* get the config number */
result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0),
USB_REQ_GET_CONFIGURATION, USB_DIR_IN,
- 0, 0, &data, 1, HZ * 3);
+ 0, 0, &data, 1, 3000);
if (result < 0) {
dev_err(dev, "%s: get config number failed: %d\n", __FUNCTION__, result);
return result;
@@ -905,7 +905,7 @@ static int clie_3_5_startup (struct usb_serial *serial)
result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0),
USB_REQ_GET_INTERFACE,
USB_DIR_IN | USB_RECIP_INTERFACE,
- 0, 0, &data, 1, HZ * 3);
+ 0, 0, &data, 1, 3000);
if (result < 0) {
dev_err(dev, "%s: get interface number failed: %d\n", __FUNCTION__, result);
return result;
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index b6384a313373..cf3bc30675a1 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -254,6 +254,7 @@ static int firm_report_tx_done(struct usb_serial_port *port);
#define COMMAND_PORT 4
#define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */
+#define COMMAND_TIMEOUT_MS 2000
#define CLOSING_DELAY (30 * HZ)
@@ -379,7 +380,7 @@ static int whiteheat_attach (struct usb_serial *serial)
* unlinking bug in disguise. Same for the call below.
*/
usb_clear_halt(serial->dev, pipe);
- ret = usb_bulk_msg (serial->dev, pipe, command, 2, &alen, COMMAND_TIMEOUT);
+ ret = usb_bulk_msg (serial->dev, pipe, command, 2, &alen, COMMAND_TIMEOUT_MS);
if (ret) {
err("%s: Couldn't send command [%d]", serial->type->name, ret);
goto no_firmware;
@@ -391,7 +392,7 @@ static int whiteheat_attach (struct usb_serial *serial)
pipe = usb_rcvbulkpipe (serial->dev, command_port->bulk_in_endpointAddress);
/* See the comment on the usb_clear_halt() above */
usb_clear_halt(serial->dev, pipe);
- ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT);
+ ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT_MS);
if (ret) {
err("%s: Couldn't get results [%d]", serial->type->name, ret);
goto no_firmware;
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index 1099581dea41..1985fc41d074 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -89,12 +89,26 @@ config USB_STORAGE_DPCM
Say Y here to support the Microtech/ZiO! CompactFlash reader.
There is a web page at <http://www.ziocorp.com/products/>.
-config USB_STORAGE_HP8200e
- bool "HP CD-Writer 82xx support (EXPERIMENTAL)"
+config USB_STORAGE_USBAT
+ bool "USBAT/USBAT02-based storage support (EXPERIMENTAL)"
depends on USB_STORAGE && EXPERIMENTAL
help
- Say Y here to include additional code to support Hewlett-Packard
- 8200e/8210e/8230e CD-Writer Plus drives.
+ Say Y here to include additional code to support storage devices
+ based on the SCM/Shuttle USBAT/USBAT02 processors.
+
+ Devices reported to work with this driver include:
+ - CompactFlash reader included with Kodak DC3800 camera
+ - Dane-Elec Zmate CompactFlash reader
+ - Delkin Efilm reader2
+ - HP 8200e/8210e/8230e CD-Writer Plus drives
+ - I-JAM JS-50U
+ - Jessops CompactFlash JESDCFRU BLACK
+ - Kingston Technology PCREAD-USB/CF
+ - Maxell UA4 CompactFlash reader
+ - Memorex UCF-100
+ - Microtech ZiO! ICS-45 CF2
+ - RCA LYRA MP3 portable
+ - Sandisk ImageMate SDDR-05b
config USB_STORAGE_SDDR09
bool "SanDisk SDDR-09 (and other SmartMedia) support (EXPERIMENTAL)"
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
index 40b535fb6e11..56652ccc2881 100644
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -10,7 +10,7 @@ EXTRA_CFLAGS := -Idrivers/scsi
obj-$(CONFIG_USB_STORAGE) += usb-storage.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG) += debug.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_HP8200e) += shuttle_usbat.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_USBAT) += shuttle_usbat.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09) += sddr09.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR55) += sddr55.o
usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM) += freecom.o
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index 9d3d77452525..a0ca60a08b2b 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -54,39 +54,6 @@
#include "transport.h"
/***********************************************************************
- * Helper routines
- ***********************************************************************/
-
-/*
- * Fix-up the return data from a READ CAPACITY command. My Feiya reader
- * returns a value that is 1 too large.
- */
-static void fix_read_capacity(struct scsi_cmnd *srb)
-{
- unsigned int index, offset;
- __be32 c;
- unsigned long capacity;
-
- /* verify that it's a READ CAPACITY command */
- if (srb->cmnd[0] != READ_CAPACITY)
- return;
-
- index = offset = 0;
- if (usb_stor_access_xfer_buf((unsigned char *) &c, 4, srb,
- &index, &offset, FROM_XFER_BUF) != 4)
- return;
-
- capacity = be32_to_cpu(c);
- US_DEBUGP("US: Fixing capacity: from %ld to %ld\n",
- capacity+1, capacity);
- c = cpu_to_be32(capacity - 1);
-
- index = offset = 0;
- usb_stor_access_xfer_buf((unsigned char *) &c, 4, srb,
- &index, &offset, TO_XFER_BUF);
-}
-
-/***********************************************************************
* Protocol routines
***********************************************************************/
@@ -174,12 +141,6 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
{
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
-
- if (srb->result == SAM_STAT_GOOD) {
- /* 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 714e8328c841..13200aed4f94 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -149,6 +149,11 @@ static int slave_configure(struct scsi_device *sdev)
sdev->skip_ms_page_3f = 1;
#endif
+ /* Some disks return the total number of blocks in response
+ * to READ CAPACITY rather than the highest block number.
+ * If this device makes that mistake, tell the sd driver. */
+ if (us->flags & US_FL_FIX_CAPACITY)
+ sdev->fix_capacity = 1;
} else {
/* Non-disk-type devices don't need to blacklist any pages
@@ -157,6 +162,11 @@ static int slave_configure(struct scsi_device *sdev)
sdev->use_10_for_ms = 1;
}
+ /* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
+ * REMOVAL command, so suppress those commands. */
+ if (us->flags & US_FL_NOT_LOCKABLE)
+ sdev->lockable = 0;
+
/* this is to satisfy the compiler, tho I don't think the
* return code is ever checked anywhere. */
return 0;
@@ -346,9 +356,22 @@ static int proc_info (struct Scsi_Host *hostptr, char *buffer, char **start, off
SPRINTF(" Host scsi%d: usb-storage\n", hostptr->host_no);
/* print product, vendor, and serial number strings */
- SPRINTF(" Vendor: %s\n", us->vendor);
- SPRINTF(" Product: %s\n", us->product);
- SPRINTF("Serial Number: %s\n", us->serial);
+ if (us->pusb_dev->manufacturer)
+ SPRINTF(" Vendor: %s\n", us->pusb_dev->manufacturer);
+ else if (us->unusual_dev->vendorName)
+ SPRINTF(" Vendor: %s\n", us->unusual_dev->vendorName);
+ else
+ SPRINTF(" Vendor: Unknown\n");
+ if (us->pusb_dev->product)
+ SPRINTF(" Product: %s\n", us->pusb_dev->product);
+ else if (us->unusual_dev->productName)
+ SPRINTF(" Product: %s\n", us->unusual_dev->productName);
+ else
+ SPRINTF(" Product: Unknown\n");
+ if (us->pusb_dev->serial)
+ SPRINTF("Serial Number: %s\n", us->pusb_dev->serial);
+ else
+ SPRINTF("Serial Number: None\n");
/* show the protocol and transport */
SPRINTF(" Protocol: %s\n", us->protocol_name);
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index c98fa393814f..f6839e17e790 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -4,10 +4,14 @@
*
* Current development and maintenance by:
* (c) 2000, 2001 Robert Baruch (autophile@starband.net)
+ * (c) 2004, 2005 Daniel Drake <dsd@gentoo.org>
*
* Developed with the assistance of:
* (c) 2002 Alan Stern <stern@rowland.org>
*
+ * Flash support based on earlier work by:
+ * (c) 2002 Thomas Kreiling <usbdev@sm04.de>
+ *
* Many originally ATAPI devices were slightly modified to meet the USB
* market by using some kind of translation from ATAPI to USB on the host,
* and the peripheral would translate from USB back to ATAPI.
@@ -21,8 +25,8 @@
* as well. This driver is only guaranteed to work with the ATAPI
* translation.
*
- * The only peripheral that I know of (as of 27 Mar 2001) that uses this
- * device is the Hewlett-Packard 8200e/8210e/8230e CD-Writer Plus.
+ * See the Kconfig help text for a list of devices known to be supported by
+ * this driver.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -59,44 +63,149 @@
int transferred = 0;
+/*
+ * Convenience function to produce an ATAPI read/write sectors command
+ * Use cmd=0x20 for read, cmd=0x30 for write
+ */
+static void usbat_pack_atapi_sector_cmd(unsigned char *buf,
+ unsigned char thistime,
+ u32 sector, unsigned char cmd)
+{
+ buf[0] = 0;
+ buf[1] = thistime;
+ buf[2] = sector & 0xFF;
+ buf[3] = (sector >> 8) & 0xFF;
+ buf[4] = (sector >> 16) & 0xFF;
+ buf[5] = 0xE0 | ((sector >> 24) & 0x0F);
+ buf[6] = cmd;
+}
+
+/*
+ * Convenience function to get the device type (flash or hp8200)
+ */
+static int usbat_get_device_type(struct us_data *us)
+{
+ return ((struct usbat_info*)us->extra)->devicetype;
+}
+
+/*
+ * Read a register from the device
+ */
static int usbat_read(struct us_data *us,
unsigned char access,
unsigned char reg,
unsigned char *content)
{
- int result;
-
- result = usb_stor_ctrl_transfer(us,
+ return usb_stor_ctrl_transfer(us,
us->recv_ctrl_pipe,
- access,
+ access | USBAT_CMD_READ_REG,
0xC0,
(u16)reg,
0,
content,
1);
-
- return result;
}
+/*
+ * Write to a register on the device
+ */
static int usbat_write(struct us_data *us,
unsigned char access,
unsigned char reg,
unsigned char content)
{
- int result;
-
- result = usb_stor_ctrl_transfer(us,
+ return usb_stor_ctrl_transfer(us,
us->send_ctrl_pipe,
- access|0x01,
+ access | USBAT_CMD_WRITE_REG,
0x40,
short_pack(reg, content),
0,
NULL,
0);
+}
- return result;
+/*
+ * Convenience function to perform a bulk read
+ */
+static int usbat_bulk_read(struct us_data *us,
+ unsigned char *data,
+ unsigned int len)
+{
+ if (len == 0)
+ return USB_STOR_XFER_GOOD;
+
+ US_DEBUGP("usbat_bulk_read: len = %d\n", len);
+ return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, data, len, NULL);
+}
+
+/*
+ * Convenience function to perform a bulk write
+ */
+static int usbat_bulk_write(struct us_data *us,
+ unsigned char *data,
+ unsigned int len)
+{
+ if (len == 0)
+ return USB_STOR_XFER_GOOD;
+
+ US_DEBUGP("usbat_bulk_write: len = %d\n", len);
+ return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, data, len, NULL);
+}
+
+/*
+ * Some USBAT-specific commands can only be executed over a command transport
+ * This transport allows one (len=8) or two (len=16) vendor-specific commands
+ * to be executed.
+ */
+static int usbat_execute_command(struct us_data *us,
+ unsigned char *commands,
+ unsigned int len)
+{
+ return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+ USBAT_CMD_EXEC_CMD, 0x40, 0, 0,
+ commands, len);
+}
+
+/*
+ * Read the status register
+ */
+static int usbat_get_status(struct us_data *us, unsigned char *status)
+{
+ int rc;
+ rc = usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status);
+
+ US_DEBUGP("usbat_get_status: 0x%02X\n", (unsigned short) (*status));
+ return rc;
+}
+
+/*
+ * Check the device status
+ */
+static int usbat_check_status(struct us_data *us)
+{
+ unsigned char *reply = us->iobuf;
+ int rc;
+
+ if (!us)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ rc = usbat_get_status(us, reply);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_FAILED;
+
+ if (*reply & 0x01 && *reply != 0x51) // error/check condition (0x51 is ok)
+ return USB_STOR_TRANSPORT_FAILED;
+
+ if (*reply & 0x20) // device fault
+ return USB_STOR_TRANSPORT_FAILED;
+
+ return USB_STOR_TRANSPORT_GOOD;
}
+/*
+ * Stores critical information in internal registers in prepartion for the execution
+ * of a conditional usbat_read_blocks or usbat_write_blocks call.
+ */
static int usbat_set_shuttle_features(struct us_data *us,
unsigned char external_trigger,
unsigned char epp_control,
@@ -105,76 +214,44 @@ static int usbat_set_shuttle_features(struct us_data *us,
unsigned char subcountH,
unsigned char subcountL)
{
- int result;
unsigned char *command = us->iobuf;
command[0] = 0x40;
- command[1] = 0x81;
+ command[1] = USBAT_CMD_SET_FEAT;
+
+ // The only bit relevant to ATA access is bit 6
+ // which defines 8 bit data access (set) or 16 bit (unset)
command[2] = epp_control;
+
+ // If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1,
+ // ET1 and ET2 define an external event to be checked for on event of a
+ // _read_blocks or _write_blocks operation. The read/write will not take
+ // place unless the defined trigger signal is active.
command[3] = external_trigger;
+
+ // The resultant byte of the mask operation (see mask_byte) is compared for
+ // equivalence with this test pattern. If equal, the read/write will take
+ // place.
command[4] = test_pattern;
+
+ // This value is logically ANDed with the status register field specified
+ // in the read/write command.
command[5] = mask_byte;
+
+ // If ALQ is set in the qualifier, this field contains the address of the
+ // registers where the byte count should be read for transferring the data.
+ // If ALQ is not set, then this field contains the number of bytes to be
+ // transferred.
command[6] = subcountL;
command[7] = subcountH;
- result = usb_stor_ctrl_transfer(us,
- us->send_ctrl_pipe,
- 0x80,
- 0x40,
- 0,
- 0,
- command,
- 8);
-
- return result;
-}
-
-static int usbat_read_block(struct us_data *us,
- unsigned char access,
- unsigned char reg,
- unsigned char *content,
- unsigned short len,
- int use_sg)
-{
- int result;
- unsigned char *command = us->iobuf;
-
- if (!len)
- return USB_STOR_TRANSPORT_GOOD;
-
- command[0] = 0xC0;
- command[1] = access | 0x02;
- command[2] = reg;
- command[3] = 0;
- command[4] = 0;
- command[5] = 0;
- command[6] = LSB_of(len);
- command[7] = MSB_of(len);
-
- result = usb_stor_ctrl_transfer(us,
- us->send_ctrl_pipe,
- 0x80,
- 0x40,
- 0,
- 0,
- command,
- 8);
-
- if (result != USB_STOR_XFER_GOOD)
- return USB_STOR_TRANSPORT_ERROR;
-
- result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe,
- content, len, use_sg, NULL);
-
- return (result == USB_STOR_XFER_GOOD ?
- USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+ return usbat_execute_command(us, command, 8);
}
/*
* Block, waiting for an ATA device to become not busy or to report
* an error condition.
*/
-
static int usbat_wait_not_busy(struct us_data *us, int minutes)
{
int i;
@@ -189,7 +266,7 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes)
for (i=0; i<1200+minutes*60; i++) {
- result = usbat_read(us, USBAT_ATA, 0x17, status);
+ result = usbat_get_status(us, status);
if (result!=USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -220,12 +297,45 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes)
return USB_STOR_TRANSPORT_FAILED;
}
+/*
+ * Read block data from the data register
+ */
+static int usbat_read_block(struct us_data *us,
+ unsigned char *content,
+ unsigned short len)
+{
+ int result;
+ unsigned char *command = us->iobuf;
+
+ if (!len)
+ return USB_STOR_TRANSPORT_GOOD;
+
+ command[0] = 0xC0;
+ command[1] = USBAT_ATA | USBAT_CMD_READ_BLOCK;
+ command[2] = USBAT_ATA_DATA;
+ command[3] = 0;
+ command[4] = 0;
+ command[5] = 0;
+ command[6] = LSB_of(len);
+ command[7] = MSB_of(len);
+
+ result = usbat_execute_command(us, command, 8);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ result = usbat_bulk_read(us, content, len);
+ return (result == USB_STOR_XFER_GOOD ?
+ USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+}
+
+/*
+ * Write block data via the data register
+ */
static int usbat_write_block(struct us_data *us,
- unsigned char access,
- unsigned char reg,
+ unsigned char access,
unsigned char *content,
unsigned short len,
- int use_sg, int minutes)
+ int minutes)
{
int result;
unsigned char *command = us->iobuf;
@@ -234,57 +344,48 @@ static int usbat_write_block(struct us_data *us,
return USB_STOR_TRANSPORT_GOOD;
command[0] = 0x40;
- command[1] = access | 0x03;
- command[2] = reg;
+ command[1] = access | USBAT_CMD_WRITE_BLOCK;
+ command[2] = USBAT_ATA_DATA;
command[3] = 0;
command[4] = 0;
command[5] = 0;
command[6] = LSB_of(len);
command[7] = MSB_of(len);
- result = usb_stor_ctrl_transfer(us,
- us->send_ctrl_pipe,
- 0x80,
- 0x40,
- 0,
- 0,
- command,
- 8);
+ result = usbat_execute_command(us, command, 8);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe,
- content, len, use_sg, NULL);
-
+ result = usbat_bulk_write(us, content, len);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
return usbat_wait_not_busy(us, minutes);
}
-static int usbat_rw_block_test(struct us_data *us,
- unsigned char access,
- unsigned char *registers,
- unsigned char *data_out,
- unsigned short num_registers,
- unsigned char data_reg,
- unsigned char status_reg,
- unsigned char timeout,
- unsigned char qualifier,
- int direction,
- unsigned char *content,
- unsigned short len,
- int use_sg,
- int minutes)
+/*
+ * Process read and write requests
+ */
+static int usbat_hp8200e_rw_block_test(struct us_data *us,
+ unsigned char access,
+ unsigned char *registers,
+ unsigned char *data_out,
+ unsigned short num_registers,
+ unsigned char data_reg,
+ unsigned char status_reg,
+ unsigned char timeout,
+ unsigned char qualifier,
+ int direction,
+ unsigned char *content,
+ unsigned short len,
+ int use_sg,
+ int minutes)
{
int result;
unsigned int pipe = (direction == DMA_FROM_DEVICE) ?
us->recv_bulk_pipe : us->send_bulk_pipe;
- // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here,
- // but that's what came out of the trace every single time.
-
unsigned char *command = us->iobuf;
int i, j;
int cmdlen;
@@ -308,8 +409,11 @@ static int usbat_rw_block_test(struct us_data *us,
if (i==0) {
cmdlen = 16;
+ // Write to multiple registers
+ // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here,
+ // but that's what came out of the trace every single time.
command[0] = 0x40;
- command[1] = access | 0x07;
+ command[1] = access | USBAT_CMD_WRITE_REGS;
command[2] = 0x07;
command[3] = 0x17;
command[4] = 0xFC;
@@ -319,9 +423,11 @@ static int usbat_rw_block_test(struct us_data *us,
} else
cmdlen = 8;
+ // Conditionally read or write blocks
command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0);
command[cmdlen-7] = access |
- (direction==DMA_TO_DEVICE ? 0x05 : 0x04);
+ (direction==DMA_TO_DEVICE ?
+ USBAT_CMD_COND_WRITE_BLOCK : USBAT_CMD_COND_READ_BLOCK);
command[cmdlen-6] = data_reg;
command[cmdlen-5] = status_reg;
command[cmdlen-4] = timeout;
@@ -329,14 +435,7 @@ static int usbat_rw_block_test(struct us_data *us,
command[cmdlen-2] = LSB_of(len);
command[cmdlen-1] = MSB_of(len);
- result = usb_stor_ctrl_transfer(us,
- us->send_ctrl_pipe,
- 0x80,
- 0x40,
- 0,
- 0,
- command,
- cmdlen);
+ result = usbat_execute_command(us, command, cmdlen);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -348,10 +447,7 @@ static int usbat_rw_block_test(struct us_data *us,
data[1+(j<<1)] = data_out[j];
}
- result = usb_stor_bulk_transfer_buf(us,
- us->send_bulk_pipe,
- data, num_registers*2, NULL);
-
+ result = usbat_bulk_write(us, data, num_registers*2);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -403,7 +499,8 @@ static int usbat_rw_block_test(struct us_data *us,
*/
result = usbat_read(us, USBAT_ATA,
- direction==DMA_TO_DEVICE ? 0x17 : 0x0E,
+ direction==DMA_TO_DEVICE ?
+ USBAT_ATA_STATUS : USBAT_ATA_ALTSTATUS,
status);
if (result!=USB_STOR_XFER_GOOD)
@@ -430,101 +527,602 @@ static int usbat_rw_block_test(struct us_data *us,
}
/*
- * Write data to multiple registers at once. Not meant for large
- * transfers of data!
+ * Write to multiple registers:
+ * Allows us to write specific data to any registers. The data to be written
+ * gets packed in this sequence: reg0, data0, reg1, data1, ..., regN, dataN
+ * which gets sent through bulk out.
+ * Not designed for large transfers of data!
*/
-
static int usbat_multiple_write(struct us_data *us,
- unsigned char access,
unsigned char *registers,
unsigned char *data_out,
unsigned short num_registers)
{
- int result;
+ int i, result;
unsigned char *data = us->iobuf;
- int i;
unsigned char *command = us->iobuf;
BUG_ON(num_registers > US_IOBUF_SIZE/2);
+ // Write to multiple registers, ATA access
command[0] = 0x40;
- command[1] = access | 0x07;
+ command[1] = USBAT_ATA | USBAT_CMD_WRITE_REGS;
+
+ // No relevance
command[2] = 0;
command[3] = 0;
command[4] = 0;
command[5] = 0;
+
+ // Number of bytes to be transferred (incl. addresses and data)
command[6] = LSB_of(num_registers*2);
command[7] = MSB_of(num_registers*2);
- result = usb_stor_ctrl_transfer(us,
- us->send_ctrl_pipe,
- 0x80,
- 0x40,
- 0,
- 0,
- command,
- 8);
-
+ // The setup command
+ result = usbat_execute_command(us, command, 8);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
+ // Create the reg/data, reg/data sequence
for (i=0; i<num_registers; i++) {
data[i<<1] = registers[i];
data[1+(i<<1)] = data_out[i];
}
- result = usb_stor_bulk_transfer_buf(us,
- us->send_bulk_pipe, data, num_registers*2, NULL);
-
+ // Send the data
+ result = usbat_bulk_write(us, data, num_registers*2);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- return usbat_wait_not_busy(us, 0);
+ if (usbat_get_device_type(us) == USBAT_DEV_HP8200)
+ return usbat_wait_not_busy(us, 0);
+ else
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Conditionally read blocks from device:
+ * Allows us to read blocks from a specific data register, based upon the
+ * condition that a status register can be successfully masked with a status
+ * qualifier. If this condition is not initially met, the read will wait
+ * up until a maximum amount of time has elapsed, as specified by timeout.
+ * The read will start when the condition is met, otherwise the command aborts.
+ *
+ * The qualifier defined here is not the value that is masked, it defines
+ * conditions for the write to take place. The actual masked qualifier (and
+ * other related details) are defined beforehand with _set_shuttle_features().
+ */
+static int usbat_read_blocks(struct us_data *us,
+ unsigned char *buffer,
+ int len)
+{
+ int result;
+ unsigned char *command = us->iobuf;
+
+ command[0] = 0xC0;
+ command[1] = USBAT_ATA | USBAT_CMD_COND_READ_BLOCK;
+ command[2] = USBAT_ATA_DATA;
+ command[3] = USBAT_ATA_STATUS;
+ command[4] = 0xFD; // Timeout (ms);
+ command[5] = USBAT_QUAL_FCQ;
+ command[6] = LSB_of(len);
+ command[7] = MSB_of(len);
+
+ // Multiple block read setup command
+ result = usbat_execute_command(us, command, 8);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_FAILED;
+
+ // Read the blocks we just asked for
+ result = usbat_bulk_read(us, buffer, len);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_FAILED;
+
+ return USB_STOR_TRANSPORT_GOOD;
}
+/*
+ * Conditionally write blocks to device:
+ * Allows us to write blocks to a specific data register, based upon the
+ * condition that a status register can be successfully masked with a status
+ * qualifier. If this condition is not initially met, the write will wait
+ * up until a maximum amount of time has elapsed, as specified by timeout.
+ * The read will start when the condition is met, otherwise the command aborts.
+ *
+ * The qualifier defined here is not the value that is masked, it defines
+ * conditions for the write to take place. The actual masked qualifier (and
+ * other related details) are defined beforehand with _set_shuttle_features().
+ */
+static int usbat_write_blocks(struct us_data *us,
+ unsigned char *buffer,
+ int len)
+{
+ int result;
+ unsigned char *command = us->iobuf;
+
+ command[0] = 0x40;
+ command[1] = USBAT_ATA | USBAT_CMD_COND_WRITE_BLOCK;
+ command[2] = USBAT_ATA_DATA;
+ command[3] = USBAT_ATA_STATUS;
+ command[4] = 0xFD; // Timeout (ms)
+ command[5] = USBAT_QUAL_FCQ;
+ command[6] = LSB_of(len);
+ command[7] = MSB_of(len);
+
+ // Multiple block write setup command
+ result = usbat_execute_command(us, command, 8);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_FAILED;
+
+ // Write the data
+ result = usbat_bulk_write(us, buffer, len);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_FAILED;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Read the User IO register
+ */
static int usbat_read_user_io(struct us_data *us, unsigned char *data_flags)
{
int result;
result = usb_stor_ctrl_transfer(us,
us->recv_ctrl_pipe,
- 0x82,
+ USBAT_CMD_UIO,
0xC0,
0,
0,
data_flags,
- 1);
+ USBAT_UIO_READ);
+
+ US_DEBUGP("usbat_read_user_io: UIO register reads %02X\n", (unsigned short) (*data_flags));
return result;
}
+/*
+ * Write to the User IO register
+ */
static int usbat_write_user_io(struct us_data *us,
unsigned char enable_flags,
unsigned char data_flags)
{
- int result;
-
- result = usb_stor_ctrl_transfer(us,
+ return usb_stor_ctrl_transfer(us,
us->send_ctrl_pipe,
- 0x82,
+ USBAT_CMD_UIO,
0x40,
short_pack(enable_flags, data_flags),
0,
NULL,
- 0);
+ USBAT_UIO_WRITE);
+}
+
+/*
+ * Reset the device
+ * Often needed on media change.
+ */
+static int usbat_device_reset(struct us_data *us)
+{
+ int rc;
+
+ // Reset peripheral, enable peripheral control signals
+ // (bring reset signal up)
+ rc = usbat_write_user_io(us,
+ USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0,
+ USBAT_UIO_EPAD | USBAT_UIO_1);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ // Enable peripheral control signals
+ // (bring reset signal down)
+ rc = usbat_write_user_io(us,
+ USBAT_UIO_OE1 | USBAT_UIO_OE0,
+ USBAT_UIO_EPAD | USBAT_UIO_1);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Enable card detect
+ */
+static int usbat_device_enable_cdt(struct us_data *us)
+{
+ int rc;
+
+ // Enable peripheral control signals and card detect
+ rc = usbat_write_user_io(us,
+ USBAT_UIO_ACKD | USBAT_UIO_OE1 | USBAT_UIO_OE0,
+ USBAT_UIO_EPAD | USBAT_UIO_1);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+/*
+ * Determine if media is present.
+ */
+static int usbat_flash_check_media_present(unsigned char *uio)
+{
+ if (*uio & USBAT_UIO_UI0) {
+ US_DEBUGP("usbat_flash_check_media_present: no media detected\n");
+ return USBAT_FLASH_MEDIA_NONE;
+ }
+
+ return USBAT_FLASH_MEDIA_CF;
+}
+
+/*
+ * Determine if media has changed since last operation
+ */
+static int usbat_flash_check_media_changed(unsigned char *uio)
+{
+ if (*uio & USBAT_UIO_0) {
+ US_DEBUGP("usbat_flash_check_media_changed: media change detected\n");
+ return USBAT_FLASH_MEDIA_CHANGED;
+ }
+
+ return USBAT_FLASH_MEDIA_SAME;
+}
+
+/*
+ * Check for media change / no media and handle the situation appropriately
+ */
+static int usbat_flash_check_media(struct us_data *us,
+ struct usbat_info *info)
+{
+ int rc;
+ unsigned char *uio = us->iobuf;
+
+ rc = usbat_read_user_io(us, uio);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ // Check for media existance
+ rc = usbat_flash_check_media_present(uio);
+ if (rc == USBAT_FLASH_MEDIA_NONE) {
+ info->sense_key = 0x02;
+ info->sense_asc = 0x3A;
+ info->sense_ascq = 0x00;
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ // Check for media change
+ rc = usbat_flash_check_media_changed(uio);
+ if (rc == USBAT_FLASH_MEDIA_CHANGED) {
+
+ // Reset and re-enable card detect
+ rc = usbat_device_reset(us);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
+ rc = usbat_device_enable_cdt(us);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
+
+ msleep(50);
+
+ rc = usbat_read_user_io(us, uio);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ info->sense_key = UNIT_ATTENTION;
+ info->sense_asc = 0x28;
+ info->sense_ascq = 0x00;
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Determine whether we are controlling a flash-based reader/writer,
+ * or a HP8200-based CD drive.
+ * Sets transport functions as appropriate.
+ */
+static int usbat_identify_device(struct us_data *us,
+ struct usbat_info *info)
+{
+ int rc;
+ unsigned char status;
+
+ if (!us || !info)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ rc = usbat_device_reset(us);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
+
+ /*
+ * By examining the device signature after a reset, we can identify
+ * whether the device supports the ATAPI packet interface.
+ * The flash-devices do not support this, whereas the HP CDRW's obviously
+ * do.
+ *
+ * This method is not ideal, but works because no other devices have been
+ * produced based on the USBAT/USBAT02.
+ *
+ * Section 9.1 of the ATAPI-4 spec states (amongst other things) that
+ * after a device reset, a Cylinder low of 0x14 indicates that the device
+ * does support packet commands.
+ */
+ rc = usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, &status);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ US_DEBUGP("usbat_identify_device: Cylinder low is %02X\n", status);
+
+ if (status == 0x14) {
+ // Device is HP 8200
+ US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n");
+ info->devicetype = USBAT_DEV_HP8200;
+ } else {
+ // Device is a CompactFlash reader/writer
+ US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n");
+ info->devicetype = USBAT_DEV_FLASH;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Set the transport function based on the device type
+ */
+int usbat_set_transport(struct us_data *us,
+ struct usbat_info *info)
+{
+ int rc;
+
+ if (!info->devicetype) {
+ rc = usbat_identify_device(us, info);
+ if (rc != USB_STOR_TRANSPORT_GOOD) {
+ US_DEBUGP("usbat_set_transport: Could not identify device\n");
+ return 1;
+ }
+ }
+
+ if (usbat_get_device_type(us) == USBAT_DEV_HP8200)
+ us->transport = usbat_hp8200e_transport;
+ else if (usbat_get_device_type(us) == USBAT_DEV_FLASH)
+ us->transport = usbat_flash_transport;
+
+ return 0;
+}
+
+/*
+ * Read the media capacity
+ */
+static int usbat_flash_get_sector_count(struct us_data *us,
+ struct usbat_info *info)
+{
+ unsigned char registers[3] = {
+ USBAT_ATA_SECCNT,
+ USBAT_ATA_DEVICE,
+ USBAT_ATA_CMD,
+ };
+ unsigned char command[3] = { 0x01, 0xA0, 0xEC };
+ unsigned char *reply;
+ unsigned char status;
+ int rc;
+
+ if (!us || !info)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ reply = kmalloc(512, GFP_NOIO);
+ if (!reply)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ // ATAPI command : IDENTIFY DEVICE
+ rc = usbat_multiple_write(us, registers, command, 3);
+ if (rc != USB_STOR_XFER_GOOD) {
+ US_DEBUGP("usbat_flash_get_sector_count: Gah! identify_device failed\n");
+ rc = USB_STOR_TRANSPORT_ERROR;
+ goto leave;
+ }
+
+ // Read device status
+ if (usbat_get_status(us, &status) != USB_STOR_XFER_GOOD) {
+ rc = USB_STOR_TRANSPORT_ERROR;
+ goto leave;
+ }
+
+ msleep(100);
+
+ // Read the device identification data
+ rc = usbat_read_block(us, reply, 512);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ goto leave;
+
+ info->sectors = ((u32)(reply[117]) << 24) |
+ ((u32)(reply[116]) << 16) |
+ ((u32)(reply[115]) << 8) |
+ ((u32)(reply[114]) );
+
+ rc = USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+ kfree(reply);
+ return rc;
+}
+
+/*
+ * Read data from device
+ */
+static int usbat_flash_read_data(struct us_data *us,
+ struct usbat_info *info,
+ u32 sector,
+ u32 sectors)
+{
+ unsigned char registers[7] = {
+ USBAT_ATA_FEATURES,
+ USBAT_ATA_SECCNT,
+ USBAT_ATA_SECNUM,
+ USBAT_ATA_LBA_ME,
+ USBAT_ATA_LBA_HI,
+ USBAT_ATA_DEVICE,
+ USBAT_ATA_STATUS,
+ };
+ unsigned char command[7];
+ unsigned char *buffer;
+ unsigned char thistime;
+ unsigned int totallen, alloclen;
+ int len, result;
+ unsigned int sg_idx = 0, sg_offset = 0;
+
+ result = usbat_flash_check_media(us, info);
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ // we're working in LBA mode. according to the ATA spec,
+ // we can support up to 28-bit addressing. I don't know if Jumpshot
+ // supports beyond 24-bit addressing. It's kind of hard to test
+ // since it requires > 8GB CF card.
+
+ if (sector > 0x0FFFFFFF)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ totallen = sectors * info->ssize;
+
+ // Since we don't read more than 64 KB at a time, we have to create
+ // a bounce buffer and move the data a piece at a time between the
+ // bounce buffer and the actual transfer buffer.
+
+ alloclen = min(totallen, 65536u);
+ buffer = kmalloc(alloclen, GFP_NOIO);
+ if (buffer == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ do {
+ // loop, never allocate or transfer more than 64k at once
+ // (min(128k, 255*info->ssize) is the real limit)
+ len = min(totallen, alloclen);
+ thistime = (len / info->ssize) & 0xff;
+
+ // ATAPI command 0x20 (READ SECTORS)
+ usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x20);
+
+ // Write/execute ATAPI read command
+ result = usbat_multiple_write(us, registers, command, 7);
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ goto leave;
+
+ // Read the data we just requested
+ result = usbat_read_blocks(us, buffer, len);
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ goto leave;
+
+ US_DEBUGP("usbat_flash_read_data: %d bytes\n", len);
+
+ // Store the data in the transfer buffer
+ usb_stor_access_xfer_buf(buffer, len, us->srb,
+ &sg_idx, &sg_offset, TO_XFER_BUF);
+
+ sector += thistime;
+ totallen -= len;
+ } while (totallen > 0);
+
+ kfree(buffer);
+ return USB_STOR_TRANSPORT_GOOD;
+
+leave:
+ kfree(buffer);
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+/*
+ * Write data to device
+ */
+static int usbat_flash_write_data(struct us_data *us,
+ struct usbat_info *info,
+ u32 sector,
+ u32 sectors)
+{
+ unsigned char registers[7] = {
+ USBAT_ATA_FEATURES,
+ USBAT_ATA_SECCNT,
+ USBAT_ATA_SECNUM,
+ USBAT_ATA_LBA_ME,
+ USBAT_ATA_LBA_HI,
+ USBAT_ATA_DEVICE,
+ USBAT_ATA_STATUS,
+ };
+ unsigned char command[7];
+ unsigned char *buffer;
+ unsigned char thistime;
+ unsigned int totallen, alloclen;
+ int len, result;
+ unsigned int sg_idx = 0, sg_offset = 0;
+
+ result = usbat_flash_check_media(us, info);
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ // we're working in LBA mode. according to the ATA spec,
+ // we can support up to 28-bit addressing. I don't know if Jumpshot
+ // supports beyond 24-bit addressing. It's kind of hard to test
+ // since it requires > 8GB CF card.
+
+ if (sector > 0x0FFFFFFF)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ totallen = sectors * info->ssize;
+
+ // Since we don't write more than 64 KB at a time, we have to create
+ // a bounce buffer and move the data a piece at a time between the
+ // bounce buffer and the actual transfer buffer.
+
+ alloclen = min(totallen, 65536u);
+ buffer = kmalloc(alloclen, GFP_NOIO);
+ if (buffer == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ do {
+ // loop, never allocate or transfer more than 64k at once
+ // (min(128k, 255*info->ssize) is the real limit)
+ len = min(totallen, alloclen);
+ thistime = (len / info->ssize) & 0xff;
+
+ // Get the data from the transfer buffer
+ usb_stor_access_xfer_buf(buffer, len, us->srb,
+ &sg_idx, &sg_offset, FROM_XFER_BUF);
+
+ // ATAPI command 0x30 (WRITE SECTORS)
+ usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x30);
+
+ // Write/execute ATAPI write command
+ result = usbat_multiple_write(us, registers, command, 7);
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ goto leave;
+
+ // Write the data
+ result = usbat_write_blocks(us, buffer, len);
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ goto leave;
+
+ sector += thistime;
+ totallen -= len;
+ } while (totallen > 0);
+
+ kfree(buffer);
return result;
+
+leave:
+ kfree(buffer);
+ return USB_STOR_TRANSPORT_ERROR;
}
/*
* Squeeze a potentially huge (> 65535 byte) read10 command into
* a little ( <= 65535 byte) ATAPI pipe
*/
-
-static int usbat_handle_read10(struct us_data *us,
- unsigned char *registers,
- unsigned char *data,
- struct scsi_cmnd *srb)
+static int usbat_hp8200e_handle_read10(struct us_data *us,
+ unsigned char *registers,
+ unsigned char *data,
+ struct scsi_cmnd *srb)
{
int result = USB_STOR_TRANSPORT_GOOD;
unsigned char *buffer;
@@ -538,9 +1136,10 @@ static int usbat_handle_read10(struct us_data *us,
if (srb->request_bufflen < 0x10000) {
- result = usbat_rw_block_test(us, USBAT_ATA,
+ result = usbat_hp8200e_rw_block_test(us, USBAT_ATA,
registers, data, 19,
- 0x10, 0x17, 0xFD, 0x30,
+ USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
+ (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
DMA_FROM_DEVICE,
srb->request_buffer,
srb->request_bufflen, srb->use_sg, 1);
@@ -607,9 +1206,10 @@ static int usbat_handle_read10(struct us_data *us,
data[7+7] = MSB_of(len / srb->transfersize); // SCSI command
data[7+8] = LSB_of(len / srb->transfersize); // num sectors
- result = usbat_rw_block_test(us, USBAT_ATA,
+ result = usbat_hp8200e_rw_block_test(us, USBAT_ATA,
registers, data, 19,
- 0x10, 0x17, 0xFD, 0x30,
+ USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
+ (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
DMA_FROM_DEVICE,
buffer,
len, 0, 1);
@@ -632,48 +1232,52 @@ static int usbat_handle_read10(struct us_data *us,
return result;
}
-static int hp_8200e_select_and_test_registers(struct us_data *us)
+static int usbat_select_and_test_registers(struct us_data *us)
{
int selector;
unsigned char *status = us->iobuf;
+ unsigned char max_selector = 0xB0;
+ if (usbat_get_device_type(us) == USBAT_DEV_FLASH)
+ max_selector = 0xA0;
// try device = master, then device = slave.
- for (selector = 0xA0; selector <= 0xB0; selector += 0x10) {
+ for (selector = 0xA0; selector <= max_selector; selector += 0x10) {
- if (usbat_write(us, USBAT_ATA, 0x16, selector) !=
+ if (usbat_get_device_type(us) == USBAT_DEV_HP8200 &&
+ usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) !=
USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- if (usbat_read(us, USBAT_ATA, 0x17, status) !=
+ if (usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status) !=
USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- if (usbat_read(us, USBAT_ATA, 0x16, status) !=
+ if (usbat_read(us, USBAT_ATA, USBAT_ATA_DEVICE, status) !=
USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- if (usbat_read(us, USBAT_ATA, 0x14, status) !=
+ if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) !=
USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- if (usbat_read(us, USBAT_ATA, 0x15, status) !=
+ if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) !=
USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- if (usbat_write(us, USBAT_ATA, 0x14, 0x55) !=
+ if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_ME, 0x55) !=
USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- if (usbat_write(us, USBAT_ATA, 0x15, 0xAA) !=
+ if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_HI, 0xAA) !=
USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- if (usbat_read(us, USBAT_ATA, 0x14, status) !=
+ if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) !=
USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- if (usbat_read(us, USBAT_ATA, 0x15, status) !=
+ if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) !=
USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
}
@@ -681,125 +1285,131 @@ static int hp_8200e_select_and_test_registers(struct us_data *us)
return USB_STOR_TRANSPORT_GOOD;
}
-int init_8200e(struct us_data *us)
+/*
+ * Initialize the USBAT processor and the storage device
+ */
+int init_usbat(struct us_data *us)
{
- int result;
+ int rc;
+ struct usbat_info *info;
+ unsigned char subcountH = USBAT_ATA_LBA_HI;
+ unsigned char subcountL = USBAT_ATA_LBA_ME;
unsigned char *status = us->iobuf;
- // Enable peripheral control signals
+ us->extra = kmalloc(sizeof(struct usbat_info), GFP_NOIO);
+ if (!us->extra) {
+ US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n");
+ return 1;
+ }
+ memset(us->extra, 0, sizeof(struct usbat_info));
+ info = (struct usbat_info *) (us->extra);
- if (usbat_write_user_io(us,
- USBAT_UIO_OE1 | USBAT_UIO_OE0,
- USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+ // Enable peripheral control signals
+ rc = usbat_write_user_io(us,
+ USBAT_UIO_OE1 | USBAT_UIO_OE0,
+ USBAT_UIO_EPAD | USBAT_UIO_1);
+ if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 1\n");
msleep(2000);
- if (usbat_read_user_io(us, status) !=
- USB_STOR_XFER_GOOD)
- return USB_STOR_TRANSPORT_ERROR;
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
US_DEBUGP("INIT 2\n");
- if (usbat_read_user_io(us, status) !=
- USB_STOR_XFER_GOOD)
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 3\n");
-
- // Reset peripheral, enable periph control signals
- // (bring reset signal up)
-
- if (usbat_write_user_io(us,
- USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0,
- USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 4\n");
-
- // Enable periph control signals
- // (bring reset signal down)
+ US_DEBUGP("INIT 3\n");
- if (usbat_write_user_io(us,
- USBAT_UIO_OE1 | USBAT_UIO_OE0,
- USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+ // At this point, we need to detect which device we are using
+ if (usbat_set_transport(us, info))
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 5\n");
+ US_DEBUGP("INIT 4\n");
- msleep(250);
+ if (usbat_get_device_type(us) == USBAT_DEV_HP8200) {
+ msleep(250);
- // Write 0x80 to ISA port 0x3F
+ // Write 0x80 to ISA port 0x3F
+ rc = usbat_write(us, USBAT_ISA, 0x3F, 0x80);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
- if (usbat_write(us, USBAT_ISA, 0x3F, 0x80) !=
- USB_STOR_XFER_GOOD)
- return USB_STOR_TRANSPORT_ERROR;
+ US_DEBUGP("INIT 5\n");
- US_DEBUGP("INIT 6\n");
+ // Read ISA port 0x27
+ rc = usbat_read(us, USBAT_ISA, 0x27, status);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
- // Read ISA port 0x27
+ US_DEBUGP("INIT 6\n");
- if (usbat_read(us, USBAT_ISA, 0x27, status) !=
- USB_STOR_XFER_GOOD)
- return USB_STOR_TRANSPORT_ERROR;
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 7\n");
+ US_DEBUGP("INIT 7\n");
+ }
- if (usbat_read_user_io(us, status) !=
- USB_STOR_XFER_GOOD)
- return USB_STOR_TRANSPORT_ERROR;
+ rc = usbat_select_and_test_registers(us);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
US_DEBUGP("INIT 8\n");
- if ( (result = hp_8200e_select_and_test_registers(us)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 9\n");
- if (usbat_read_user_io(us, status) !=
- USB_STOR_XFER_GOOD)
- return USB_STOR_TRANSPORT_ERROR;
+ // Enable peripheral control signals and card detect
+ rc = usbat_device_enable_cdt(us);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
US_DEBUGP("INIT 10\n");
- // Enable periph control signals and card detect
-
- if (usbat_write_user_io(us,
- USBAT_UIO_ACKD |USBAT_UIO_OE1 | USBAT_UIO_OE0,
- USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 11\n");
- if (usbat_read_user_io(us, status) !=
- USB_STOR_XFER_GOOD)
- return USB_STOR_TRANSPORT_ERROR;
-
- US_DEBUGP("INIT 12\n");
-
msleep(1400);
- if (usbat_read_user_io(us, status) !=
- USB_STOR_XFER_GOOD)
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 13\n");
+ US_DEBUGP("INIT 12\n");
- if ( (result = hp_8200e_select_and_test_registers(us)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
+ rc = usbat_select_and_test_registers(us);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
- US_DEBUGP("INIT 14\n");
+ US_DEBUGP("INIT 13\n");
- if (usbat_set_shuttle_features(us,
- 0x83, 0x00, 0x88, 0x08, 0x15, 0x14) !=
- USB_STOR_XFER_GOOD)
+ if (usbat_get_device_type(us) == USBAT_DEV_FLASH) {
+ subcountH = 0x02;
+ subcountL = 0x00;
+ }
+ rc = usbat_set_shuttle_features(us, (USBAT_FEAT_ETEN | USBAT_FEAT_ET2 | USBAT_FEAT_ET1),
+ 0x00, 0x88, 0x08, subcountH, subcountL);
+ if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 15\n");
+ US_DEBUGP("INIT 14\n");
return USB_STOR_TRANSPORT_GOOD;
}
@@ -807,7 +1417,7 @@ int init_8200e(struct us_data *us)
/*
* Transport for the HP 8200e
*/
-int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
+int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
{
int result;
unsigned char *status = us->iobuf;
@@ -824,13 +1434,13 @@ int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
commands... just ATA Packet Commands.
*/
- registers[0] = 0x11;
- registers[1] = 0x12;
- registers[2] = 0x13;
- registers[3] = 0x14;
- registers[4] = 0x15;
- registers[5] = 0x16;
- registers[6] = 0x17;
+ registers[0] = USBAT_ATA_FEATURES;
+ registers[1] = USBAT_ATA_SECCNT;
+ registers[2] = USBAT_ATA_SECNUM;
+ registers[3] = USBAT_ATA_LBA_ME;
+ registers[4] = USBAT_ATA_LBA_HI;
+ registers[5] = USBAT_ATA_DEVICE;
+ registers[6] = USBAT_ATA_CMD;
data[0] = 0x00;
data[1] = 0x00;
data[2] = 0x00;
@@ -844,7 +1454,7 @@ int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7];
}
- result = usbat_read(us, USBAT_ATA, 0x17, status);
+ result = usbat_get_status(us, status);
US_DEBUGP("Status = %02X\n", *status);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -853,9 +1463,10 @@ int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
if (srb->sc_data_direction == DMA_TO_DEVICE) {
- result = usbat_rw_block_test(us, USBAT_ATA,
+ result = usbat_hp8200e_rw_block_test(us, USBAT_ATA,
registers, data, 19,
- 0x10, 0x17, 0xFD, 0x30,
+ USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
+ (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
DMA_TO_DEVICE,
srb->request_buffer,
len, srb->use_sg, 10);
@@ -870,7 +1481,7 @@ int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
} else if (srb->cmnd[0] == READ_10 ||
srb->cmnd[0] == GPCMD_READ_CD) {
- return usbat_handle_read10(us, registers, data, srb);
+ return usbat_hp8200e_handle_read10(us, registers, data, srb);
}
@@ -881,7 +1492,6 @@ int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
}
if ( (result = usbat_multiple_write(us,
- USBAT_ATA,
registers, data, 7)) != USB_STOR_TRANSPORT_GOOD) {
return result;
}
@@ -895,7 +1505,7 @@ int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
// AT SPEED 4 IS UNRELIABLE!!!
if ( (result = usbat_write_block(us,
- USBAT_ATA, 0x10, srb->cmnd, 12, 0,
+ USBAT_ATA, srb->cmnd, 12,
srb->cmnd[0]==GPCMD_BLANK ? 75 : 10)) !=
USB_STOR_TRANSPORT_GOOD) {
return result;
@@ -908,14 +1518,14 @@ int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
// How many bytes to read in? Check cylL register
- if (usbat_read(us, USBAT_ATA, 0x14, status) !=
+ if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) !=
USB_STOR_XFER_GOOD) {
return USB_STOR_TRANSPORT_ERROR;
}
if (len > 0xFF) { // need to read cylH also
len = *status;
- if (usbat_read(us, USBAT_ATA, 0x15, status) !=
+ if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) !=
USB_STOR_XFER_GOOD) {
return USB_STOR_TRANSPORT_ERROR;
}
@@ -925,8 +1535,7 @@ int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
len = *status;
- result = usbat_read_block(us, USBAT_ATA, 0x10,
- srb->request_buffer, len, srb->use_sg);
+ result = usbat_read_block(us, srb->request_buffer, len);
/* Debug-print the first 32 bytes of the transfer */
@@ -948,4 +1557,153 @@ int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
return result;
}
+/*
+ * Transport for USBAT02-based CompactFlash and similar storage devices
+ */
+int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
+{
+ int rc;
+ struct usbat_info *info = (struct usbat_info *) (us->extra);
+ unsigned long block, blocks;
+ unsigned char *ptr = us->iobuf;
+ static unsigned char inquiry_response[36] = {
+ 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
+ };
+
+ if (srb->cmnd[0] == INQUIRY) {
+ US_DEBUGP("usbat_flash_transport: INQUIRY. Returning bogus response.\n");
+ memcpy(ptr, inquiry_response, sizeof(inquiry_response));
+ fill_inquiry_response(us, ptr, 36);
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ if (srb->cmnd[0] == READ_CAPACITY) {
+ rc = usbat_flash_check_media(us, info);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
+
+ rc = usbat_flash_get_sector_count(us, info);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
+
+ info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec
+ US_DEBUGP("usbat_flash_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
+ info->sectors, info->ssize);
+
+ // build the reply
+ // note: must return the sector number of the last sector,
+ // *not* the total number of sectors
+ ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
+ ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
+ usb_stor_set_xfer_buf(ptr, 8, srb);
+
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ if (srb->cmnd[0] == MODE_SELECT_10) {
+ US_DEBUGP("usbat_flash_transport: Gah! MODE_SELECT_10.\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ if (srb->cmnd[0] == READ_10) {
+ block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+ ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5]));
+
+ blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+ US_DEBUGP("usbat_flash_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks);
+ return usbat_flash_read_data(us, info, block, blocks);
+ }
+
+ if (srb->cmnd[0] == READ_12) {
+ // I don't think we'll ever see a READ_12 but support it anyway...
+ block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+ ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5]));
+
+ blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+ ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
+
+ US_DEBUGP("usbat_flash_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks);
+ return usbat_flash_read_data(us, info, block, blocks);
+ }
+
+ if (srb->cmnd[0] == WRITE_10) {
+ block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+ ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5]));
+
+ blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+ US_DEBUGP("usbat_flash_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks);
+ return usbat_flash_write_data(us, info, block, blocks);
+ }
+
+ if (srb->cmnd[0] == WRITE_12) {
+ // I don't think we'll ever see a WRITE_12 but support it anyway...
+ block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+ ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5]));
+
+ blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+ ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
+
+ US_DEBUGP("usbat_flash_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks);
+ return usbat_flash_write_data(us, info, block, blocks);
+ }
+
+
+ if (srb->cmnd[0] == TEST_UNIT_READY) {
+ US_DEBUGP("usbat_flash_transport: TEST_UNIT_READY.\n");
+
+ rc = usbat_flash_check_media(us, info);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
+
+ return usbat_check_status(us);
+ }
+
+ if (srb->cmnd[0] == REQUEST_SENSE) {
+ US_DEBUGP("usbat_flash_transport: REQUEST_SENSE.\n");
+
+ memset(ptr, 0, 18);
+ ptr[0] = 0xF0;
+ ptr[2] = info->sense_key;
+ ptr[7] = 11;
+ ptr[12] = info->sense_asc;
+ ptr[13] = info->sense_ascq;
+ usb_stor_set_xfer_buf(ptr, 18, srb);
+
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+ // sure. whatever. not like we can stop the user from popping
+ // the media out of the device (no locking doors, etc)
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ US_DEBUGP("usbat_flash_transport: Gah! Unknown command: %d (0x%x)\n",
+ srb->cmnd[0], srb->cmnd[0]);
+ info->sense_key = 0x05;
+ info->sense_asc = 0x20;
+ info->sense_ascq = 0x00;
+ return USB_STOR_TRANSPORT_FAILED;
+}
+
+/*
+ * Default transport function. Attempts to detect which transport function
+ * should be called, makes it the new default, and calls it.
+ *
+ * This function should never be called. Our usbat_init() function detects the
+ * device type and changes the us->transport ptr to the transport function
+ * relevant to the device.
+ * However, we'll support this impossible(?) case anyway.
+ */
+int usbat_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+ struct usbat_info *info = (struct usbat_info*) (us->extra);
+
+ if (usbat_set_transport(us, info))
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return us->transport(srb, us);
+}
diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h
index 9855c1d32d05..32fec067d518 100644
--- a/drivers/usb/storage/shuttle_usbat.h
+++ b/drivers/usb/storage/shuttle_usbat.h
@@ -5,8 +5,9 @@
*
* Current development and maintenance by:
* (c) 2000 Robert Baruch (autophile@dol.net)
+ * (c) 2004, 2005 Daniel Drake <dsd@gentoo.org>
*
- * See scm.c for more explanation
+ * See shuttle_usbat.c for more explanation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -26,13 +27,59 @@
#ifndef _USB_SHUTTLE_USBAT_H
#define _USB_SHUTTLE_USBAT_H
+/* Supported device types */
+#define USBAT_DEV_HP8200 0x01
+#define USBAT_DEV_FLASH 0x02
+
#define USBAT_EPP_PORT 0x10
#define USBAT_EPP_REGISTER 0x30
#define USBAT_ATA 0x40
#define USBAT_ISA 0x50
-/* SCM User I/O Data registers */
+/* Commands (need to be logically OR'd with an access type */
+#define USBAT_CMD_READ_REG 0x00
+#define USBAT_CMD_WRITE_REG 0x01
+#define USBAT_CMD_READ_BLOCK 0x02
+#define USBAT_CMD_WRITE_BLOCK 0x03
+#define USBAT_CMD_COND_READ_BLOCK 0x04
+#define USBAT_CMD_COND_WRITE_BLOCK 0x05
+#define USBAT_CMD_WRITE_REGS 0x07
+
+/* Commands (these don't need an access type) */
+#define USBAT_CMD_EXEC_CMD 0x80
+#define USBAT_CMD_SET_FEAT 0x81
+#define USBAT_CMD_UIO 0x82
+
+/* Methods of accessing UIO register */
+#define USBAT_UIO_READ 1
+#define USBAT_UIO_WRITE 0
+
+/* Qualifier bits */
+#define USBAT_QUAL_FCQ 0x20 // full compare
+#define USBAT_QUAL_ALQ 0x10 // auto load subcount
+
+/* USBAT Flash Media status types */
+#define USBAT_FLASH_MEDIA_NONE 0
+#define USBAT_FLASH_MEDIA_CF 1
+
+/* USBAT Flash Media change types */
+#define USBAT_FLASH_MEDIA_SAME 0
+#define USBAT_FLASH_MEDIA_CHANGED 1
+
+/* USBAT ATA registers */
+#define USBAT_ATA_DATA 0x10 // read/write data (R/W)
+#define USBAT_ATA_FEATURES 0x11 // set features (W)
+#define USBAT_ATA_ERROR 0x11 // error (R)
+#define USBAT_ATA_SECCNT 0x12 // sector count (R/W)
+#define USBAT_ATA_SECNUM 0x13 // sector number (R/W)
+#define USBAT_ATA_LBA_ME 0x14 // cylinder low (R/W)
+#define USBAT_ATA_LBA_HI 0x15 // cylinder high (R/W)
+#define USBAT_ATA_DEVICE 0x16 // head/device selection (R/W)
+#define USBAT_ATA_STATUS 0x17 // device status (R)
+#define USBAT_ATA_CMD 0x17 // device command (W)
+#define USBAT_ATA_ALTSTATUS 0x0E // status (no clear IRQ) (R)
+/* USBAT User I/O Data registers */
#define USBAT_UIO_EPAD 0x80 // Enable Peripheral Control Signals
#define USBAT_UIO_CDT 0x40 // Card Detect (Read Only)
// CDT = ACKD & !UI1 & !UI0
@@ -43,8 +90,7 @@
#define USBAT_UIO_UI0 0x02 // Input 0
#define USBAT_UIO_INTR_ACK 0x01 // Interrupt (ATA & ISA)/Acknowledge (EPP)
-/* SCM User I/O Enable registers */
-
+/* USBAT User I/O Enable registers */
#define USBAT_UIO_DRVRST 0x80 // Reset Peripheral
#define USBAT_UIO_ACKD 0x40 // Enable Card Detect
#define USBAT_UIO_OE1 0x20 // I/O 1 set=output/clr=input
@@ -52,8 +98,30 @@
#define USBAT_UIO_OE0 0x10 // I/O 0 set=output/clr=input
#define USBAT_UIO_ADPRST 0x01 // Reset SCM chip
-/* HP 8200e stuff */
-extern int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us);
-extern int init_8200e(struct us_data *us);
+/* USBAT Features */
+#define USBAT_FEAT_ETEN 0x80 // External trigger enable
+#define USBAT_FEAT_U1 0x08
+#define USBAT_FEAT_U0 0x04
+#define USBAT_FEAT_ET1 0x02
+#define USBAT_FEAT_ET2 0x01
+
+/* Transport functions */
+int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us);
+int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us);
+
+extern int usbat_transport(struct scsi_cmnd *srb, struct us_data *us);
+extern int init_usbat(struct us_data *us);
+
+struct usbat_info {
+ int devicetype;
+
+ /* Used for Flash readers only */
+ unsigned long sectors; // total sector count
+ unsigned long ssize; // sector size in bytes
+
+ unsigned char sense_key;
+ unsigned long sense_asc; // additional sense code
+ unsigned long sense_ascq; // additional sense code qualifier
+};
#endif
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index ddc1e3bcf845..b4047f3a01cd 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -991,10 +991,10 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
/* DATA STAGE */
/* send/receive data payload, if there is any */
- /* Genesys Logic interface chips need a 100us delay between the
+ /* Some USB-IDE converter chips need a 100us delay between the
* command phase and the data phase. Some devices need a little
* more than that, probably because of clock rate inaccuracies. */
- if (le16_to_cpu(us->pusb_dev->descriptor.idVendor) == USB_VENDOR_ID_GENESYS)
+ if (unlikely(us->flags & US_FL_GO_SLOW))
udelay(110);
if (transfer_length) {
@@ -1055,19 +1055,31 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
le32_to_cpu(bcs->Signature), bcs->Tag,
residue, bcs->Status);
- if ((bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) &&
- bcs->Signature != cpu_to_le32(US_BULK_CS_OLYMPUS_SIGN)) ||
- bcs->Tag != srb->serial_number ||
- bcs->Status > US_BULK_STAT_PHASE) {
+ if (bcs->Tag != srb->serial_number || bcs->Status > US_BULK_STAT_PHASE) {
US_DEBUGP("Bulk logical error\n");
return USB_STOR_TRANSPORT_ERROR;
}
+ /* Some broken devices report odd signatures, so we do not check them
+ * for validity against the spec. We store the first one we see,
+ * and check subsequent transfers for validity against this signature.
+ */
+ if (!us->bcs_signature) {
+ us->bcs_signature = bcs->Signature;
+ if (us->bcs_signature != cpu_to_le32(US_BULK_CS_SIGN))
+ US_DEBUGP("Learnt BCS signature 0x%08X\n",
+ le32_to_cpu(us->bcs_signature));
+ } else if (bcs->Signature != us->bcs_signature) {
+ US_DEBUGP("Signature mismatch: got %08X, expecting %08X\n",
+ le32_to_cpu(bcs->Signature),
+ le32_to_cpu(us->bcs_signature));
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
/* try to compute the actual residue, based on how much data
* was really transferred and what the device tells us */
if (residue) {
- if (!(us->flags & US_FL_IGNORE_RESIDUE) ||
- srb->sc_data_direction == DMA_TO_DEVICE) {
+ if (!(us->flags & US_FL_IGNORE_RESIDUE)) {
residue = min(residue, transfer_length);
srb->resid = max(srb->resid, (int) residue);
}
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index 153efd623afb..0f12370bd34e 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -52,7 +52,7 @@ struct scsi_cmnd;
#define US_PR_CBI 0x00 /* Control/Bulk/Interrupt */
#define US_PR_CB 0x01 /* Control/Bulk w/o interrupt */
#define US_PR_BULK 0x50 /* bulk only */
-#ifdef CONFIG_USB_STORAGE_HP8200e
+#ifdef CONFIG_USB_STORAGE_USBAT
#define US_PR_SCM_ATAPI 0x80 /* SCM-ATAPI bridge */
#endif
#ifdef CONFIG_USB_STORAGE_SDDR09
@@ -108,8 +108,6 @@ struct bulk_cs_wrap {
#define US_BULK_CS_WRAP_LEN 13
#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */
-/* This is for Olympus Camedia digital cameras */
-#define US_BULK_CS_OLYMPUS_SIGN 0x55425355 /* spells out 'USBU' */
#define US_BULK_STAT_OK 0
#define US_BULK_STAT_FAIL 1
#define US_BULK_STAT_PHASE 2
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index e0904aab6b69..0fc20b877803 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -59,16 +59,16 @@ UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200,
"CD-Writer+",
US_SC_8070, US_PR_CB, NULL, 0),
-#ifdef CONFIG_USB_STORAGE_HP8200e
+#ifdef CONFIG_USB_STORAGE_USBAT
UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001,
"HP",
"CD-Writer+ 8200e",
- US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0),
+ US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0),
UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001,
"HP",
"CD-Writer+ CD-4e",
- US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0),
+ US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0),
#endif
/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
@@ -123,6 +123,13 @@ UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001,
"DVD-CAM DZ-MV100A Camcorder",
US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN),
+/* Reported by Andreas Bockhold <andreas@bockionline.de> */
+UNUSUAL_DEV( 0x04b0, 0x0405, 0x0100, 0x0100,
+ "NIKON",
+ "NIKON DSC D70",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* Reported by Simon Levitt <simon@whattf.com>
* This entry needs Sub and Proto fields */
UNUSUAL_DEV( 0x04b8, 0x0601, 0x0100, 0x0100,
@@ -171,15 +178,12 @@ 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). */
+/* Reported by Adriaan Penning <a.penning@luon.net> */
UNUSUAL_DEV( 0x04da, 0x2372, 0x0000, 0x9999,
"Panasonic",
"DMC-LCx Camera",
US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
+ US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ),
/* Most of the following entries were developed with the help of
* Shuttle/SCM directly.
@@ -268,6 +272,14 @@ UNUSUAL_DEV( 0x04fc, 0x80c2, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_BULK32),
+#ifdef CONFIG_USB_STORAGE_USBAT
+UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999,
+ "SCM",
+ "SCM USBAT-02",
+ US_SC_SCSI, US_PR_SCM_ATAPI, init_usbat,
+ US_FL_SINGLE_LUN),
+#endif
+
/* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */
UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133,
"Belkin",
@@ -324,12 +336,11 @@ UNUSUAL_DEV( 0x052b, 0x1911, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
-/* This entry is needed because the device reports Sub=ff */
UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450,
"Sony",
"DSC-S30/S70/S75/505V/F505/F707/F717/P8",
US_SC_SCSI, US_PR_DEVICE, NULL,
- US_FL_SINGLE_LUN ),
+ US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE ),
/* This entry is needed because the device reports Sub=ff */
UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0500,
@@ -512,6 +523,25 @@ UNUSUAL_DEV( 0x05dc, 0xb002, 0x0000, 0x0113,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
+/* The following two entries are for a Genesys USB to IDE
+ * converter chip, but it changes its ProductId depending
+ * on whether or not a disk or an optical device is enclosed
+ * They were originally reported by Alexander Oltu
+ * <alexander@all-2.com> and Peter Marks <peter.marks@turner.com>
+ * respectively.
+ */
+UNUSUAL_DEV( 0x05e3, 0x0701, 0x0000, 0xffff,
+ "Genesys Logic",
+ "USB to IDE Optical",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_GO_SLOW ),
+
+UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff,
+ "Genesys Logic",
+ "USB to IDE Disk",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_GO_SLOW ),
+
/* Reported by Hanno Boeck <hanno@gmx.de>
* Taken from the Lycoris Kernel */
UNUSUAL_DEV( 0x0636, 0x0003, 0x0000, 0x9999,
@@ -540,19 +570,19 @@ UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
-/* Reported by Alex Butcher <alex.butcher@assursys.co.uk> */
-UNUSUAL_DEV( 0x067b, 0x3507, 0x0001, 0x0001,
+/* Reported by Richard -=[]=- <micro_flyer@hotmail.com> */
+UNUSUAL_DEV( 0x067b, 0x2507, 0x0100, 0x0100,
"Prolific Technology Inc.",
- "ATAPI-6 Bridge Controller",
+ "Mass Storage Device",
US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
+ US_FL_FIX_CAPACITY | US_FL_GO_SLOW ),
/* Reported by Alex Butcher <alex.butcher@assursys.co.uk> */
UNUSUAL_DEV( 0x067b, 0x3507, 0x0001, 0x0001,
"Prolific Technology Inc.",
"ATAPI-6 Bridge Controller",
US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
+ US_FL_FIX_CAPACITY | US_FL_GO_SLOW ),
/* Submitted by Benny Sjostrand <benny@hostmobility.com> */
UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001,
@@ -582,12 +612,18 @@ UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200,
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN ),
-#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE)
UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009,
"Sandisk",
"ImageMate SDDR-31",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_SER ),
+
+#ifdef CONFIG_USB_STORAGE_USBAT
+UNUSUAL_DEV( 0x0781, 0x0005, 0x0005, 0x0005,
+ "Sandisk",
+ "ImageMate SDDR-05b",
+ US_SC_SCSI, US_PR_SCM_ATAPI, init_usbat,
+ US_FL_SINGLE_LUN),
#endif
UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100,
@@ -866,6 +902,13 @@ UNUSUAL_DEV( 0x0dda, 0x0001, 0x0012, 0x0012,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Ian McConnell <ian at emit.demon.co.uk> */
+UNUSUAL_DEV( 0x0dda, 0x0301, 0x0012, 0x0012,
+ "PNP_MP3",
+ "PNP_MP3 PLAYER",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
/* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */
UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
"USB",
@@ -905,6 +948,13 @@ UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Radovan Garabik <garabik@kassiopeia.juls.savba.sk> */
+UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999,
+ "MPIO",
+ "HS200",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_GO_SLOW ),
+
#ifdef CONFIG_USB_STORAGE_SDDR55
UNUSUAL_DEV( 0x55aa, 0xa103, 0x0000, 0x9999,
"Sandisk",
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 0a8c42a0a8bf..2dab9de75783 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -63,7 +63,7 @@
#include "debug.h"
#include "initializers.h"
-#ifdef CONFIG_USB_STORAGE_HP8200e
+#ifdef CONFIG_USB_STORAGE_USBAT
#include "shuttle_usbat.h"
#endif
#ifdef CONFIG_USB_STORAGE_SDDR09
@@ -144,9 +144,7 @@ static struct usb_device_id storage_usb_ids [] = {
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) },
-#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE)
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
-#endif
/* Terminating entry */
{ }
@@ -220,10 +218,8 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
.useTransport = US_PR_BULK},
{ .useProtocol = US_SC_8070,
.useTransport = US_PR_BULK},
-#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE)
{ .useProtocol = US_SC_SCSI,
.useTransport = US_PR_BULK},
-#endif
/* Terminating entry */
{ NULL }
@@ -483,6 +479,13 @@ static void get_device_info(struct us_data *us, int id_index)
unusual_dev->useTransport;
us->flags = unusual_dev->flags;
+ /*
+ * This flag is only needed when we're in high-speed, so let's
+ * disable it if we're in full-speed
+ */
+ if (dev->speed != USB_SPEED_HIGH)
+ us->flags &= ~US_FL_GO_SLOW;
+
/* Log a message if a non-generic unusual_dev entry contains an
* unnecessary subclass or protocol override. This may stimulate
* reports from users that will help us remove unneeded entries
@@ -515,37 +518,6 @@ static void get_device_info(struct us_data *us, int id_index)
idesc->bInterfaceProtocol,
msgs[msg]);
}
-
- /* Read the device's string descriptors */
- if (dev->descriptor.iManufacturer)
- usb_string(dev, dev->descriptor.iManufacturer,
- us->vendor, sizeof(us->vendor));
- if (dev->descriptor.iProduct)
- usb_string(dev, dev->descriptor.iProduct,
- us->product, sizeof(us->product));
- if (dev->descriptor.iSerialNumber)
- usb_string(dev, dev->descriptor.iSerialNumber,
- us->serial, sizeof(us->serial));
-
- /* Use the unusual_dev strings if the device didn't provide them */
- if (strlen(us->vendor) == 0) {
- if (unusual_dev->vendorName)
- strlcpy(us->vendor, unusual_dev->vendorName,
- sizeof(us->vendor));
- else
- strcpy(us->vendor, "Unknown");
- }
- if (strlen(us->product) == 0) {
- if (unusual_dev->productName)
- strlcpy(us->product, unusual_dev->productName,
- sizeof(us->product));
- else
- strcpy(us->product, "Unknown");
- }
- if (strlen(us->serial) == 0)
- strcpy(us->serial, "None");
-
- US_DEBUGP("Vendor: %s, Product: %s\n", us->vendor, us->product);
}
/* Get the transport settings */
@@ -572,10 +544,10 @@ static int get_transport(struct us_data *us)
us->transport_reset = usb_stor_Bulk_reset;
break;
-#ifdef CONFIG_USB_STORAGE_HP8200e
+#ifdef CONFIG_USB_STORAGE_USBAT
case US_PR_SCM_ATAPI:
us->transport_name = "SCM/ATAPI";
- us->transport = hp8200e_transport;
+ us->transport = usbat_transport;
us->transport_reset = usb_stor_CB_reset;
us->max_lun = 1;
break;
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index aaaf7ed5455c..68b528320652 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -75,6 +75,8 @@ struct us_unusual_dev {
#define US_FL_FIX_CAPACITY 0x00000080 /* READ CAPACITY response too big */
#define US_FL_IGNORE_RESIDUE 0x00000100 /* reported residue is wrong */
#define US_FL_BULK32 0x00000200 /* Uses 32-byte CBW length */
+#define US_FL_NOT_LOCKABLE 0x00000400 /* PREVENT/ALLOW not supported */
+#define US_FL_GO_SLOW 0x00000800 /* Need delay after Command phase */
/* Dynamic flag definitions: used in set_bit() etc. */
#define US_FLIDX_URB_ACTIVE 18 /* 0x00040000 current_urb is in use */
@@ -121,11 +123,9 @@ struct us_data {
unsigned int recv_intr_pipe;
/* information about the device */
- char vendor[USB_STOR_STRING_LEN];
- char product[USB_STOR_STRING_LEN];
- char serial[USB_STOR_STRING_LEN];
char *transport_name;
char *protocol_name;
+ __le32 bcs_signature;
u8 subclass;
u8 protocol;
u8 max_lun;
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 71abda209aa2..1bb67337fe6f 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -120,7 +120,7 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, count),
- &count, HZ*10);
+ &count, 10000);
/* if the read was successful, copy the data to userspace */
if (!retval) {
@@ -271,7 +271,7 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
}
if (!dev->bulk_out_endpointAddr &&
- !(endpoint->bEndpointAddress & USB_DIR_IN) &&
+ !(endpoint->bEndpointAddress & USB_DIR_OUT) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK)) {
/* we found a bulk out endpoint */
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
index b54ec447725d..3c026b036c86 100644
--- a/drivers/video/backlight/corgi_bl.c
+++ b/drivers/video/backlight/corgi_bl.c
@@ -52,9 +52,9 @@ static void corgibl_send_intensity(int intensity)
corgi_ssp_blduty_set(intensity & 0x1f);
/* Bit 5 is via SCOOP */
if (intensity & 0x0020)
- set_scoop_gpio(CORGI_SCP_BACKLIGHT_CONT);
+ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
else
- reset_scoop_gpio(CORGI_SCP_BACKLIGHT_CONT);
+ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
spin_unlock_irqrestore(&bl_lock, flags);
}
diff --git a/drivers/w1/dscore.c b/drivers/w1/dscore.c
index ccb33fa13e63..eee6644d33d6 100644
--- a/drivers/w1/dscore.c
+++ b/drivers/w1/dscore.c
@@ -81,7 +81,7 @@ static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
int err;
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
- CONTROL_CMD, 0x40, value, index, NULL, 0, HZ);
+ CONTROL_CMD, 0x40, value, index, NULL, 0, 1000);
if (err < 0) {
printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n",
value, index, err);
@@ -96,7 +96,7 @@ static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
int err;
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
- MODE_CMD, 0x40, value, index, NULL, 0, HZ);
+ MODE_CMD, 0x40, value, index, NULL, 0, 1000);
if (err < 0) {
printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n",
value, index, err);
@@ -111,7 +111,7 @@ static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
int err;
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
- COMM_CMD, 0x40, value, index, NULL, 0, HZ);
+ COMM_CMD, 0x40, value, index, NULL, 0, 1000);
if (err < 0) {
printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",
value, index, err);
@@ -210,7 +210,7 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
count = 0;
err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
- buf, size, &count, HZ);
+ buf, size, &count, 1000);
if (err < 0) {
printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
@@ -236,7 +236,7 @@ static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
int count, err;
count = 0;
- err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, HZ);
+ err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
if (err < 0) {
printk(KERN_ERR "Failed to read 1-wire data from 0x02: err=%d.\n", err);
return err;
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 25ab41399ec4..d46c4cc3ffc4 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -2515,229 +2515,11 @@ static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg
return sys_ioctl(fd, USBDEVFS_BULK, (unsigned long)p);
}
-/* This needs more work before we can enable it. Unfortunately
- * because of the fancy asynchronous way URB status/error is written
- * back to userspace, we'll need to fiddle with USB devio internals
- * and/or reimplement entirely the frontend of it ourselves. -DaveM
- *
- * The issue is:
- *
- * When an URB is submitted via usbdevicefs it is put onto an
- * asynchronous queue. When the URB completes, it may be reaped
- * via another ioctl. During this reaping the status is written
- * back to userspace along with the length of the transfer.
- *
- * We must translate into 64-bit kernel types so we pass in a kernel
- * space copy of the usbdevfs_urb structure. This would mean that we
- * must do something to deal with the async entry reaping. First we
- * have to deal somehow with this transitory memory we've allocated.
- * This is problematic since there are many call sites from which the
- * async entries can be destroyed (and thus when we'd need to free up
- * this kernel memory). One of which is the close() op of usbdevicefs.
- * To handle that we'd need to make our own file_operations struct which
- * overrides usbdevicefs's release op with our own which runs usbdevicefs's
- * real release op then frees up the kernel memory.
- *
- * But how to keep track of these kernel buffers? We'd need to either
- * keep track of them in some table _or_ know about usbdevicefs internals
- * (ie. the exact layout of its file private, which is actually defined
- * in linux/usbdevice_fs.h, the layout of the async queues are private to
- * devio.c)
- *
- * There is one possible other solution I considered, also involving knowledge
- * of usbdevicefs internals:
- *
- * After an URB is submitted, we "fix up" the address back to the user
- * space one. This would work if the status/length fields written back
- * by the async URB completion lines up perfectly in the 32-bit type with
- * the 64-bit kernel type. Unfortunately, it does not because the iso
- * frame descriptors, at the end of the struct, can be written back.
- *
- * I think we'll just need to simply duplicate the devio URB engine here.
- */
-#if 0
-struct usbdevfs_urb32 {
- unsigned char type;
- unsigned char endpoint;
- compat_int_t status;
- compat_uint_t flags;
- compat_caddr_t buffer;
- compat_int_t buffer_length;
- compat_int_t actual_length;
- compat_int_t start_frame;
- compat_int_t number_of_packets;
- compat_int_t error_count;
- compat_uint_t signr;
- compat_caddr_t usercontext; /* unused */
- struct usbdevfs_iso_packet_desc iso_frame_desc[0];
-};
-
-#define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32)
-
-static int get_urb32(struct usbdevfs_urb *kurb,
- struct usbdevfs_urb32 *uurb)
-{
- if (get_user(kurb->type, &uurb->type) ||
- __get_user(kurb->endpoint, &uurb->endpoint) ||
- __get_user(kurb->status, &uurb->status) ||
- __get_user(kurb->flags, &uurb->flags) ||
- __get_user(kurb->buffer_length, &uurb->buffer_length) ||
- __get_user(kurb->actual_length, &uurb->actual_length) ||
- __get_user(kurb->start_frame, &uurb->start_frame) ||
- __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
- __get_user(kurb->error_count, &uurb->error_count) ||
- __get_user(kurb->signr, &uurb->signr))
- return -EFAULT;
-
- kurb->usercontext = 0; /* unused currently */
-
- return 0;
-}
-
-/* Just put back the values which usbdevfs actually changes. */
-static int put_urb32(struct usbdevfs_urb *kurb,
- struct usbdevfs_urb32 *uurb)
-{
- if (put_user(kurb->status, &uurb->status) ||
- __put_user(kurb->actual_length, &uurb->actual_length) ||
- __put_user(kurb->error_count, &uurb->error_count))
- return -EFAULT;
-
- if (kurb->number_of_packets != 0) {
- int i;
-
- for (i = 0; i < kurb->number_of_packets; i++) {
- if (__put_user(kurb->iso_frame_desc[i].actual_length,
- &uurb->iso_frame_desc[i].actual_length) ||
- __put_user(kurb->iso_frame_desc[i].status,
- &uurb->iso_frame_desc[i].status))
- return -EFAULT;
- }
- }
-
- return 0;
-}
-
-static int get_urb32_isoframes(struct usbdevfs_urb *kurb,
- struct usbdevfs_urb32 *uurb)
-{
- unsigned int totlen;
- int i;
-
- if (kurb->type != USBDEVFS_URB_TYPE_ISO) {
- kurb->number_of_packets = 0;
- return 0;
- }
-
- if (kurb->number_of_packets < 1 ||
- kurb->number_of_packets > 128)
- return -EINVAL;
-
- if (copy_from_user(&kurb->iso_frame_desc[0],
- &uurb->iso_frame_desc[0],
- sizeof(struct usbdevfs_iso_packet_desc) *
- kurb->number_of_packets))
- return -EFAULT;
-
- totlen = 0;
- for (i = 0; i < kurb->number_of_packets; i++) {
- unsigned int this_len;
-
- this_len = kurb->iso_frame_desc[i].length;
- if (this_len > 1023)
- return -EINVAL;
-
- totlen += this_len;
- }
-
- if (totlen > 32768)
- return -EINVAL;
-
- kurb->buffer_length = totlen;
-
- return 0;
-}
-
-static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct usbdevfs_urb *kurb;
- struct usbdevfs_urb32 *uurb;
- mm_segment_t old_fs;
- __u32 udata;
- void *uptr, *kptr;
- unsigned int buflen;
- int err;
-
- uurb = compat_ptr(arg);
-
- err = -ENOMEM;
- kurb = kmalloc(sizeof(struct usbdevfs_urb) +
- (sizeof(struct usbdevfs_iso_packet_desc) * 128),
- GFP_KERNEL);
- if (!kurb)
- goto out;
-
- err = -EFAULT;
- if (get_urb32(kurb, uurb))
- goto out;
-
- err = get_urb32_isoframes(kurb, uurb);
- if (err)
- goto out;
-
- err = -EFAULT;
- if (__get_user(udata, &uurb->buffer))
- goto out;
- uptr = compat_ptr(udata);
-
- buflen = kurb->buffer_length;
- err = verify_area(VERIFY_WRITE, uptr, buflen);
- if (err)
- goto out;
-
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb);
- set_fs(old_fs);
- if (err >= 0) {
- /* RED-PEN Shit, this doesn't work for async URBs :-( XXX */
- if (put_urb32(kurb, uurb)) {
- err = -EFAULT;
- }
- }
-
-out:
- kfree(kurb);
- return err;
-}
-#endif
-
-#define USBDEVFS_REAPURB32 _IOW('U', 12, u32)
-#define USBDEVFS_REAPURBNDELAY32 _IOW('U', 13, u32)
-
-static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- mm_segment_t old_fs;
- void *kptr;
- int err;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd,
- (cmd == USBDEVFS_REAPURB32 ?
- USBDEVFS_REAPURB :
- USBDEVFS_REAPURBNDELAY),
- (unsigned long) &kptr);
- set_fs(old_fs);
-
- if (err >= 0 &&
- put_user((u32)(u64)kptr, (u32 __user *)compat_ptr(arg)))
- err = -EFAULT;
-
- return err;
-}
+/*
+ * USBDEVFS_SUBMITURB, USBDEVFS_REAPURB and USBDEVFS_REAPURBNDELAY
+ * are handled in usbdevfs core. -Christopher Li
+ */
struct usbdevfs_disconnectsignal32 {
compat_int_t signr;
@@ -3269,9 +3051,6 @@ HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl)
/* Usbdevfs */
HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
-/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
-HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
-HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
/* i2c */
HANDLE_IOCTL(I2C_FUNCS, w_long)
diff --git a/include/asm-arm/arch-ixp2000/io.h b/include/asm-arm/arch-ixp2000/io.h
index 571dbbcd8521..4555265cf5ce 100644
--- a/include/asm-arm/arch-ixp2000/io.h
+++ b/include/asm-arm/arch-ixp2000/io.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-arm/arch-ixdp2000/io.h
+ * linux/include/asm-arm/arch-ixp2000/io.h
*
* Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
* Maintainer: Deepak Saxena <dsaxena@plexity.net>
diff --git a/include/asm-arm/arch-ixp2000/ixdp2x01.h b/include/asm-arm/arch-ixp2000/ixdp2x01.h
index 9e1672cd84cf..b3a1bcda8d01 100644
--- a/include/asm-arm/arch-ixp2000/ixdp2x01.h
+++ b/include/asm-arm/arch-ixp2000/ixdp2x01.h
@@ -1,5 +1,5 @@
/*
- * include/asm/arch/ixdp2x01.h
+ * include/asm-arm/arch-ixp2000/ixdp2x01.h
*
* Platform definitions for IXDP2X01 && IXDP2801 systems
*
diff --git a/include/asm-arm/arch-ixp2000/platform.h b/include/asm-arm/arch-ixp2000/platform.h
index 16e4a240199d..7118a843ab12 100644
--- a/include/asm-arm/arch-ixp2000/platform.h
+++ b/include/asm-arm/arch-ixp2000/platform.h
@@ -1,5 +1,5 @@
/*
- * include/asm-arh/arch-ixp2000/platform.h
+ * include/asm-arm/arch-ixp2000/platform.h
*
* Various bits of code used by platform-level code.
*
@@ -50,7 +50,7 @@ static inline void ixp2000_reg_write(volatile unsigned long *reg, unsigned long
* Boards may multiplex different devices on the 2nd channel of
* the slowport interface that each need different configuration
* settings. For example, the IXDP2400 uses channel 2 on the interface
- * to access the CPLD, the switch fabric card, and te media card. Each
+ * to access the CPLD, the switch fabric card, and the media card. Each
* one needs a different mode so drivers must save/restore the mode
* before and after each operation.
*
diff --git a/include/asm-arm/arch-pxa/corgi.h b/include/asm-arm/arch-pxa/corgi.h
index 950c9378a6a6..4f69467327d1 100644
--- a/include/asm-arm/arch-pxa/corgi.h
+++ b/include/asm-arm/arch-pxa/corgi.h
@@ -133,6 +133,10 @@ struct sharpsl_flash_param_info {
unsigned int phadadj;
};
+/*
+ * Shared data structures
+ */
+extern struct platform_device corgiscoop_device;
/*
* External Functions
diff --git a/include/asm-arm/hardware/scoop.h b/include/asm-arm/hardware/scoop.h
index 669b7df6e570..7ea771ff6144 100644
--- a/include/asm-arm/hardware/scoop.h
+++ b/include/asm-arm/hardware/scoop.h
@@ -40,8 +40,8 @@ struct scoop_config {
unsigned short io_dir;
};
-void reset_scoop(void);
-unsigned short set_scoop_gpio(unsigned short bit);
-unsigned short reset_scoop_gpio(unsigned short bit);
-unsigned short read_scoop_reg(unsigned short reg);
-void write_scoop_reg(unsigned short reg, unsigned short data);
+void reset_scoop(struct device *dev);
+unsigned short set_scoop_gpio(struct device *dev, unsigned short bit);
+unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit);
+unsigned short read_scoop_reg(struct device *dev, unsigned short reg);
+void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data);
diff --git a/include/asm-parisc/checksum.h b/include/asm-parisc/checksum.h
index f8bfc4c72236..229cb56fdb7a 100644
--- a/include/asm-parisc/checksum.h
+++ b/include/asm-parisc/checksum.h
@@ -30,8 +30,8 @@ extern unsigned int csum_partial_copy_nocheck(const unsigned char *, unsigned ch
* this is a new version of the above that records errors it finds in *errp,
* but continues and zeros the rest of the buffer.
*/
-extern unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst,
- int len, unsigned int sum, int *errp);
+extern unsigned int csum_partial_copy_from_user(const unsigned char __user *src,
+ unsigned char *dst, int len, unsigned int sum, int *errp);
/*
* Optimized for IP headers, which always checksum on 4 octet boundaries.
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
index 3edb5db3eace..ca0eac647a05 100644
--- a/include/asm-parisc/compat.h
+++ b/include/asm-parisc/compat.h
@@ -131,15 +131,15 @@ typedef u32 compat_sigset_word;
*/
typedef u32 compat_uptr_t;
-static inline void *compat_ptr(compat_uptr_t uptr)
+static inline void __user *compat_ptr(compat_uptr_t uptr)
{
- return (void *)(unsigned long)uptr;
+ return (void __user *)(unsigned long)uptr;
}
-static __inline__ void *compat_alloc_user_space(long len)
+static __inline__ void __user *compat_alloc_user_space(long len)
{
struct pt_regs *regs = &current->thread.regs;
- return (void *)regs->gr[30];
+ return (void __user *)regs->gr[30];
}
#endif /* _ASM_PARISC_COMPAT_H */
diff --git a/include/asm-parisc/ide.h b/include/asm-parisc/ide.h
index 15a9374c1c0f..a463c8642cab 100644
--- a/include/asm-parisc/ide.h
+++ b/include/asm-parisc/ide.h
@@ -13,8 +13,6 @@
#ifdef __KERNEL__
-#include <linux/config.h>
-
#ifndef MAX_HWIFS
#define MAX_HWIFS 2
#endif
diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h
index 4e5fad213c39..75654ba93353 100644
--- a/include/asm-parisc/irq.h
+++ b/include/asm-parisc/irq.h
@@ -40,10 +40,12 @@ struct hw_interrupt_type;
void no_ack_irq(unsigned int irq);
void no_end_irq(unsigned int irq);
-extern int txn_alloc_irq(void);
+extern int txn_alloc_irq(unsigned int nbits);
extern int txn_claim_irq(int);
-extern unsigned int txn_alloc_data(int, unsigned int);
-extern unsigned long txn_alloc_addr(int);
+extern unsigned int txn_alloc_data(unsigned int);
+extern unsigned long txn_alloc_addr(unsigned int);
+
+extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *);
extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *);
diff --git a/include/asm-parisc/numnodes.h b/include/asm-parisc/numnodes.h
index dcdd933eb60b..6c67651efd1c 100644
--- a/include/asm-parisc/numnodes.h
+++ b/include/asm-parisc/numnodes.h
@@ -1,8 +1,6 @@
#ifndef _ASM_MAX_NUMNODES_H
#define _ASM_MAX_NUMNODES_H
-#include <linux/config.h>
-
/* Max 8 Nodes */
#define NODES_SHIFT 3
diff --git a/include/asm-parisc/serial.h b/include/asm-parisc/serial.h
index 230644f9e28e..239c5dcab7e6 100644
--- a/include/asm-parisc/serial.h
+++ b/include/asm-parisc/serial.h
@@ -2,8 +2,6 @@
* include/asm-parisc/serial.h
*/
-#include <linux/config.h>
-
/*
* This assumes you have a 7.272727 MHz clock for your UART.
* The documentation implies a 40Mhz clock, and elsewhere a 7Mhz clock
diff --git a/include/asm-parisc/signal.h b/include/asm-parisc/signal.h
index cd4beefef333..358f577c8eb8 100644
--- a/include/asm-parisc/signal.h
+++ b/include/asm-parisc/signal.h
@@ -123,13 +123,14 @@ struct siginfo;
* compiler doesn't support code which changes or tests the address of
* the function in the little struct. This is really ugly -PB
*/
-typedef __kernel_caddr_t __sighandler_t;
+typedef char __user *__sighandler_t;
#else
-typedef void (*__sighandler_t)(int);
+typedef void __signalfn_t(int);
+typedef __signalfn_t __user *__sighandler_t;
#endif
typedef struct sigaltstack {
- void *ss_sp;
+ void __user *ss_sp;
int ss_flags;
size_t ss_size;
} stack_t;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 83eef4fde873..266b44fcfaa0 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -219,6 +219,7 @@ enum rq_flag_bits {
__REQ_PM_SHUTDOWN, /* shutdown request */
__REQ_BAR_PREFLUSH, /* barrier pre-flush done */
__REQ_BAR_POSTFLUSH, /* barrier post-flush */
+ __REQ_BAR_FLUSH, /* rq is the flush request */
__REQ_NR_BITS, /* stops here */
};
@@ -246,6 +247,7 @@ enum rq_flag_bits {
#define REQ_PM_SHUTDOWN (1 << __REQ_PM_SHUTDOWN)
#define REQ_BAR_PREFLUSH (1 << __REQ_BAR_PREFLUSH)
#define REQ_BAR_POSTFLUSH (1 << __REQ_BAR_POSTFLUSH)
+#define REQ_BAR_FLUSH (1 << __REQ_BAR_FLUSH)
/*
* State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
index 56fa057bf0d7..70a4ebb5d964 100644
--- a/include/linux/compat_ioctl.h
+++ b/include/linux/compat_ioctl.h
@@ -693,6 +693,9 @@ COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE)
COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO)
COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO)
COMPATIBLE_IOCTL(USBDEVFS_RESET)
+COMPATIBLE_IOCTL(USBDEVFS_SUBMITURB32)
+COMPATIBLE_IOCTL(USBDEVFS_REAPURB32)
+COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32)
COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT)
/* MTD */
COMPATIBLE_IOCTL(MEMGETINFO)
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index 8cf0e3f290bf..ee54f81faad5 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -20,6 +20,7 @@ typedef int (elevator_may_queue_fn) (request_queue_t *, int);
typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, int);
typedef void (elevator_put_req_fn) (request_queue_t *, struct request *);
+typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *);
typedef int (elevator_init_fn) (request_queue_t *, elevator_t *);
typedef void (elevator_exit_fn) (elevator_t *);
@@ -34,6 +35,7 @@ struct elevator_ops
elevator_add_req_fn *elevator_add_req_fn;
elevator_remove_req_fn *elevator_remove_req_fn;
elevator_requeue_req_fn *elevator_requeue_req_fn;
+ elevator_deactivate_req_fn *elevator_deactivate_req_fn;
elevator_queue_empty_fn *elevator_queue_empty_fn;
elevator_completed_req_fn *elevator_completed_req_fn;
@@ -87,6 +89,7 @@ extern void elv_merge_requests(request_queue_t *, struct request *,
extern void elv_merged_request(request_queue_t *, struct request *);
extern void elv_remove_request(request_queue_t *, struct request *);
extern void elv_requeue_request(request_queue_t *, struct request *);
+extern void elv_deactivate_request(request_queue_t *, struct request *);
extern int elv_queue_empty(request_queue_t *);
extern struct request *elv_next_request(struct request_queue *q);
extern struct request *elv_former_request(request_queue_t *, struct request *);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index b65f84ec1118..a0bf80e45aee 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2068,8 +2068,8 @@
#define PCI_VENDOR_ID_TOPSPIN 0x1867
-#define PCI_VENDOR_ID_ARC 0x192E
-#define PCI_DEVICE_ID_ARC_EHCI 0x0101
+#define PCI_VENDOR_ID_TDI 0x192E
+#define PCI_DEVICE_ID_TDI_EHCI 0x0101
#define PCI_VENDOR_ID_SYMPHONY 0x1c1c
#define PCI_DEVICE_ID_SYMPHONY_101 0x0001
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 7dbcc054c7dc..8d2687ae39ff 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -70,6 +70,7 @@ struct usb_host_interface {
*/
struct usb_host_endpoint *endpoint;
+ char *string; /* iInterface string, if present */
unsigned char *extra; /* Extra descriptors */
int extralen;
};
@@ -189,6 +190,8 @@ struct usb_interface_cache {
/**
* struct usb_host_config - representation of a device's configuration
* @desc: the device's configuration descriptor.
+ * @string: pointer to the cached version of the iConfiguration string, if
+ * present for this configuration.
* @interface: array of pointers to usb_interface structures, one for each
* interface in the configuration. The number of interfaces is stored
* in desc.bNumInterfaces. These pointers are valid only while the
@@ -225,6 +228,7 @@ struct usb_interface_cache {
struct usb_host_config {
struct usb_config_descriptor desc;
+ char *string;
/* the interfaces associated with this configuration,
* stored in no particular order */
struct usb_interface *interface[USB_MAXINTERFACES];
@@ -285,6 +289,10 @@ struct usb_bus {
struct class_device class_dev; /* class device for this bus */
void (*release)(struct usb_bus *bus); /* function to destroy this bus's memory */
+#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
+ struct mon_bus *mon_bus; /* non-null when associated */
+ int monitored; /* non-zero when monitored */
+#endif
};
#define to_usb_bus(d) container_of(d, struct usb_bus, class_dev)
@@ -338,6 +346,9 @@ struct usb_device {
int have_langid; /* whether string_langid is valid yet */
int string_langid; /* language ID for strings */
+ char *product;
+ char *manufacturer;
+ char *serial; /* static strings from the device */
struct list_head filelist;
struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */
@@ -986,13 +997,13 @@ extern int usb_reset_configuration(struct usb_device *dev);
extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
/*
- * timeouts, in seconds, used for sending/receiving control messages
+ * timeouts, in milliseconds, used for sending/receiving control messages
* they typically complete within a few frames (msec) after they're issued
* USB identifies 5 second timeouts, maybe more in a few cases, and a few
* slow devices (like some MGE Ellipse UPSes) actually push that limit.
*/
-#define USB_CTRL_GET_TIMEOUT 5
-#define USB_CTRL_SET_TIMEOUT 5
+#define USB_CTRL_GET_TIMEOUT 5000
+#define USB_CTRL_SET_TIMEOUT 5000
/**
diff --git a/include/linux/usb_cdc.h b/include/linux/usb_cdc.h
new file mode 100644
index 000000000000..0b8d9a78a51a
--- /dev/null
+++ b/include/linux/usb_cdc.h
@@ -0,0 +1,162 @@
+/*
+ * USB Communications Device Class (CDC) definitions
+ *
+ * CDC says how to talk to lots of different types of network adapters,
+ * notably ethernet adapters and various modems. It's used mostly with
+ * firmware based USB peripherals.
+ */
+
+#define USB_CDC_SUBCLASS_ACM 2
+#define USB_CDC_SUBCLASS_ETHERNET 6
+
+#define USB_CDC_PROTO_NONE 0
+
+#define USB_CDC_ACM_PROTO_AT_V25TER 1
+#define USB_CDC_ACM_PROTO_AT_PCCA101 2
+#define USB_CDC_ACM_PROTO_AT_PCCA101_WAKE 3
+#define USB_CDC_ACM_PROTO_AT_GSM 4
+#define USB_CDC_ACM_PROTO_AT_3G 5
+#define USB_CDC_ACM_PROTO_AT_CDMA 6
+#define USB_CDC_ACM_PROTO_VENDOR 0xff
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class-Specific descriptors ... there are a couple dozen of them
+ */
+
+#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */
+#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */
+#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */
+#define USB_CDC_UNION_TYPE 0x06 /* union_desc */
+#define USB_CDC_COUNTRY_TYPE 0x07
+#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */
+
+/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
+struct usb_cdc_header_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __le16 bcdCDC;
+} __attribute__ ((packed));
+
+/* "Call Management Descriptor" from CDC spec 5.2.3.2 */
+struct usb_cdc_call_mgmt_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __u8 bmCapabilities;
+#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT 0x01
+#define USB_CDC_CALL_MGMT_CAP_DATA_INTF 0x02
+
+ __u8 bDataInterface;
+} __attribute__ ((packed));
+
+/* "Abstract Control Management Descriptor" from CDC spec 5.2.3.3 */
+struct usb_cdc_acm_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __u8 bmCapabilities;
+} __attribute__ ((packed));
+
+/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */
+struct usb_cdc_union_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __u8 bMasterInterface0;
+ __u8 bSlaveInterface0;
+ /* ... and there could be other slave interfaces */
+} __attribute__ ((packed));
+
+/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
+struct usb_cdc_ether_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __u8 iMACAddress;
+ __le32 bmEthernetStatistics;
+ __le16 wMaxSegmentSize;
+ __le16 wNumberMCFilters;
+ __u8 bNumberPowerFilters;
+} __attribute__ ((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class-Specific Control Requests (6.2)
+ *
+ * section 3.6.2.1 table 4 has the ACM profile, for modems.
+ * section 3.8.2 table 10 has the ethernet profile.
+ *
+ * Microsoft's RNDIS stack for Ethernet is a vendor-specific CDC ACM variant,
+ * heavily dependent on the encapsulated (proprietary) command mechanism.
+ */
+
+#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
+#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
+#define USB_CDC_REQ_SET_LINE_CODING 0x20
+#define USB_CDC_REQ_GET_LINE_CODING 0x21
+#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
+#define USB_CDC_REQ_SEND_BREAK 0x23
+#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40
+#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41
+#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42
+#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43
+#define USB_CDC_GET_ETHERNET_STATISTIC 0x44
+
+/* Line Coding Structure from CDC spec 6.2.13 */
+struct usb_cdc_line_coding {
+ __le32 dwDTERate;
+ __u8 bCharFormat;
+#define USB_CDC_1_STOP_BITS 0
+#define USB_CDC_1_5_STOP_BITS 1
+#define USB_CDC_2_STOP_BITS 2
+
+ __u8 bParityType;
+#define USB_CDC_NO_PARITY 0
+#define USB_CDC_ODD_PARITY 1
+#define USB_CDC_EVEN_PARITY 2
+#define USB_CDC_MARK_PARITY 3
+#define USB_CDC_SPACE_PARITY 4
+
+ __u8 bDataBits;
+} __attribute__ ((packed));
+
+/* table 62; bits in multicast filter */
+#define USB_CDC_PACKET_TYPE_PROMISCUOUS (1 << 0)
+#define USB_CDC_PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */
+#define USB_CDC_PACKET_TYPE_DIRECTED (1 << 2)
+#define USB_CDC_PACKET_TYPE_BROADCAST (1 << 3)
+#define USB_CDC_PACKET_TYPE_MULTICAST (1 << 4) /* filtered */
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Class-Specific Notifications (6.3) sent by interrupt transfers
+ *
+ * section 3.8.2 table 11 of the CDC spec lists Ethernet notifications
+ * section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS
+ * RNDIS also defines its own bit-incompatible notifications
+ */
+
+#define USB_CDC_NOTIFY_NETWORK_CONNECTION 0x00
+#define USB_CDC_NOTIFY_RESPONSE_AVAILABLE 0x01
+#define USB_CDC_NOTIFY_SERIAL_STATE 0x20
+#define USB_CDC_NOTIFY_SPEED_CHANGE 0x2a
+
+struct usb_cdc_notification {
+ __u8 bmRequestType;
+ __u8 bNotificationType;
+ __le16 wValue;
+ __le16 wIndex;
+ __le16 wLength;
+} __attribute__ ((packed));
+
diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
index aed8193eb420..fb57c2217468 100644
--- a/include/linux/usbdevice_fs.h
+++ b/include/linux/usbdevice_fs.h
@@ -32,6 +32,7 @@
#define _LINUX_USBDEVICE_FS_H
#include <linux/types.h>
+#include <linux/compat.h>
/* --------------------------------------------------------------------- */
@@ -123,6 +124,24 @@ struct usbdevfs_hub_portinfo {
char port [127]; /* e.g. port 3 connects to device 27 */
};
+#ifdef CONFIG_COMPAT
+struct usbdevfs_urb32 {
+ unsigned char type;
+ unsigned char endpoint;
+ compat_int_t status;
+ compat_uint_t flags;
+ compat_caddr_t buffer;
+ compat_int_t buffer_length;
+ compat_int_t actual_length;
+ compat_int_t start_frame;
+ compat_int_t number_of_packets;
+ compat_int_t error_count;
+ compat_uint_t signr;
+ compat_caddr_t usercontext; /* unused */
+ struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+};
+#endif
+
#define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer)
#define USBDEVFS_BULK _IOWR('U', 2, struct usbdevfs_bulktransfer)
#define USBDEVFS_RESETEP _IOR('U', 3, unsigned int)
@@ -130,9 +149,12 @@ struct usbdevfs_hub_portinfo {
#define USBDEVFS_SETCONFIGURATION _IOR('U', 5, unsigned int)
#define USBDEVFS_GETDRIVER _IOW('U', 8, struct usbdevfs_getdriver)
#define USBDEVFS_SUBMITURB _IOR('U', 10, struct usbdevfs_urb)
+#define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32)
#define USBDEVFS_DISCARDURB _IO('U', 11)
#define USBDEVFS_REAPURB _IOW('U', 12, void *)
+#define USBDEVFS_REAPURB32 _IOW('U', 12, u32)
#define USBDEVFS_REAPURBNDELAY _IOW('U', 13, void *)
+#define USBDEVFS_REAPURBNDELAY32 _IOW('U', 13, u32)
#define USBDEVFS_DISCSIGNAL _IOR('U', 14, struct usbdevfs_disconnectsignal)
#define USBDEVFS_CLAIMINTERFACE _IOR('U', 15, unsigned int)
#define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int)
@@ -143,5 +165,4 @@ struct usbdevfs_hub_portinfo {
#define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int)
#define USBDEVFS_DISCONNECT _IO('U', 22)
#define USBDEVFS_CONNECT _IO('U', 23)
-
#endif /* _LINUX_USBDEVICE_FS_H */
diff --git a/sound/oss/harmony.c b/sound/oss/harmony.c
index 2f83ac8a4cee..bee9d344cd26 100644
--- a/sound/oss/harmony.c
+++ b/sound/oss/harmony.c
@@ -310,7 +310,7 @@ static int harmony_detect_rate(int *freq)
case 32000: newrate = HARMONY_SR_32KHZ; break;
case 48000: newrate = HARMONY_SR_48KHZ; break;
case 9600: newrate = HARMONY_SR_9KHZ; break;
- case 5125: newrate = HARMONY_SR_5KHZ; break;
+ case 5512: newrate = HARMONY_SR_5KHZ; break;
case 11025: newrate = HARMONY_SR_11KHZ; break;
case 18900: newrate = HARMONY_SR_18KHZ; break;
case 22050: newrate = HARMONY_SR_22KHZ; break;
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index adbf6e37cabe..12c656d3b585 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -368,7 +368,7 @@ snd_harmony_capture_trigger(snd_pcm_substream_t *ss, int cmd)
}
static int
-snd_harmony_set_data_format(harmony_t *h, int fmt)
+snd_harmony_set_data_format(harmony_t *h, int fmt, int force)
{
int o = h->st.format;
int n;
@@ -388,10 +388,10 @@ snd_harmony_set_data_format(harmony_t *h, int fmt)
break;
}
- if (o != n) {
+ if (force || o != n) {
snd_pcm_format_set_silence(fmt, h->sdma.area,
SILENCE_BUFSZ /
- snd_pcm_format_width(fmt));
+ (snd_pcm_format_physical_width(fmt) / 8));
}
return n;
@@ -412,7 +412,7 @@ snd_harmony_playback_prepare(snd_pcm_substream_t *ss)
h->st.playing = 0;
h->st.rate = snd_harmony_rate_bits(rt->rate);
- h->st.format = snd_harmony_set_data_format(h, rt->format);
+ h->st.format = snd_harmony_set_data_format(h, rt->format, 0);
if (rt->channels == 2)
h->st.stereo = HARMONY_SS_STEREO;
@@ -441,7 +441,7 @@ snd_harmony_capture_prepare(snd_pcm_substream_t *ss)
h->st.capturing = 0;
h->st.rate = snd_harmony_rate_bits(rt->rate);
- h->st.format = snd_harmony_set_data_format(h, rt->format);
+ h->st.format = snd_harmony_set_data_format(h, rt->format, 0);
if (rt->channels == 2)
h->st.stereo = HARMONY_SS_STEREO;
@@ -666,6 +666,9 @@ snd_harmony_pcm_init(harmony_t *h)
return err;
}
+ h->st.format = snd_harmony_set_data_format(h,
+ SNDRV_PCM_FORMAT_S16_BE, 1);
+
return 0;
}
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index ccc0069e458d..316db237d1e2 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -305,7 +305,7 @@ static int get_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i
request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, cval->ctrlif | (cval->id << 8),
- buf, val_len, HZ / 10) >= 0) {
+ buf, val_len, 100) >= 0) {
*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
return 0;
}
@@ -343,7 +343,7 @@ static int set_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i
request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
validx, cval->ctrlif | (cval->id << 8),
- buf, val_len, HZ / 10) >= 0)
+ buf, val_len, 100) >= 0)
return 0;
snd_printdd(KERN_ERR "cannot set ctl value: req = 0x%x, wValue = 0x%x, wIndex = 0x%x, type = %d, data = 0x%x/0x%x\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]);
return -EINVAL;
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
index 40ca82a3e6c5..bef9b0c142c4 100644
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -226,7 +226,7 @@ static int snd_usX2Y_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
if (err)
snd_printk("usb_set_interface error \n");
else
- err = usb_bulk_msg(dev, usb_sndbulkpipe(dev, 2), buf, dsp->length, &lret, 6*HZ);
+ err = usb_bulk_msg(dev, usb_sndbulkpipe(dev, 2), buf, dsp->length, &lret, 6000);
kfree(buf);
}
if (err)