Signed-off-by: Andrew Morton --- 25-akpm/CREDITS | 6 25-akpm/Documentation/usb/error-codes.txt | 27 25-akpm/Documentation/usb/sn9c102.txt | 13 25-akpm/MAINTAINERS | 20 25-akpm/drivers/bluetooth/bfusb.c | 8 25-akpm/drivers/char/watchdog/pcwd_usb.c | 2 25-akpm/drivers/media/dvb/b2c2/b2c2-usb-core.c | 10 25-akpm/drivers/media/dvb/cinergyT2/cinergyT2.c | 4 25-akpm/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c | 2 25-akpm/drivers/media/dvb/dibusb/dvb-dibusb.h | 2 25-akpm/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 4 25-akpm/drivers/media/dvb/ttusb-dec/ttusb_dec.c | 8 25-akpm/drivers/media/video/cpia_usb.c | 4 25-akpm/drivers/net/irda/irda-usb.c | 2 25-akpm/drivers/net/irda/stir4200.c | 6 25-akpm/drivers/usb/Kconfig | 2 25-akpm/drivers/usb/Makefile | 2 25-akpm/drivers/usb/atm/speedtch.c | 8 25-akpm/drivers/usb/class/audio.c | 56 25-akpm/drivers/usb/class/cdc-acm.c | 86 25-akpm/drivers/usb/class/cdc-acm.h | 49 25-akpm/drivers/usb/class/usblp.c | 2 25-akpm/drivers/usb/core/config.c | 3 25-akpm/drivers/usb/core/devices.c | 25 25-akpm/drivers/usb/core/devio.c | 260 - 25-akpm/drivers/usb/core/hcd-pci.c | 159 25-akpm/drivers/usb/core/hcd.c | 310 + 25-akpm/drivers/usb/core/hcd.h | 74 25-akpm/drivers/usb/core/hub.c | 124 25-akpm/drivers/usb/core/hub.h | 1 25-akpm/drivers/usb/core/message.c | 73 25-akpm/drivers/usb/core/sysfs.c | 90 25-akpm/drivers/usb/core/usb.c | 5 25-akpm/drivers/usb/gadget/Kconfig | 8 25-akpm/drivers/usb/gadget/dummy_hcd.c | 81 25-akpm/drivers/usb/gadget/ether.c | 250 - 25-akpm/drivers/usb/gadget/gadget_chips.h | 6 25-akpm/drivers/usb/gadget/net2280.c | 25 25-akpm/drivers/usb/gadget/omap_udc.c | 30 25-akpm/drivers/usb/gadget/pxa2xx_udc.c | 1 25-akpm/drivers/usb/gadget/rndis.c | 2 25-akpm/drivers/usb/gadget/serial.c | 157 25-akpm/drivers/usb/gadget/zero.c | 2 25-akpm/drivers/usb/host/Kconfig | 31 25-akpm/drivers/usb/host/ehci-hcd.c | 53 25-akpm/drivers/usb/host/ehci-hub.c | 4 25-akpm/drivers/usb/host/ehci-q.c | 6 25-akpm/drivers/usb/host/ehci-sched.c | 8 25-akpm/drivers/usb/host/ehci.h | 8 25-akpm/drivers/usb/host/ohci-au1xxx.c | 136 25-akpm/drivers/usb/host/ohci-dbg.c | 4 25-akpm/drivers/usb/host/ohci-hcd.c | 47 25-akpm/drivers/usb/host/ohci-lh7a404.c | 138 25-akpm/drivers/usb/host/ohci-omap.c | 177 25-akpm/drivers/usb/host/ohci-ppc-soc.c | 234 + 25-akpm/drivers/usb/host/ohci-pxa27x.c | 127 25-akpm/drivers/usb/host/ohci-q.c | 9 25-akpm/drivers/usb/host/ohci-sa1111.c | 130 25-akpm/drivers/usb/host/ohci.h | 48 25-akpm/drivers/usb/host/sl811-hcd.c | 73 25-akpm/drivers/usb/host/uhci-debug.c | 9 25-akpm/drivers/usb/host/uhci-hcd.c | 1521 ------ 25-akpm/drivers/usb/host/uhci-q.c | 1488 ++++++ 25-akpm/drivers/usb/image/mdc800.c | 42 25-akpm/drivers/usb/input/aiptek.c | 23 25-akpm/drivers/usb/input/ati_remote.c | 38 25-akpm/drivers/usb/input/hid-core.c | 36 25-akpm/drivers/usb/input/mtouchusb.c | 22 25-akpm/drivers/usb/input/powermate.c | 2 25-akpm/drivers/usb/input/touchkitusb.c | 19 25-akpm/drivers/usb/input/usbkbd.c | 20 25-akpm/drivers/usb/input/usbmouse.c | 19 25-akpm/drivers/usb/input/wacom.c | 2 25-akpm/drivers/usb/media/ibmcam.c | 4 25-akpm/drivers/usb/media/konicawc.c | 2 25-akpm/drivers/usb/media/ov511.c | 6 25-akpm/drivers/usb/media/se401.c | 6 25-akpm/drivers/usb/media/sn9c102.h | 8 25-akpm/drivers/usb/media/sn9c102_core.c | 52 25-akpm/drivers/usb/media/ultracam.c | 4 25-akpm/drivers/usb/media/vicam.c | 4 25-akpm/drivers/usb/media/w9968cf.h | 2 25-akpm/drivers/usb/misc/Kconfig | 2 25-akpm/drivers/usb/misc/Makefile | 2 25-akpm/drivers/usb/misc/auerswald.c | 21 25-akpm/drivers/usb/misc/cytherm.c | 2 25-akpm/drivers/usb/misc/idmouse.c | 16 25-akpm/drivers/usb/misc/legousbtower.c | 4 25-akpm/drivers/usb/misc/phidgetkit.c | 29 25-akpm/drivers/usb/misc/phidgetservo.c | 4 25-akpm/drivers/usb/misc/rio500.c | 8 25-akpm/drivers/usb/misc/sisusbvga/Kconfig | 14 25-akpm/drivers/usb/misc/sisusbvga/Makefile | 6 25-akpm/drivers/usb/misc/sisusbvga/sisusb.c | 3144 ++++++++++++++ 25-akpm/drivers/usb/misc/sisusbvga/sisusb.h | 278 + 25-akpm/drivers/usb/misc/usblcd.c | 4 25-akpm/drivers/usb/misc/usbled.c | 2 25-akpm/drivers/usb/misc/usbtest.c | 10 25-akpm/drivers/usb/misc/uss720.c | 12 25-akpm/drivers/usb/mon/Kconfig | 22 25-akpm/drivers/usb/mon/Makefile | 7 25-akpm/drivers/usb/mon/mon_main.c | 377 + 25-akpm/drivers/usb/mon/mon_stat.c | 74 25-akpm/drivers/usb/mon/mon_text.c | 395 + 25-akpm/drivers/usb/mon/usb_mon.h | 51 25-akpm/drivers/usb/net/Kconfig | 21 25-akpm/drivers/usb/net/Makefile | 3 25-akpm/drivers/usb/net/catc.c | 2 25-akpm/drivers/usb/net/kaweth.c | 13 25-akpm/drivers/usb/net/pegasus.c | 61 25-akpm/drivers/usb/net/pegasus.h | 1 25-akpm/drivers/usb/net/rtl8150.c | 4 25-akpm/drivers/usb/net/usbnet.c | 589 ++ 25-akpm/drivers/usb/net/zd1201.c | 1905 ++++++++ 25-akpm/drivers/usb/net/zd1201.h | 147 25-akpm/drivers/usb/serial/belkin_sa.c | 2 25-akpm/drivers/usb/serial/cyberjack.c | 7 25-akpm/drivers/usb/serial/cypress_m8.c | 6 25-akpm/drivers/usb/serial/ezusb.c | 2 25-akpm/drivers/usb/serial/ftdi_sio.c | 5 25-akpm/drivers/usb/serial/ftdi_sio.h | 1 25-akpm/drivers/usb/serial/io_edgeport.c | 49 25-akpm/drivers/usb/serial/io_ti.c | 7 25-akpm/drivers/usb/serial/ipaq.c | 2 25-akpm/drivers/usb/serial/ipw.c | 18 25-akpm/drivers/usb/serial/ir-usb.c | 2 25-akpm/drivers/usb/serial/keyspan_pda.c | 14 25-akpm/drivers/usb/serial/kl5kusb105.c | 2 25-akpm/drivers/usb/serial/mct_u232.c | 2 25-akpm/drivers/usb/serial/ti_usb_3410_5052.c | 6 25-akpm/drivers/usb/serial/visor.c | 4 25-akpm/drivers/usb/serial/whiteheat.c | 5 25-akpm/drivers/usb/storage/Kconfig | 22 25-akpm/drivers/usb/storage/Makefile | 2 25-akpm/drivers/usb/storage/protocol.c | 39 25-akpm/drivers/usb/storage/scsiglue.c | 29 25-akpm/drivers/usb/storage/shuttle_usbat.c | 1258 ++++- 25-akpm/drivers/usb/storage/shuttle_usbat.h | 82 25-akpm/drivers/usb/storage/transport.c | 28 25-akpm/drivers/usb/storage/transport.h | 4 25-akpm/drivers/usb/storage/unusual_devs.h | 82 25-akpm/drivers/usb/storage/usb.c | 48 25-akpm/drivers/usb/storage/usb.h | 6 25-akpm/drivers/usb/usb-skeleton.c | 4 25-akpm/drivers/w1/dscore.c | 10 25-akpm/fs/compat_ioctl.c | 229 - 25-akpm/include/linux/compat_ioctl.h | 3 25-akpm/include/linux/pci_ids.h | 4 25-akpm/include/linux/usb.h | 17 25-akpm/include/linux/usb_cdc.h | 162 25-akpm/include/linux/usbdevice_fs.h | 23 25-akpm/sound/usb/usbmixer.c | 4 25-akpm/sound/usb/usx2y/usX2Yhwdep.c | 2 153 files changed, 11883 insertions(+), 4110 deletions(-) diff -puN CREDITS~bk-usb CREDITS --- 25/CREDITS~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/CREDITS 2005-03-04 00:45:34.000000000 -0800 @@ -842,6 +842,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 -puN Documentation/usb/error-codes.txt~bk-usb Documentation/usb/error-codes.txt --- 25/Documentation/usb/error-codes.txt~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/Documentation/usb/error-codes.txt 2005-03-04 00:45:34.000000000 -0800 @@ -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 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 -puN Documentation/usb/sn9c102.txt~bk-usb Documentation/usb/sn9c102.txt --- 25/Documentation/usb/sn9c102.txt~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/Documentation/usb/sn9c102.txt 2005-03-04 00:45:34.000000000 -0800 @@ -210,8 +210,8 @@ There are other four entries in the dire 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 Corpo 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 -puN drivers/bluetooth/bfusb.c~bk-usb drivers/bluetooth/bfusb.c --- 25/drivers/bluetooth/bfusb.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/bluetooth/bfusb.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 bf 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 bf 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 -puN drivers/char/watchdog/pcwd_usb.c~bk-usb drivers/char/watchdog/pcwd_usb.c --- 25/drivers/char/watchdog/pcwd_usb.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/char/watchdog/pcwd_usb.c 2005-03-04 00:45:34.000000000 -0800 @@ -227,7 +227,7 @@ static int usb_pcwd_send_command(struct 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 -puN drivers/media/dvb/b2c2/b2c2-usb-core.c~bk-usb drivers/media/dvb/b2c2/b2c2-usb-core.c --- 25/drivers/media/dvb/b2c2/b2c2-usb-core.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/media/dvb/b2c2/b2c2-usb-core.c 2005-03-04 00:45:34.000000000 -0800 @@ -194,7 +194,7 @@ static u32 b2c2_usb_read_dw(struct usb_b 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_ 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 wIndex, pbBuffer, buflen, - nWaitTime * HZ); + nWaitTime * 1000); return len == buflen ? 0 : -EIO; } @@ -312,7 +312,7 @@ static int b2c2_usb_i2c_req(struct usb_b wIndex, buf, buflen, - nWaitTime * HZ); + nWaitTime * 1000); return len == buflen ? 0 : -EIO; } @@ -334,7 +334,7 @@ int static b2c2_usb_utility_req(struct u wIndex, pvBuffer, buflen, - nWaitTime * HZ); + nWaitTime * 1000); return len == buflen ? 0 : -EIO; } diff -puN drivers/media/dvb/cinergyT2/cinergyT2.c~bk-usb drivers/media/dvb/cinergyT2/cinergyT2.c --- 25/drivers/media/dvb/cinergyT2/cinergyT2.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/media/dvb/cinergyT2/cinergyT2.c 2005-03-04 00:45:34.000000000 -0800 @@ -212,7 +212,7 @@ static int cinergyt2_command (struct cin 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 cin 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 -puN drivers/media/dvb/dibusb/dvb-dibusb-firmware.c~bk-usb drivers/media/dvb/dibusb/dvb-dibusb-firmware.c --- 25/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/media/dvb/dibusb/dvb-dibusb.h~bk-usb drivers/media/dvb/dibusb/dvb-dibusb.h --- 25/drivers/media/dvb/dibusb/dvb-dibusb.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/media/dvb/dibusb/dvb-dibusb.h 2005-03-04 00:45:34.000000000 -0800 @@ -236,7 +236,7 @@ void dibusb_pid_list_exit(struct usb_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 -puN drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c~bk-usb drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c --- 25/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/media/dvb/ttusb-dec/ttusb_dec.c~bk-usb drivers/media/dvb/ttusb-dec/ttusb_dec.c --- 25/drivers/media/dvb/ttusb-dec/ttusb_dec.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2005-03-04 00:45:34.000000000 -0800 @@ -208,7 +208,7 @@ static int ttusb_dec_send_command(struct } 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 } 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 ttu 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 -puN drivers/media/video/cpia_usb.c~bk-usb drivers/media/video/cpia_usb.c --- 25/drivers/media/video/cpia_usb.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/media/video/cpia_usb.c 2005-03-04 00:45:34.000000000 -0800 @@ -308,7 +308,7 @@ static int WritePacket(struct usb_device 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 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 -puN drivers/net/irda/irda-usb.c~bk-usb drivers/net/irda/irda-usb.c --- 25/drivers/net/irda/irda-usb.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/net/irda/irda-usb.c 2005-03-04 00:45:34.000000000 -0800 @@ -1308,7 +1308,7 @@ static inline struct irda_class_desc *ir 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 -puN drivers/net/irda/stir4200.c~bk-usb drivers/net/irda/stir4200.c --- 25/drivers/net/irda/stir4200.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/net/irda/stir4200.c 2005-03-04 00:45:34.000000000 -0800 @@ -208,7 +208,7 @@ static int write_reg(struct stir_cb *sti 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_c 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 *st 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 -puN drivers/usb/atm/speedtch.c~bk-usb drivers/usb/atm/speedtch.c --- 25/drivers/usb/atm/speedtch.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/atm/speedtch.c 2005-03-04 00:45:34.000000000 -0800 @@ -58,8 +58,8 @@ static const char speedtch_driver_name[] #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(str /* 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 /* 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 -puN drivers/usb/class/audio.c~bk-usb drivers/usb/class/audio.c --- 25/drivers/usb/class/audio.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/class/audio.c 2005-03-04 00:45:34.000000000 -0800 @@ -1561,7 +1561,7 @@ static int set_format_in(struct usb_audi 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_audi 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_aud 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_aud 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 * 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 * 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 * 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 * 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_mixerd 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_mixerd 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_mixerd 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 consmixstat 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 consmixstat 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 consmixstat /* 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 consmixstat 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 consmixstat 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 consmixstat 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 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 -puN drivers/usb/class/cdc-acm.c~bk-usb drivers/usb/class/cdc-acm.c --- 25/drivers/usb/class/cdc-acm.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/class/cdc-acm.c 2005-03-04 00:45:34.000000000 -0800 @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -89,7 +90,7 @@ static int acm_ctrl_msg(struct acm *acm, 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, /* 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, 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 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 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 t { 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 t 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_interfa } 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) }, + { 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/2/0xff is likely MSFT RNDIS ... NOT a modem!! */ + /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */ { } }; diff -puN drivers/usb/class/cdc-acm.h~bk-usb drivers/usb/class/cdc-acm.h --- 25/drivers/usb/class/cdc-acm.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/class/cdc-acm.h 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/class/usblp.c~bk-usb drivers/usb/class/usblp.c --- 25/drivers/usb/class/usblp.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/class/usblp.c 2005-03-04 00:45:34.000000000 -0800 @@ -114,7 +114,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD #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 -puN drivers/usb/core/config.c~bk-usb drivers/usb/core/config.c --- 25/drivers/usb/core/config.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/core/config.c 2005-03-04 00:45:34.000000000 -0800 @@ -420,6 +420,9 @@ void usb_destroy_configuration(struct us 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 -puN drivers/usb/core/devices.c~bk-usb drivers/usb/core/devices.c --- 25/drivers/usb/core/devices.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/core/devices.c 2005-03-04 00:45:34.000000000 -0800 @@ -362,33 +362,21 @@ static char *usb_dump_device_descriptor( */ 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(stru /* 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 -puN drivers/usb/core/devio.c~bk-usb drivers/usb/core/devio.c --- 25/drivers/usb/core/devio.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/core/devio.c 2005-03-04 00:45:34.000000000 -0800 @@ -565,7 +565,7 @@ static int proc_control(struct dev_state 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 *p 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 *p 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_sta 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_sta 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_sta 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_sta 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_sta 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_sta 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_sta 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_sta 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_sta 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_sta 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 } 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 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 *in 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 -puN drivers/usb/core/hcd.c~bk-usb drivers/usb/core/hcd.c --- 25/drivers/usb/core/hcd.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/core/hcd.c 2005-03-04 00:45:34.000000000 -0800 @@ -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, *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_h { 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_h 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_h 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_h 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_h 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_h 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 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 *u 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 *u // 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 *u 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 *u * 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_ope */ 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_hc : 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 /** * 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 * * 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 -puN drivers/usb/core/hcd.h~bk-usb drivers/usb/core/hcd.h --- 25/drivers/usb/core/hcd.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/core/hcd.h 2005-03-04 00:45:34.000000000 -0800 @@ -63,6 +63,7 @@ struct usb_hcd { /* usb_bus.hcpriv point 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 point 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 -puN drivers/usb/core/hcd-pci.c~bk-usb drivers/usb/core/hcd-pci.c --- 25/drivers/usb/core/hcd-pci.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/core/hcd-pci.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 *d "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; - } - 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; + goto err1; } } - // 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 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 -puN drivers/usb/core/hub.c~bk-usb drivers/usb/core/hub.c --- 25/drivers/usb/core/hub.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/core/hub.c 2005-03-04 00:45:34.000000000 -0800 @@ -74,7 +74,7 @@ module_param(old_scheme_first, bool, S_I 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 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 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 { 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_d { 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_dev 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_de 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 * { 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 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 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->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 u } #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 *ud 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 *ud 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 *ud */ 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_h * 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_dev /** * 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 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_devi 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_interfa } 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_de 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, stru 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, stru 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 * 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 -puN drivers/usb/core/hub.h~bk-usb drivers/usb/core/hub.h --- 25/drivers/usb/core/hub.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/core/hub.h 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/core/message.c~bk-usb drivers/usb/core/message.c --- 25/drivers/usb/core/message.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/core/message.c 2005-03-04 00:45:34.000000000 -0800 @@ -55,7 +55,7 @@ static int usb_start_wait_urb(struct urb 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 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_ * @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 *d * @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_ 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 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 *de 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 *de 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 *de 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_devic 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 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 /* 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_d 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 -puN drivers/usb/core/sysfs.c~bk-usb drivers/usb/core/sysfs.c --- 25/drivers/usb/core/sysfs.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/core/sysfs.c 2005-03-04 00:45:34.000000000 -0800 @@ -46,27 +46,24 @@ usb_actconfig_attr (bNumInterfaces, 1, " 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, 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 devic } \ 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 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); +static ssize_t show_interface_string(struct device *dev, char *buf) +{ + struct usb_interface *intf; + struct usb_device *udev; + int len; -usb_intf_str (interface, iInterface); + 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 { 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 { 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 -puN drivers/usb/core/usb.c~bk-usb drivers/usb/core/usb.c --- 25/drivers/usb/core/usb.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/core/usb.c 2005-03-04 00:45:34.000000000 -0800 @@ -647,7 +647,10 @@ static void usb_release_dev(struct devic usb_destroy_configuration(udev); usb_bus_put(udev->bus); - kfree (udev); + kfree(udev->product); + kfree(udev->manufacturer); + kfree(udev->serial); + kfree(udev); } /** diff -puN drivers/usb/gadget/dummy_hcd.c~bk-usb drivers/usb/gadget/dummy_hcd.c --- 25/drivers/usb/gadget/dummy_hcd.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/gadget/dummy_hcd.c 2005-03-04 00:45:34.000000000 -0800 @@ -4,7 +4,7 @@ * Maintainer: Alan Stern * * 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 * * 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 * /* ...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 * 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 -puN drivers/usb/gadget/ether.c~bk-usb drivers/usb/gadget/ether.c --- 25/drivers/usb/gadget/ether.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/gadget/ether.c 2005-03-04 00:45:34.000000000 -0800 @@ -49,6 +49,7 @@ #include #include +#include #include #include @@ -259,6 +260,9 @@ MODULE_PARM_DESC(host_addr, "Host Ethern #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_des #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, uns /*-------------------------------------------------------------------------*/ -/* 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 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 u 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 (str "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 (stru 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, co 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, co 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, co #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, co 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, co } #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, co 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, co * 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 u #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_buf 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 } /* 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 -puN drivers/usb/gadget/gadget_chips.h~bk-usb drivers/usb/gadget/gadget_chips.h --- 25/drivers/usb/gadget/gadget_chips.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/gadget/gadget_chips.h 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/gadget/Kconfig~bk-usb drivers/usb/gadget/Kconfig --- 25/drivers/usb/gadget/Kconfig~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/gadget/Kconfig 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/gadget/net2280.c~bk-usb drivers/usb/gadget/net2280.c --- 25/drivers/usb/gadget/net2280.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/gadget/net2280.c 2005-03-04 00:45:34.000000000 -0800 @@ -1,8 +1,9 @@ /* - * Driver for the NetChip 2280 USB device controller. - * Specs and errata are available from . + * Driver for the PLX NET2280 USB device controller. + * Specs and errata are available from . * - * 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 -#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 ne 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 -puN drivers/usb/gadget/omap_udc.c~bk-usb drivers/usb/gadget/omap_udc.c --- 25/drivers/usb/gadget/omap_udc.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/gadget/omap_udc.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 u 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 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 } } -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 -puN drivers/usb/gadget/pxa2xx_udc.c~bk-usb drivers/usb/gadget/pxa2xx_udc.c --- 25/drivers/usb/gadget/pxa2xx_udc.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/gadget/pxa2xx_udc.c 2005-03-04 00:45:34.000000000 -0800 @@ -943,6 +943,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, stru 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 -puN drivers/usb/gadget/rndis.c~bk-usb drivers/usb/gadget/rndis.c --- 25/drivers/usb/gadget/rndis.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/gadget/rndis.c 2005-03-04 00:45:34.000000000 -0800 @@ -730,7 +730,7 @@ static int gen_ndis_set_resp (u8 configN /* 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 -puN drivers/usb/gadget/serial.c~bk-usb drivers/usb/gadget/serial.c --- 25/drivers/usb/gadget/serial.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/gadget/serial.c 2005-03-04 00:45:34.000000000 -0800 @@ -45,6 +45,7 @@ #include #include +#include #include #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_descri .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_descri 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 *ga } 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 *g 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 *g 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_ 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_ 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_ #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_ 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_ 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_ 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_gad 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_gad 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_gad 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 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 } spin_unlock_irqrestore(&port->port_lock, flags); } else { + spin_unlock_irqrestore(&port->port_lock, flags); kfree(port); } diff -puN drivers/usb/gadget/zero.c~bk-usb drivers/usb/gadget/zero.c --- 25/drivers/usb/gadget/zero.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/gadget/zero.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/host/ehci.h~bk-usb drivers/usb/host/ehci.h --- 25/drivers/usb/host/ehci.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ehci.h 2005-03-04 00:45:34.000000000 -0800 @@ -82,7 +82,7 @@ struct ehci_hcd { /* one per controlle 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, u #else -#define ehci_is_ARC(e) (0) +#define ehci_is_TDI(e) (0) #define ehci_port_speed(ehci, portsc) (1<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 * 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 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 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 *h /* 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 -puN drivers/usb/host/ehci-hub.c~bk-usb drivers/usb/host/ehci-hub.c --- 25/drivers/usb/host/ehci-hub.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ehci-hub.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/host/ehci-q.c~bk-usb drivers/usb/host/ehci-q.c --- 25/drivers/usb/host/ehci-q.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ehci-q.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/host/ehci-sched.c~bk-usb drivers/usb/host/ehci-sched.c --- 25/drivers/usb/host/ehci-sched.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ehci-sched.c 2005-03-04 00:45:34.000000000 -0800 @@ -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, /* 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 -puN drivers/usb/host/Kconfig~bk-usb drivers/usb/host/Kconfig --- 25/drivers/usb/host/Kconfig~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/Kconfig 2005-03-04 00:45:34.000000000 -0800 @@ -47,7 +47,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" @@ -66,6 +66,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 -puN drivers/usb/host/ohci-au1xxx.c~bk-usb drivers/usb/host/ohci-au1xxx.c --- 25/drivers/usb/host/ohci-au1xxx.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ohci-au1xxx.c 2005-03-04 00:45:34.000000000 -0800 @@ -70,19 +70,6 @@ static void au1xxx_stop_hc(struct platfo /*-------------------------------------------------------------------------*/ - -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_h * */ 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 h */ 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_au1xx * 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_au1xx 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(str 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(st struct usb_hcd *hcd = dev_get_drvdata(dev); usb_hcd_au1xxx_remove(hcd, pdev); - dev_set_drvdata(dev, NULL); return 0; } /*TBD*/ diff -puN drivers/usb/host/ohci-dbg.c~bk-usb drivers/usb/host/ohci-dbg.c --- 25/drivers/usb/host/ohci-dbg.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ohci-dbg.c 2005-03-04 00:45:34.000000000 -0800 @@ -138,7 +138,7 @@ ohci_dump_status (struct ohci_hcd *contr 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, ®s->control); ohci_dbg_sw (controller, next, size, @@ -328,7 +328,7 @@ static void ohci_dump_td (const struct o 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 -puN drivers/usb/host/ohci.h~bk-usb drivers/usb/host/ohci.h --- 25/drivers/usb/host/ohci.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ohci.h 2005-03-04 00:45:34.000000000 -0800 @@ -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 ) to access these fields!! @@ -554,6 +554,44 @@ static inline u32 hc32_to_cpup (const st /*-------------------------------------------------------------------------*/ +/* 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 -puN drivers/usb/host/ohci-hcd.c~bk-usb drivers/usb/host/ohci-hcd.c --- 25/drivers/usb/host/ohci-hcd.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ohci-hcd.c 2005-03-04 00:45:34.000000000 -0800 @@ -148,10 +148,22 @@ static void ohci_stop (struct usb_hcd *h #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 *oh // 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_ /* interrupt for some other device? */ } else if ((ints &= ohci_readl (ohci, ®s->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 -puN drivers/usb/host/ohci-lh7a404.c~bk-usb drivers/usb/host/ohci-lh7a404.c --- 25/drivers/usb/host/ohci-lh7a404.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ohci-lh7a404.c 2005-03-04 00:45:34.000000000 -0800 @@ -53,19 +53,6 @@ static void lh7a404_stop_hc(struct platf /*-------------------------------------------------------------------------*/ - -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_ * */ 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 */ 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_lh7a4 * 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_lh7a4 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(st 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(s struct usb_hcd *hcd = dev_get_drvdata(dev); usb_hcd_lh7a404_remove(hcd, pdev); - dev_set_drvdata(dev, NULL); return 0; } /*TBD*/ diff -puN drivers/usb/host/ohci-omap.c~bk-usb drivers/usb/host/ohci-omap.c --- 25/drivers/usb/host/ohci-omap.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ohci-omap.c 2005-03-04 00:45:34.000000000 -0800 @@ -33,11 +33,27 @@ #error "This file is OMAP bus glue. CONFIG_OMAP must be defined." #endif +#ifdef CONFIG_TPS65010 +#include +#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(i 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 { 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 } #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 /*-------------------------------------------------------------------------*/ -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_ 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_ 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_ */ 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_ * 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(stru (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 devi 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 devic 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 -puN /dev/null drivers/usb/host/ohci-ppc-soc.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/host/ohci-ppc-soc.c 2005-03-04 00:45:34.000000000 -0800 @@ -0,0 +1,234 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * (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 from ohci-sa1111.c + * + * This file is licenced under the GPL. + */ + +#include + +/* 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 -puN drivers/usb/host/ohci-pxa27x.c~bk-usb drivers/usb/host/ohci-pxa27x.c --- 25/drivers/usb/host/ohci-pxa27x.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ohci-pxa27x.c 2005-03-04 00:45:34.000000000 -0800 @@ -152,8 +152,6 @@ static void pxa27x_stop_hc(struct platfo /*-------------------------------------------------------------------------*/ -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_h * */ 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 h 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 h */ 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_pxa27 * 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_pxa27 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(str 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(st struct usb_hcd *hcd = dev_get_drvdata(dev); usb_hcd_pxa27x_remove(hcd, pdev); - dev_set_drvdata(dev, NULL); return 0; } diff -puN drivers/usb/host/ohci-q.c~bk-usb drivers/usb/host/ohci-q.c --- 25/drivers/usb/host/ohci-q.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ohci-q.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 *oh /* 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 -puN drivers/usb/host/ohci-sa1111.c~bk-usb drivers/usb/host/ohci-sa1111.c --- 25/drivers/usb/host/ohci-sa1111.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/ohci-sa1111.c 2005-03-04 00:45:34.000000000 -0800 @@ -105,34 +105,8 @@ static void dump_hci_status(struct usb_h } #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_h * 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 h */ 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_sa111 * 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_sa111 .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_sa111 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(st struct usb_hcd *hcd = sa1111_get_drvdata(dev); usb_hcd_sa1111_remove(hcd, dev); - - sa1111_set_drvdata(dev, NULL); - return 0; } diff -puN drivers/usb/host/sl811-hcd.c~bk-usb drivers/usb/host/sl811-hcd.c --- 25/drivers/usb/host/sl811-hcd.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/sl811-hcd.c 2005-03-04 00:45:34.000000000 -0800 @@ -90,8 +90,6 @@ static const char hcd_name[] = "sl811-hc /*-------------------------------------------------------------------------*/ -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 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 *h */ 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 s 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 ph * 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 -puN drivers/usb/host/uhci-debug.c~bk-usb drivers/usb/host/uhci-debug.c --- 25/drivers/usb/host/uhci-debug.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/uhci-debug.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 u #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 .read = uhci_debug_read, .release = uhci_debug_release, }; + +#else /* CONFIG_DEBUG_FS */ + +#define uhci_debug_operations (* (struct file_operations *) NULL) + #endif diff -puN drivers/usb/host/uhci-hcd.c~bk-usb drivers/usb/host/uhci-hcd.c --- 25/drivers/usb/host/uhci-hcd.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/host/uhci-hcd.c 2005-03-04 00:45:34.000000000 -0800 @@ -87,1448 +87,23 @@ 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 */ -#define IDLE_TIMEOUT msecs_to_jiffies(50) -#define FSBR_DELAY msecs_to_jiffies(50) - -/* When we timeout an idle transfer for FSBR, we'll switch it over to */ -/* depth first traversal. We'll do it in groups of this number of TD's */ -/* 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 - * - * is (td_status(td) & 0xF60000), a.k.a. - * uhci_status_bits(td_status(td)). - * Note: does not include the TD_CTRL_NAK bit. - * 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 - */ +static kmem_cache_t *uhci_up_cachep; /* urb_priv */ - 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; +static unsigned int uhci_get_current_frame_number(struct uhci_hcd *uhci); +static void hc_state_transitions(struct uhci_hcd *uhci); - count++; - } +/* If a transfer is still active after this much time, turn off FSBR */ +#define IDLE_TIMEOUT msecs_to_jiffies(50) +#define FSBR_DELAY msecs_to_jiffies(50) - return 0; -} +/* When we timeout an idle transfer for FSBR, we'll switch it over to */ +/* depth first traversal. We'll do it in groups of this number of TD's */ +/* to make sure it doesn't hog all of the bandwidth */ +#define DEPTH_INTERVAL 5 -/* - * 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_h 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 } } +/* + * 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 *uhc } /* - * 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 *hc { 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 *hc 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 -puN /dev/null drivers/usb/host/uhci-q.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/host/uhci-q.c 2005-03-04 00:45:34.000000000 -0800 @@ -0,0 +1,1488 @@ +/* + * Universal Host Controller Interface driver for USB. + * + * Maintainer: Alan Stern + * + * (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 + * + * is (td_status(td) & 0xF60000), a.k.a. + * uhci_status_bits(td_status(td)). + * Note: does not include the TD_CTRL_NAK bit. + * 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 -puN drivers/usb/image/mdc800.c~bk-usb drivers/usb/image/mdc800.c --- 25/drivers/usb/image/mdc800.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/image/mdc800.c 2005-03-04 00:45:34.000000000 -0800 @@ -95,6 +95,7 @@ #include #include #include +#include #include #include @@ -330,7 +331,7 @@ static void mdc800_usb_irq (struct urb * { 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 * */ 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 (str 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 ( 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 (struc { 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 (struc 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 (struc 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 (stru 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 (stru 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 -puN drivers/usb/input/aiptek.c~bk-usb drivers/usb/input/aiptek.c --- 25/drivers/usb/input/aiptek.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/input/aiptek.c 2005-03-04 00:45:34.000000000 -0800 @@ -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(s 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 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, */ 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 -puN drivers/usb/input/ati_remote.c~bk-usb drivers/usb/input/ati_remote.c --- 25/drivers/usb/input/ati_remote.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/input/ati_remote.c 2005-03-04 00:45:34.000000000 -0800 @@ -94,6 +94,7 @@ #include #include #include +#include /* * Module and Version Information, Module Parameters @@ -384,8 +385,6 @@ static void ati_remote_irq_out(struct ur */ 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 */ @@ -403,18 +402,10 @@ static int ati_remote_sendpacket(struct 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; @@ -715,7 +706,6 @@ static int ati_remote_probe(struct usb_i 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))) @@ -749,8 +739,6 @@ static int ati_remote_probe(struct usb_i 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, @@ -773,14 +761,11 @@ static int ati_remote_probe(struct usb_i 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->descriptor.iProduct && - (usb_string(udev, udev->descriptor.iProduct, buf, NAME_BUFSIZE) > 0)) - sprintf(ati_remote->name, "%s %s", ati_remote->name, buf); + if (udev->manufacturer) + strcat(ati_remote->name, udev->manufacturer); + + 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)", @@ -802,9 +787,6 @@ static int ati_remote_probe(struct usb_i usb_set_intfdata(interface, ati_remote); error: - if (buf) - kfree(buf); - if (retval) ati_remote_delete(ati_remote); diff -puN drivers/usb/input/hid-core.c~bk-usb drivers/usb/input/hid-core.c --- 25/drivers/usb/input/hid-core.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/input/hid-core.c 2005-03-04 00:45:58.000000000 -0800 @@ -24,6 +24,7 @@ #include #include #include +#include #undef DEBUG #undef DEBUG_DATA @@ -1223,22 +1224,9 @@ void hid_submit_report(struct hid_device 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; } @@ -1256,7 +1244,7 @@ static int hid_get_class_descriptor(stru 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; @@ -1317,7 +1305,7 @@ void hid_init_reports(struct hid_device usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0), HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, - hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); + hid->ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT); } #define USB_VENDOR_ID_WACOM 0x056a @@ -1675,12 +1663,12 @@ static struct hid_device *usb_hid_config 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 -puN drivers/usb/input/mtouchusb.c~bk-usb drivers/usb/input/mtouchusb.c --- 25/drivers/usb/input/mtouchusb.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/input/mtouchusb.c 2005-03-04 00:45:34.000000000 -0800 @@ -206,7 +206,6 @@ static int mtouchusb_probe(struct usb_in struct usb_endpoint_descriptor *endpoint; struct usb_device *udev = interface_to_usbdev (intf); char path[64]; - char *buf; int nRet; dbg("%s - called", __FUNCTION__); @@ -263,24 +262,15 @@ static int mtouchusb_probe(struct usb_in 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, @@ -289,7 +279,7 @@ static int mtouchusb_probe(struct usb_in 0, NULL, 0, - HZ * USB_CTRL_SET_TIMEOUT); + USB_CTRL_SET_TIMEOUT); dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d", __FUNCTION__, nRet); @@ -323,7 +313,7 @@ static int mtouchusb_probe(struct usb_in 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 -puN drivers/usb/input/powermate.c~bk-usb drivers/usb/input/powermate.c --- 25/drivers/usb/input/powermate.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/input/powermate.c 2005-03-04 00:45:34.000000000 -0800 @@ -320,7 +320,7 @@ static int powermate_probe(struct usb_in 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 -puN drivers/usb/input/touchkitusb.c~bk-usb drivers/usb/input/touchkitusb.c --- 25/drivers/usb/input/touchkitusb.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/input/touchkitusb.c 2005-03-04 00:45:34.000000000 -0800 @@ -184,7 +184,6 @@ static int touchkit_probe(struct usb_int 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_int 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 -puN drivers/usb/input/usbkbd.c~bk-usb drivers/usb/input/usbkbd.c --- 25/drivers/usb/input/usbkbd.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/input/usbkbd.c 2005-03-04 00:45:34.000000000 -0800 @@ -238,7 +238,6 @@ static int usb_kbd_probe(struct usb_inte 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_inte 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 -puN drivers/usb/input/usbmouse.c~bk-usb drivers/usb/input/usbmouse.c --- 25/drivers/usb/input/usbmouse.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/input/usbmouse.c 2005-03-04 00:45:34.000000000 -0800 @@ -129,7 +129,6 @@ static int usb_mouse_probe(struct usb_in 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_in 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 -puN drivers/usb/input/wacom.c~bk-usb drivers/usb/input/wacom.c --- 25/drivers/usb/input/wacom.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/input/wacom.c 2005-03-04 00:45:34.000000000 -0800 @@ -115,7 +115,7 @@ static int usb_set_report(struct usb_int 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 -puN drivers/usb/Kconfig~bk-usb drivers/usb/Kconfig --- 25/drivers/usb/Kconfig~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/Kconfig 2005-03-04 00:45:34.000000000 -0800 @@ -74,6 +74,8 @@ source "drivers/usb/media/Kconfig" source "drivers/usb/net/Kconfig" +source "drivers/usb/mon/Kconfig" + comment "USB port drivers" depends on USB diff -puN drivers/usb/Makefile~bk-usb drivers/usb/Makefile --- 25/drivers/usb/Makefile~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/Makefile 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/media/ibmcam.c~bk-usb drivers/usb/media/ibmcam.c --- 25/drivers/usb/media/ibmcam.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/media/ibmcam.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/media/konicawc.c~bk-usb drivers/usb/media/konicawc.c --- 25/drivers/usb/media/konicawc.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/media/konicawc.c 2005-03-04 00:45:34.000000000 -0800 @@ -133,7 +133,7 @@ static int konicawc_ctrl_msg(struct uvd { 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 -puN drivers/usb/media/ov511.c~bk-usb drivers/usb/media/ov511.c --- 25/drivers/usb/media/ov511.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/media/ov511.c 2005-03-04 00:45:34.000000000 -0800 @@ -383,7 +383,7 @@ reg_w(struct usb_ov511 *ov, unsigned cha 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 cha 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, unsi 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 -puN drivers/usb/media/se401.c~bk-usb drivers/usb/media/se401.c --- 25/drivers/usb/media/se401.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/media/se401.c 2005-03-04 00:45:34.000000000 -0800 @@ -122,7 +122,7 @@ static int se401_sndctrl(int set, struct 0, cp, size, - HZ + 1000 ); } @@ -142,7 +142,7 @@ static int se401_set_feature(struct usb_ selector, NULL, 0, - HZ + 1000 ); } @@ -162,7 +162,7 @@ static unsigned short se401_get_feature( selector, cp, 2, - HZ + 1000 ); return cp[0]+cp[1]*256; } diff -puN drivers/usb/media/sn9c102_core.c~bk-usb drivers/usb/media/sn9c102_core.c --- 25/drivers/usb/media/sn9c102_core.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/media/sn9c102_core.c 2005-03-04 00:45:34.000000000 -0800 @@ -164,8 +164,8 @@ sn9c102_request_buffers(struct sn9c102_d 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 { 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 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 (*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 __u 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 __u 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 } 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* fil } -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 ino 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 ino 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 ino 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 ino 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 ino 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* i 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 -puN drivers/usb/media/sn9c102.h~bk-usb drivers/usb/media/sn9c102.h --- 25/drivers/usb/media/sn9c102.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/media/sn9c102.h 2005-03-04 00:45:34.000000000 -0800 @@ -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 "" #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 -puN drivers/usb/media/ultracam.c~bk-usb drivers/usb/media/ultracam.c --- 25/drivers/usb/media/ultracam.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/media/ultracam.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/media/vicam.c~bk-usb drivers/usb/media/vicam.c --- 25/drivers/usb/media/vicam.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/media/vicam.c 2005-03-04 00:45:34.000000000 -0800 @@ -441,7 +441,7 @@ static int __send_control_msg(struct vic 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 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 -puN drivers/usb/media/w9968cf.h~bk-usb drivers/usb/media/w9968cf.h --- 25/drivers/usb/media/w9968cf.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/media/w9968cf.h 2005-03-04 00:45:34.000000000 -0800 @@ -65,7 +65,7 @@ static const u16 wMaxPacketSize[] = {102 #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 -puN drivers/usb/misc/auerswald.c~bk-usb drivers/usb/misc/auerswald.c --- 25/drivers/usb/misc/auerswald.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/auerswald.c 2005-03-04 00:45:34.000000000 -0800 @@ -29,6 +29,7 @@ #include #include #include +#include #undef DEBUG /* include debug macros until it's done */ #include @@ -605,7 +606,6 @@ static void auerchain_blocking_completio /* 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 (pau 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_i 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 -puN drivers/usb/misc/cytherm.c~bk-usb drivers/usb/misc/cytherm.c --- 25/drivers/usb/misc/cytherm.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/cytherm.c 2005-03-04 00:45:34.000000000 -0800 @@ -77,7 +77,7 @@ static int vendor_command(struct usb_dev USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, value, index, buf, size, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); } diff -puN drivers/usb/misc/idmouse.c~bk-usb drivers/usb/misc/idmouse.c --- 25/drivers/usb/misc/idmouse.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/idmouse.c 2005-03-04 00:45:34.000000000 -0800 @@ -124,28 +124,28 @@ static int idmouse_create_image(struct u 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 u 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 u /* 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 -puN drivers/usb/misc/Kconfig~bk-usb drivers/usb/misc/Kconfig --- 25/drivers/usb/misc/Kconfig~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/Kconfig 2005-03-04 00:45:34.000000000 -0800 @@ -137,6 +137,8 @@ config USB_IDMOUSE See also . +source "drivers/usb/misc/sisusbvga/Kconfig" + config USB_TEST tristate "USB testing driver (DEVELOPMENT)" depends on USB && USB_DEVICEFS && EXPERIMENTAL diff -puN drivers/usb/misc/legousbtower.c~bk-usb drivers/usb/misc/legousbtower.c --- 25/drivers/usb/misc/legousbtower.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/legousbtower.c 2005-03-04 00:45:34.000000000 -0800 @@ -391,7 +391,7 @@ static int tower_open (struct inode *ino 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_inter 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 -puN drivers/usb/misc/Makefile~bk-usb drivers/usb/misc/Makefile --- 25/drivers/usb/misc/Makefile~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/Makefile 2005-03-04 00:45:34.000000000 -0800 @@ -16,3 +16,5 @@ obj-$(CONFIG_USB_PHIDGETSERVO) += phidge 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 -puN drivers/usb/misc/phidgetkit.c~bk-usb drivers/usb/misc/phidgetkit.c --- 25/drivers/usb/misc/phidgetkit.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/phidgetkit.c 2005-03-04 00:45:34.000000000 -0800 @@ -103,14 +103,15 @@ static int change_outputs(struct phidget } } - 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_ 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 devi 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 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 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 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(stru 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(stru 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 -puN drivers/usb/misc/phidgetservo.c~bk-usb drivers/usb/misc/phidgetservo.c --- 25/drivers/usb/misc/phidgetservo.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/phidgetservo.c 2005-03-04 00:45:34.000000000 -0800 @@ -148,7 +148,7 @@ change_position_v30(struct phidget_servo 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 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 -puN drivers/usb/misc/rio500.c~bk-usb drivers/usb/misc/rio500.c --- 25/drivers/usb/misc/rio500.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/rio500.c 2005-03-04 00:45:34.000000000 -0800 @@ -166,7 +166,7 @@ ioctl_rio(struct inode *inode, struct fi 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 fi 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 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 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 -puN /dev/null drivers/usb/misc/sisusbvga/Kconfig --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/misc/sisusbvga/Kconfig 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN /dev/null drivers/usb/misc/sisusbvga/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/misc/sisusbvga/Makefile 2005-03-04 00:45:34.000000000 -0800 @@ -0,0 +1,6 @@ +# +# Makefile for the sisusb driver (if driver is inside kernel tree). +# + +obj-$(CONFIG_USB_SISUSBVGA) += sisusb.o + diff -puN /dev/null drivers/usb/misc/sisusbvga/sisusb.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/misc/sisusbvga/sisusb.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("sisusb - Driver for Net2280/SiS315-based USB2VGA dongles"); +MODULE_LICENSE("GPL"); + diff -puN /dev/null drivers/usb/misc/sisusbvga/sisusb.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/misc/sisusbvga/sisusb.h 2005-03-04 00:45:34.000000000 -0800 @@ -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 + * + */ + +#ifndef _SISUSB_H_ +#define _SISUSB_H_ + +#ifdef CONFIG_COMPAT +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10) +#include +#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 -puN drivers/usb/misc/usblcd.c~bk-usb drivers/usb/misc/usblcd.c --- 25/drivers/usb/misc/usblcd.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/usblcd.c 2005-03-04 00:45:34.000000000 -0800 @@ -144,7 +144,7 @@ write_lcd(struct file *file, const char 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 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 -puN drivers/usb/misc/usbled.c~bk-usb drivers/usb/misc/usbled.c --- 25/drivers/usb/misc/usbled.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/usbled.c 2005-03-04 00:45:34.000000000 -0800 @@ -74,7 +74,7 @@ static void change_color(struct usb_led (0x00 * 0x100) + color, buffer, 8, - 2 * HZ); + 2000); if (retval) dev_dbg(&led->udev->dev, "retval = %d\n", retval); kfree(buffer); diff -puN drivers/usb/misc/usbtest.c~bk-usb drivers/usb/misc/usbtest.c --- 25/drivers/usb/misc/usbtest.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/usbtest.c 2005-03-04 00:45:34.000000000 -0800 @@ -472,7 +472,7 @@ static int get_altsetting (struct usbtes 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 usbtes 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 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 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 /* 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 -puN drivers/usb/misc/uss720.c~bk-usb drivers/usb/misc/uss720.c --- 25/drivers/usb/misc/uss720.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/misc/uss720.c 2005-03-04 00:45:34.000000000 -0800 @@ -75,7 +75,7 @@ static int get_1284_register(struct parp 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 parp 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_d 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_d 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_da 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_compa 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 -puN /dev/null drivers/usb/mon/Kconfig --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/mon/Kconfig 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN /dev/null drivers/usb/mon/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/mon/Makefile 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN /dev/null drivers/usb/mon/mon_main.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/mon/mon_main.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 +#include +#include +#include +#include + +#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 -puN /dev/null drivers/usb/mon/mon_stat.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/mon/mon_stat.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 +#include +#include + +#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 -puN /dev/null drivers/usb/mon/mon_text.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/mon/mon_text.c 2005-03-04 00:45:34.000000000 -0800 @@ -0,0 +1,395 @@ +/* + * The USB Monitor, inspired by Dave Harding's USBMon. + * + * This is a text format reader. + */ + +#include +#include +#include +#include +#include + +#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 -puN /dev/null drivers/usb/mon/usb_mon.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/mon/usb_mon.h 2005-03-04 00:45:34.000000000 -0800 @@ -0,0 +1,51 @@ +/* + * The USB Monitor, inspired by Dave Harding's USBMon. + */ + +#ifndef __USB_MON_H +#define __USB_MON_H + +#include +#include +#include +/* #include */ /* 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 -puN drivers/usb/net/catc.c~bk-usb drivers/usb/net/catc.c --- 25/drivers/usb/net/catc.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/net/catc.c 2005-03-04 00:45:34.000000000 -0800 @@ -457,7 +457,7 @@ static int catc_ctrl_msg(struct catc *ca { 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 -puN drivers/usb/net/kaweth.c~bk-usb drivers/usb/net/kaweth.c --- 25/drivers/usb/net/kaweth.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/net/kaweth.c 2005-03-04 00:45:34.000000000 -0800 @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -1180,31 +1181,21 @@ static void usb_api_blocking_completion( // 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 -puN drivers/usb/net/Kconfig~bk-usb drivers/usb/net/Kconfig --- 25/drivers/usb/net/Kconfig~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/net/Kconfig 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/net/Makefile~bk-usb drivers/usb/net/Makefile --- 25/drivers/usb/net/Makefile~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/net/Makefile 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/net/pegasus.c~bk-usb drivers/usb/net/pegasus.c --- 25/drivers/usb/net/pegasus.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/net/pegasus.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 " #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" @@ -301,20 +301,20 @@ static int read_mii_word(pegasus_t * peg if (i < REG_TIMEOUT) { get_registers(pegasus, PhyData, 2, ®di); *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_interva 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, 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(pega 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_inte 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_inte 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 us 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 us 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 -puN drivers/usb/net/pegasus.h~bk-usb drivers/usb/net/pegasus.h --- 25/drivers/usb/net/pegasus.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/net/pegasus.h 2005-03-04 00:45:34.000000000 -0800 @@ -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 -puN drivers/usb/net/rtl8150.c~bk-usb drivers/usb/net/rtl8150.c --- 25/drivers/usb/net/rtl8150.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/net/rtl8150.c 2005-03-04 00:45:34.000000000 -0800 @@ -195,14 +195,14 @@ static int get_registers(rtl8150_t * dev { 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 -puN drivers/usb/net/usbnet.c~bk-usb drivers/usb/net/usbnet.c --- 25/drivers/usb/net/usbnet.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/net/usbnet.c 2005-03-04 00:45:34.000000000 -0800 @@ -2,7 +2,8 @@ * USB Networking Links * Copyright (C) 2000-2003 by David Brownell * Copyright (C) 2002 Pavel Machek - * Copyright (C) 2003 David Hollis + * Copyright (C) 2003-2005 David Hollis + * Copyright (C) 2005 Phil Chang * 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_i #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_i #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_i #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 usbne 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 usbn 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(s 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_de 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 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_ethtoo .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_ethtoo 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 *d 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 *d 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 *d 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 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_ .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_i #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 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 usbn * 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 usbn 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 usbn 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 (stru 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 */ 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 r 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 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 usbn { 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 usbn } 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 re 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 *de 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_devic 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 produc // 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 produc .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 produc * * 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 produc | 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 produc * 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 -puN /dev/null drivers/usb/net/zd1201.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/net/zd1201.c 2005-03-04 00:45:34.000000000 -0800 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 "); +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; irx_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; imc_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; irxlen; 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 -puN /dev/null drivers/usb/net/zd1201.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/usb/net/zd1201.h 2005-03-04 00:45:35.000000000 -0800 @@ -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 -puN drivers/usb/serial/belkin_sa.c~bk-usb drivers/usb/serial/belkin_sa.c --- 25/drivers/usb/serial/belkin_sa.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/belkin_sa.c 2005-03-04 00:45:35.000000000 -0800 @@ -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 -puN drivers/usb/serial/cyberjack.c~bk-usb drivers/usb/serial/cyberjack.c --- 25/drivers/usb/serial/cyberjack.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/cyberjack.c 2005-03-04 00:45:35.000000000 -0800 @@ -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 -puN drivers/usb/serial/cypress_m8.c~bk-usb drivers/usb/serial/cypress_m8.c --- 25/drivers/usb/serial/cypress_m8.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/cypress_m8.c 2005-03-04 00:45:35.000000000 -0800 @@ -57,9 +57,10 @@ #include #include #include -#include #include #include +#include +#include #include "usb-serial.h" #include "cypress_m8.h" @@ -1013,8 +1014,7 @@ static void cypress_set_termios (struct 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 -puN drivers/usb/serial/ezusb.c~bk-usb drivers/usb/serial/ezusb.c --- 25/drivers/usb/serial/ezusb.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/ezusb.c 2005-03-04 00:45:35.000000000 -0800 @@ -38,7 +38,7 @@ int ezusb_writememory (struct usb_serial 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 -puN drivers/usb/serial/ftdi_sio.c~bk-usb drivers/usb/serial/ftdi_sio.c --- 25/drivers/usb/serial/ftdi_sio.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/ftdi_sio.c 2005-03-04 00:45:35.000000000 -0800 @@ -296,6 +296,7 @@ static struct usb_device_id id_table_8U2 { 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_FT2 { 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_com { 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 ftd -#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 -puN drivers/usb/serial/ftdi_sio.h~bk-usb drivers/usb/serial/ftdi_sio.h --- 25/drivers/usb/serial/ftdi_sio.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/ftdi_sio.h 2005-03-04 00:45:35.000000000 -0800 @@ -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 -puN drivers/usb/serial/io_edgeport.c~bk-usb drivers/usb/serial/io_edgeport.c --- 25/drivers/usb/serial/io_edgeport.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/io_edgeport.c 2005-03-04 00:45:35.000000000 -0800 @@ -261,6 +261,7 @@ #include #include #include +#include #include #include #include "usb-serial.h" @@ -971,7 +972,7 @@ static void edge_bulk_out_cmd_callback ( /* 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_ 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_ } /* 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_ ************************************************************************/ 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(s } // 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(s } 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(s ************************************************************************/ 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 } // 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 edgepo *****************************************************************************/ 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 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 // 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 /* 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 edgepor // 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 -puN drivers/usb/serial/io_ti.c~bk-usb drivers/usb/serial/io_ti.c --- 25/drivers/usb/serial/io_ti.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/io_ti.c 2005-03-04 00:45:35.000000000 -0800 @@ -273,7 +273,7 @@ static int TIReadVendorRequestSync (stru index, data, size, - HZ); + 1000); if (status < 0) return status; if (status != size) { @@ -303,8 +303,7 @@ static int TISendVendorRequestSync (stru index, data, size, - HZ); - + 1000); if (status < 0) return status; if (status != size) { @@ -985,7 +984,7 @@ static int TISendBulkTransferSync (struc buffer, length, num_sent, - HZ); + 1000); return status; } diff -puN drivers/usb/serial/ipaq.c~bk-usb drivers/usb/serial/ipaq.c --- 25/drivers/usb/serial/ipaq.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/ipaq.c 2005-03-04 00:45:35.000000000 -0800 @@ -662,7 +662,7 @@ static int ipaq_open(struct usb_serial_p 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 -puN drivers/usb/serial/ipw.c~bk-usb drivers/usb/serial/ipw.c --- 25/drivers/usb/serial/ipw.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/ipw.c 2005-03-04 00:45:35.000000000 -0800 @@ -232,7 +232,7 @@ static int ipw_open(struct usb_serial_po 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_po 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_po 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_po 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_po 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_ 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_ 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_ 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_ 0, /* index */ NULL, 0, - 100*HZ); + 100000); if (result < 0) dev_err(&port->dev, "Disabling bulk RxRead failed (error = %d)", result); diff -puN drivers/usb/serial/ir-usb.c~bk-usb drivers/usb/serial/ir-usb.c --- 25/drivers/usb/serial/ir-usb.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/ir-usb.c 2005-03-04 00:45:35.000000000 -0800 @@ -189,7 +189,7 @@ static struct irda_class_desc *irda_usb_ 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 -puN drivers/usb/serial/keyspan_pda.c~bk-usb drivers/usb/serial/keyspan_pda.c --- 25/drivers/usb/serial/keyspan_pda.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/keyspan_pda.c 2005-03-04 00:45:35.000000000 -0800 @@ -205,7 +205,7 @@ static void keyspan_pda_request_unthrott 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 u 0, /* index */ NULL, /* &data */ 0, /* size */ - 2*HZ); /* timeout */ + 2000); /* timeout */ return(rc); } @@ -348,7 +348,7 @@ static void keyspan_pda_break_ctl (struc 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(st 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(st 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_ 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_ 0, /* index */ &room, 1, - 2*HZ); + 2000); if (rc < 0) { dbg("%s - roomquery failed", __FUNCTION__); goto error; diff -puN drivers/usb/serial/kl5kusb105.c~bk-usb drivers/usb/serial/kl5kusb105.c --- 25/drivers/usb/serial/kl5kusb105.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/kl5kusb105.c 2005-03-04 00:45:35.000000000 -0800 @@ -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 -puN drivers/usb/serial/mct_u232.c~bk-usb drivers/usb/serial/mct_u232.c --- 25/drivers/usb/serial/mct_u232.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/mct_u232.c 2005-03-04 00:45:35.000000000 -0800 @@ -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 -puN drivers/usb/serial/ti_usb_3410_5052.c~bk-usb drivers/usb/serial/ti_usb_3410_5052.c --- 25/drivers/usb/serial/ti_usb_3410_5052.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/ti_usb_3410_5052.c 2005-03-04 00:45:35.000000000 -0800 @@ -1580,7 +1580,7 @@ static int ti_command_out_sync(struct ti 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_ 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 t 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 -puN drivers/usb/serial/visor.c~bk-usb drivers/usb/serial/visor.c --- 25/drivers/usb/serial/visor.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/visor.c 2005-03-04 00:45:35.000000000 -0800 @@ -891,7 +891,7 @@ static int clie_3_5_startup (struct usb_ /* 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_ 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 -puN drivers/usb/serial/whiteheat.c~bk-usb drivers/usb/serial/whiteheat.c --- 25/drivers/usb/serial/whiteheat.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/serial/whiteheat.c 2005-03-04 00:45:35.000000000 -0800 @@ -254,6 +254,7 @@ static int firm_report_tx_done(struct us #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_ * 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_ 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 -puN drivers/usb/storage/Kconfig~bk-usb drivers/usb/storage/Kconfig --- 25/drivers/usb/storage/Kconfig~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/storage/Kconfig 2005-03-04 00:45:35.000000000 -0800 @@ -90,12 +90,26 @@ config USB_STORAGE_DPCM Say Y here to support the Microtech/ZiO! CompactFlash reader. There is a web page at . -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 -puN drivers/usb/storage/Makefile~bk-usb drivers/usb/storage/Makefile --- 25/drivers/usb/storage/Makefile~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/storage/Makefile 2005-03-04 00:45:35.000000000 -0800 @@ -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 -puN drivers/usb/storage/protocol.c~bk-usb drivers/usb/storage/protocol.c --- 25/drivers/usb/storage/protocol.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/storage/protocol.c 2005-03-04 00:45:35.000000000 -0800 @@ -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(s { /* 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 -puN drivers/usb/storage/scsiglue.c~bk-usb drivers/usb/storage/scsiglue.c --- 25/drivers/usb/storage/scsiglue.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/storage/scsiglue.c 2005-03-04 00:45:35.000000000 -0800 @@ -149,6 +149,11 @@ static int slave_configure(struct scsi_d 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_d 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 * 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 -puN drivers/usb/storage/shuttle_usbat.c~bk-usb drivers/usb/storage/shuttle_usbat.c --- 25/drivers/usb/storage/shuttle_usbat.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/storage/shuttle_usbat.c 2005-03-04 00:45:35.000000000 -0800 @@ -4,10 +4,14 @@ * * Current development and maintenance by: * (c) 2000, 2001 Robert Baruch (autophile@starband.net) + * (c) 2004, 2005 Daniel Drake * * Developed with the assistance of: * (c) 2002 Alan Stern * + * Flash support based on earlier work by: + * (c) 2002 Thomas Kreiling + * * 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(st 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 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 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_d 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 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 } 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 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[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 */ 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 } /* - * 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; isend_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 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[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 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_regi 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 * 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 * 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 * 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 * } 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 * } 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 * // 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 * // 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 * 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 * 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 -puN drivers/usb/storage/shuttle_usbat.h~bk-usb drivers/usb/storage/shuttle_usbat.h --- 25/drivers/usb/storage/shuttle_usbat.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/storage/shuttle_usbat.h 2005-03-04 00:45:35.000000000 -0800 @@ -5,8 +5,9 @@ * * Current development and maintenance by: * (c) 2000 Robert Baruch (autophile@dol.net) + * (c) 2004, 2005 Daniel Drake * - * 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 -puN drivers/usb/storage/transport.c~bk-usb drivers/usb/storage/transport.c --- 25/drivers/usb/storage/transport.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/storage/transport.c 2005-03-04 00:45:35.000000000 -0800 @@ -991,10 +991,10 @@ int usb_stor_Bulk_transport(struct scsi_ /* 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_ 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 -puN drivers/usb/storage/transport.h~bk-usb drivers/usb/storage/transport.h --- 25/drivers/usb/storage/transport.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/storage/transport.h 2005-03-04 00:45:35.000000000 -0800 @@ -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 -puN drivers/usb/storage/unusual_devs.h~bk-usb drivers/usb/storage/unusual_devs.h --- 25/drivers/usb/storage/unusual_devs.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/storage/unusual_devs.h 2005-03-04 00:45:35.000000000 -0800 @@ -59,16 +59,16 @@ UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x "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 @@ -123,6 +123,13 @@ UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x "DVD-CAM DZ-MV100A Camcorder", US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN), +/* Reported by Andreas Bockhold */ +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 * This entry needs Sub and Proto fields */ UNUSUAL_DEV( 0x04b8, 0x0601, 0x0100, 0x0100, @@ -171,15 +178,12 @@ UNUSUAL_DEV( 0x04da, 0x0d05, 0x0000, 0x "CD-R/RW Drive", US_SC_8070, US_PR_CB, NULL, 0), -/* Reported by Adriaan Penning - * 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 */ 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, 0x 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 -- only rev 1.33 tested */ UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133, "Belkin", @@ -324,12 +336,11 @@ UNUSUAL_DEV( 0x052b, 0x1911, 0x0100, 0x 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, 0x 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 + * and Peter Marks + * 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 * Taken from the Lycoris Kernel */ UNUSUAL_DEV( 0x0636, 0x0003, 0x0000, 0x9999, @@ -540,19 +570,19 @@ UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0 US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), -/* Reported by Alex Butcher */ -UNUSUAL_DEV( 0x067b, 0x3507, 0x0001, 0x0001, +/* Reported by Richard -=[]=- */ +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 */ 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 */ UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001, @@ -582,12 +612,18 @@ UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x 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, 0x0 US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Ian McConnell */ +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 */ UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300, "USB", @@ -905,6 +948,13 @@ UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Radovan Garabik */ +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 -puN drivers/usb/storage/usb.c~bk-usb drivers/usb/storage/usb.c --- 25/drivers/usb/storage/usb.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/storage/usb.c 2005-03-04 00:45:35.000000000 -0800 @@ -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_ { 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_ .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_da 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_da 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->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 -puN drivers/usb/storage/usb.h~bk-usb drivers/usb/storage/usb.h --- 25/drivers/usb/storage/usb.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/storage/usb.h 2005-03-04 00:45:35.000000000 -0800 @@ -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 -puN drivers/usb/usb-skeleton.c~bk-usb drivers/usb/usb-skeleton.c --- 25/drivers/usb/usb-skeleton.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/usb/usb-skeleton.c 2005-03-04 00:45:35.000000000 -0800 @@ -120,7 +120,7 @@ static ssize_t skel_read(struct file *fi 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_interfa } 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 -puN drivers/w1/dscore.c~bk-usb drivers/w1/dscore.c --- 25/drivers/w1/dscore.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/drivers/w1/dscore.c 2005-03-04 00:45:35.000000000 -0800 @@ -84,7 +84,7 @@ static int ds_send_control_cmd(struct ds 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); @@ -99,7 +99,7 @@ static int ds_send_control_mode(struct d 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); @@ -114,7 +114,7 @@ static int ds_send_control(struct ds_dev 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); @@ -213,7 +213,7 @@ int ds_recv_data(struct ds_device *dev, 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])); @@ -239,7 +239,7 @@ int ds_send_data(struct ds_device *dev, 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 -puN fs/compat_ioctl.c~bk-usb fs/compat_ioctl.c --- 25/fs/compat_ioctl.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/fs/compat_ioctl.c 2005-03-04 00:45:35.000000000 -0800 @@ -2575,229 +2575,11 @@ static int do_usbdevfs_bulk(unsigned int 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; @@ -3331,9 +3113,6 @@ HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ /* 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 -puN include/linux/compat_ioctl.h~bk-usb include/linux/compat_ioctl.h --- 25/include/linux/compat_ioctl.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/include/linux/compat_ioctl.h 2005-03-04 00:45:35.000000000 -0800 @@ -692,6 +692,9 @@ COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFA 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 -puN include/linux/pci_ids.h~bk-usb include/linux/pci_ids.h --- 25/include/linux/pci_ids.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/include/linux/pci_ids.h 2005-03-04 00:45:35.000000000 -0800 @@ -2053,8 +2053,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 -puN /dev/null include/linux/usb_cdc.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/linux/usb_cdc.h 2005-03-04 00:45:35.000000000 -0800 @@ -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 -puN include/linux/usbdevice_fs.h~bk-usb include/linux/usbdevice_fs.h --- 25/include/linux/usbdevice_fs.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/include/linux/usbdevice_fs.h 2005-03-04 00:45:35.000000000 -0800 @@ -32,6 +32,7 @@ #define _LINUX_USBDEVICE_FS_H #include +#include /* --------------------------------------------------------------------- */ @@ -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 -puN include/linux/usb.h~bk-usb include/linux/usb.h --- 25/include/linux/usb.h~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/include/linux/usb.h 2005-03-04 00:45:35.000000000 -0800 @@ -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(struc 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 -puN MAINTAINERS~bk-usb MAINTAINERS --- 25/MAINTAINERS~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/MAINTAINERS 2005-03-04 00:45:35.000000000 -0800 @@ -2053,6 +2053,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 @@ -2401,6 +2407,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 @@ -2502,6 +2514,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 -puN sound/usb/usbmixer.c~bk-usb sound/usb/usbmixer.c --- 25/sound/usb/usbmixer.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/sound/usb/usbmixer.c 2005-03-04 00:45:35.000000000 -0800 @@ -305,7 +305,7 @@ static int get_ctl_value(usb_mixer_elem_ 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_ 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 -puN sound/usb/usx2y/usX2Yhwdep.c~bk-usb sound/usb/usx2y/usX2Yhwdep.c --- 25/sound/usb/usx2y/usX2Yhwdep.c~bk-usb 2005-03-04 00:45:34.000000000 -0800 +++ 25-akpm/sound/usb/usx2y/usX2Yhwdep.c 2005-03-04 00:45:35.000000000 -0800 @@ -226,7 +226,7 @@ static int snd_usX2Y_hwdep_dsp_load(snd_ 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) _