From 8608471262ddf4b8ed4120d7211251e8b8dcbda9 Mon Sep 17 00:00:00 2001 From: Hans-Christian Egtvedt Date: Sun, 29 May 2005 02:27:45 -0500 Subject: Input: Add driver for ITM Touch USB touchscreens. From: Hans-Christian Egtvedt Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/usb/input/Kconfig | 12 ++ drivers/usb/input/Makefile | 1 + drivers/usb/input/itmtouch.c | 281 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 294 insertions(+) create mode 100644 drivers/usb/input/itmtouch.c (limited to 'drivers/usb') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index d28e7eab6f98..fcae574f3106 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -190,6 +190,18 @@ config USB_MTOUCH To compile this driver as a module, choose M here: the module will be called mtouchusb. +config USB_ITMTOUCH + tristate "ITM Touch USB Touchscreen Driver" + depends on USB && INPUT + ---help--- + Say Y here if you want to use a ITM Touch USB + Touchscreen controller. + + This touchscreen is used in LG 1510SF monitors. + + To compile this driver as a module, choose M here: the + module will be called itmtouch. + config USB_EGALAX tristate "eGalax TouchKit USB Touchscreen Driver" depends on USB && INPUT diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 6bcedd16b0a1..f0fd02e00d32 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_USB_KBD) += usbkbd.o obj-$(CONFIG_USB_KBTAB) += kbtab.o obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o +obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o obj-$(CONFIG_USB_EGALAX) += touchkitusb.o obj-$(CONFIG_USB_POWERMATE) += powermate.o obj-$(CONFIG_USB_WACOM) += wacom.o diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c new file mode 100644 index 000000000000..4c27c104f63e --- /dev/null +++ b/drivers/usb/input/itmtouch.c @@ -0,0 +1,281 @@ +/****************************************************************************** + * itmtouch.c -- Driver for ITM touchscreen panel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Based upon original work by Chris Collins . + * + * Kudos to ITM for providing me with the datasheet for the panel, + * even though it was a day later than I had finished writing this + * driver. + * + * It has meant that I've been able to correct my interpretation of the + * protocol packets however. + * + * CC -- 2003/9/29 + * + * History + * 1.0 & 1.1 2003 (CC) vojtech@suse.cz + * Original version for 2.4.x kernels + * + * 1.2 02/03/2005 (HCE) hc@mivu.no + * Complete rewrite to support Linux 2.6.10, thanks to mtouchusb.c for hints. + * Unfortunately no calibration support at this time. + * + * 1.2.1 09/03/2005 (HCE) hc@mivu.no + * Code cleanup and adjusting syntax to start matching kernel standards + * + *****************************************************************************/ + +#include + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include +#include +#include +#include +#include +#include + +/* only an 8 byte buffer necessary for a single packet */ +#define ITM_BUFSIZE 8 +#define PATH_SIZE 64 + +#define USB_VENDOR_ID_ITMINC 0x0403 +#define USB_PRODUCT_ID_TOUCHPANEL 0xf9e9 + +#define DRIVER_AUTHOR "Hans-Christian Egtvedt " +#define DRIVER_VERSION "v1.2.1" +#define DRIVER_DESC "USB ITM Inc Touch Panel Driver" +#define DRIVER_LICENSE "GPL" + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_LICENSE( DRIVER_LICENSE ); + +struct itmtouch_dev { + struct usb_device *usbdev; /* usb device */ + struct input_dev inputdev; /* input device */ + struct urb *readurb; /* urb */ + char rbuf[ITM_BUFSIZE]; /* data */ + int users; + char name[128]; + char phys[64]; +}; + +static struct usb_device_id itmtouch_ids [] = { + { USB_DEVICE(USB_VENDOR_ID_ITMINC, USB_PRODUCT_ID_TOUCHPANEL) }, + { } +}; + +static void itmtouch_irq(struct urb *urb, struct pt_regs *regs) +{ + struct itmtouch_dev * itmtouch = urb->context; + unsigned char *data = urb->transfer_buffer; + struct input_dev *dev = &itmtouch->inputdev; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ETIMEDOUT: + /* this urb is timing out */ + dbg("%s - urb timed out - was the device unplugged?", + __FUNCTION__); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + input_regs(dev, regs); + + /* if pressure has been released, then don't report X/Y */ + if (data[7] & 0x20) { + input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F)); + input_report_abs(dev, ABS_Y, (data[1] & 0x1F) << 7 | (data[4] & 0x7F)); + } + + input_report_abs(dev, ABS_PRESSURE, (data[2] & 1) << 7 | (data[5] & 0x7F)); + input_report_key(dev, BTN_TOUCH, ~data[7] & 0x20); + input_sync(dev); + +exit: + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval) + printk(KERN_ERR "%s - usb_submit_urb failed with result: %d", + __FUNCTION__, retval); +} + +static int itmtouch_open(struct input_dev *input) +{ + struct itmtouch_dev *itmtouch = input->private; + + if (itmtouch->users++) + return 0; + + itmtouch->readurb->dev = itmtouch->usbdev; + + if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL)) + { + itmtouch->users--; + return -EIO; + } + + return 0; +} + +static void itmtouch_close(struct input_dev *input) +{ + struct itmtouch_dev *itmtouch = input->private; + + if (!--itmtouch->users) + usb_kill_urb(itmtouch->readurb); +} + +static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct itmtouch_dev *itmtouch; + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = interface_to_usbdev(intf); + unsigned int pipe; + unsigned int maxp; + char path[PATH_SIZE]; + + interface = intf->cur_altsetting; + endpoint = &interface->endpoint[0].desc; + + if (!(itmtouch = kcalloc(1, sizeof(struct itmtouch_dev), GFP_KERNEL))) { + err("%s - Out of memory.", __FUNCTION__); + return -ENOMEM; + } + + itmtouch->usbdev = udev; + + itmtouch->inputdev.private = itmtouch; + itmtouch->inputdev.open = itmtouch_open; + itmtouch->inputdev.close = itmtouch_close; + + usb_make_path(udev, path, PATH_SIZE); + + itmtouch->inputdev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + itmtouch->inputdev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + itmtouch->inputdev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + + itmtouch->inputdev.name = itmtouch->name; + itmtouch->inputdev.phys = itmtouch->phys; + itmtouch->inputdev.id.bustype = BUS_USB; + itmtouch->inputdev.id.vendor = udev->descriptor.idVendor; + itmtouch->inputdev.id.product = udev->descriptor.idProduct; + itmtouch->inputdev.id.version = udev->descriptor.bcdDevice; + itmtouch->inputdev.dev = &intf->dev; + + if (!strlen(itmtouch->name)) + sprintf(itmtouch->name, "USB ITM touchscreen"); + + /* device limits */ + /* as specified by the ITM datasheet, X and Y are 12bit, + * Z (pressure) is 8 bit. However, the fields are defined up + * to 14 bits for future possible expansion. + */ + input_set_abs_params(&itmtouch->inputdev, ABS_X, 0, 0x0FFF, 2, 0); + input_set_abs_params(&itmtouch->inputdev, ABS_Y, 0, 0x0FFF, 2, 0); + input_set_abs_params(&itmtouch->inputdev, ABS_PRESSURE, 0, 0xFF, 2, 0); + + /* initialise the URB so we can read from the transport stream */ + pipe = usb_rcvintpipe(itmtouch->usbdev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + + if (maxp > ITM_BUFSIZE) + maxp = ITM_BUFSIZE; + + itmtouch->readurb = usb_alloc_urb(0, GFP_KERNEL); + + if (!itmtouch->readurb) { + dbg("%s - usb_alloc_urb failed: itmtouch->readurb", __FUNCTION__); + kfree(itmtouch); + return -ENOMEM; + } + + usb_fill_int_urb(itmtouch->readurb, + itmtouch->usbdev, + pipe, + itmtouch->rbuf, + maxp, + itmtouch_irq, + itmtouch, + endpoint->bInterval); + + input_register_device(&itmtouch->inputdev); + + printk(KERN_INFO "itmtouch: %s registered on %s\n", itmtouch->name, path); + usb_set_intfdata(intf, itmtouch); + + return 0; +} + +static void itmtouch_disconnect(struct usb_interface *intf) +{ + struct itmtouch_dev *itmtouch = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + + if (itmtouch) { + input_unregister_device(&itmtouch->inputdev); + usb_kill_urb(itmtouch->readurb); + usb_free_urb(itmtouch->readurb); + kfree(itmtouch); + } +} + +MODULE_DEVICE_TABLE(usb, itmtouch_ids); + +static struct usb_driver itmtouch_driver = { + .owner = THIS_MODULE, + .name = "itmtouch", + .probe = itmtouch_probe, + .disconnect = itmtouch_disconnect, + .id_table = itmtouch_ids, +}; + +static int __init itmtouch_init(void) +{ + info(DRIVER_DESC " " DRIVER_VERSION); + info(DRIVER_AUTHOR); + return usb_register(&itmtouch_driver); +} + +static void __exit itmtouch_exit(void) +{ + usb_deregister(&itmtouch_driver); +} + +module_init(itmtouch_init); +module_exit(itmtouch_exit); -- cgit v1.2.3 From 854561b019285acf6e98ca9288fef0d034476fec Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sun, 29 May 2005 02:28:00 -0500 Subject: Input: Make hid-core issue a SET_IDLE request before GET_REPORT, like Windows does. This should make life easier for devices that were tested with Windows only. Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/usb/input/hid-core.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 869ff73690ac..cd8d221395e2 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1233,6 +1233,13 @@ int hid_wait_io(struct hid_device *hid) return 0; } +static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle) +{ + usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report, + ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT); +} + static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, unsigned char type, void *buf, int size) { @@ -1301,10 +1308,6 @@ void hid_init_reports(struct hid_device *hid) if (err) warn("timeout initializing reports\n"); - - 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, USB_CTRL_SET_TIMEOUT); } #define USB_VENDOR_ID_WACOM 0x056a @@ -1572,6 +1575,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) return NULL; } + hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0); + if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) { dbg("reading report descriptor failed"); kfree(rdesc); -- cgit v1.2.3 From 71387bd77f662a83b18ff8de676e9d9531c58894 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sun, 29 May 2005 02:28:14 -0500 Subject: Input: Fix a warning in hid-core. Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/usb/input/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index cd8d221395e2..6bf39656adc7 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1235,7 +1235,7 @@ int hid_wait_io(struct hid_device *hid) static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle) { - usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report, ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT); } -- cgit v1.2.3 From 05f091ab4c8c1f12f8dd38ee789489904fea327d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 29 May 2005 02:29:01 -0500 Subject: Input: whitespace fixes in drivers/usb/input Signed-off-by: Dmitry Torokhov --- drivers/usb/input/aiptek.c | 18 ++-- drivers/usb/input/ati_remote.c | 221 ++++++++++++++++++++--------------------- drivers/usb/input/hid-core.c | 4 +- drivers/usb/input/hid-debug.h | 16 +-- drivers/usb/input/hid-input.c | 16 +-- drivers/usb/input/hid-lgff.c | 18 ++-- drivers/usb/input/hid.h | 18 ++-- drivers/usb/input/hiddev.c | 56 +++++------ drivers/usb/input/itmtouch.c | 55 +++++----- drivers/usb/input/kbtab.c | 6 +- drivers/usb/input/powermate.c | 30 +++--- drivers/usb/input/usbkbd.c | 18 ++-- drivers/usb/input/usbmouse.c | 20 ++-- drivers/usb/input/wacom.c | 46 ++++----- drivers/usb/input/xpad.c | 66 ++++++------ 15 files changed, 300 insertions(+), 308 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index 94ce2a9ad50f..68d9d281386c 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -1,7 +1,7 @@ /* * Native support for the Aiptek HyperPen USB Tablets * (4000U/5000U/6000U/8000U/12000U) - * + * * Copyright (c) 2001 Chris Atenasio * Copyright (c) 2002-2004 Bryan W. Headley * @@ -31,7 +31,7 @@ * - Added support for the sysfs interface, deprecating the * procfs interface for 2.5.x kernel. Also added support for * Wheel command. Bryan W. Headley July-15-2003. - * v1.2 - Reworked jitter timer as a kernel thread. + * v1.2 - Reworked jitter timer as a kernel thread. * Bryan W. Headley November-28-2003/Jan-10-2004. * v1.3 - Repaired issue of kernel thread going nuts on single-processor * machines, introduced programmableDelay as a command line @@ -49,10 +49,10 @@ * NOTE: * This kernel driver is augmented by the "Aiptek" XFree86 input * driver for your X server, as well as the Gaiptek GUI Front-end - * "Tablet Manager". - * These three products are highly interactive with one another, + * "Tablet Manager". + * These three products are highly interactive with one another, * so therefore it's easier to document them all as one subsystem. - * Please visit the project's "home page", located at, + * Please visit the project's "home page", located at, * http://aiptektablet.sourceforge.net. * * This program is free software; you can redistribute it and/or modify @@ -156,7 +156,7 @@ * Command/Data Description Return Bytes Return Value * 0x10/0x00 SwitchToMouse 0 * 0x10/0x01 SwitchToTablet 0 - * 0x18/0x04 SetResolution 0 + * 0x18/0x04 SetResolution 0 * 0x12/0xFF AutoGainOn 0 * 0x17/0x00 FilterOn 0 * 0x01/0x00 GetXExtension 2 MaxX @@ -247,7 +247,7 @@ #define AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE 2 #define AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED 3 - /* Time to wait (in ms) to help mask hand jittering + /* Time to wait (in ms) to help mask hand jittering * when pressing the stylus buttons. */ #define AIPTEK_JITTER_DELAY_DEFAULT 50 @@ -791,7 +791,7 @@ exit: * specific Aiptek model numbers, because there has been overlaps, * use, and reuse of id's in existing models. Certain models have * been known to use more than one ID, indicative perhaps of - * manufacturing revisions. In any event, we consider these + * manufacturing revisions. In any event, we consider these * IDs to not be model-specific nor unique. */ static const struct usb_device_id aiptek_ids[] = { @@ -840,7 +840,7 @@ static void aiptek_close(struct input_dev *inputdev) } /*********************************************************************** - * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x, + * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x, * where they were known as usb_set_report and usb_get_report. */ static int diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index 860df26323b1..cf45add81713 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -1,15 +1,15 @@ -/* +/* * USB ATI Remote support * * Version 2.2.0 Copyright (c) 2004 Torrey Hoffman * Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev * * This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including - * porting to the 2.6 kernel interfaces, along with other modification + * porting to the 2.6 kernel interfaces, along with other modification * to better match the style of the existing usb/input drivers. However, the * protocol and hardware handling is essentially unchanged from 2.1.1. - * - * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by + * + * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by * Vojtech Pavlik. * * Changes: @@ -23,64 +23,64 @@ * Added support for the "Lola" remote contributed by: * Seth Cohn * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Hardware & software notes * - * These remote controls are distributed by ATI as part of their - * "All-In-Wonder" video card packages. The receiver self-identifies as a + * These remote controls are distributed by ATI as part of their + * "All-In-Wonder" video card packages. The receiver self-identifies as a * "USB Receiver" with manufacturer "X10 Wireless Technology Inc". * - * The "Lola" remote is available from X10. See: + * The "Lola" remote is available from X10. See: * http://www.x10.com/products/lola_sg1.htm * The Lola is similar to the ATI remote but has no mouse support, and slightly * different keys. * - * It is possible to use multiple receivers and remotes on multiple computers + * It is possible to use multiple receivers and remotes on multiple computers * simultaneously by configuring them to use specific channels. - * - * The RF protocol used by the remote supports 16 distinct channels, 1 to 16. - * Actually, it may even support more, at least in some revisions of the + * + * The RF protocol used by the remote supports 16 distinct channels, 1 to 16. + * Actually, it may even support more, at least in some revisions of the * hardware. * * Each remote can be configured to transmit on one channel as follows: - * - Press and hold the "hand icon" button. - * - When the red LED starts to blink, let go of the "hand icon" button. - * - When it stops blinking, input the channel code as two digits, from 01 + * - Press and hold the "hand icon" button. + * - When the red LED starts to blink, let go of the "hand icon" button. + * - When it stops blinking, input the channel code as two digits, from 01 * to 16, and press the hand icon again. - * + * * The timing can be a little tricky. Try loading the module with debug=1 * to have the kernel print out messages about the remote control number * and mask. Note: debugging prints remote numbers as zero-based hexadecimal. * * The driver has a "channel_mask" parameter. This bitmask specifies which - * channels will be ignored by the module. To mask out channels, just add + * channels will be ignored by the module. To mask out channels, just add * all the 2^channel_number values together. * * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote - * ignore signals coming from remote controls transmitting on channel 4, but + * ignore signals coming from remote controls transmitting on channel 4, but * accept all other channels. * - * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be + * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be * ignored. * - * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this + * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this * parameter are unused. * */ @@ -99,13 +99,13 @@ /* * Module and Version Information, Module Parameters */ - -#define ATI_REMOTE_VENDOR_ID 0x0bc7 -#define ATI_REMOTE_PRODUCT_ID 0x004 -#define LOLA_REMOTE_PRODUCT_ID 0x002 + +#define ATI_REMOTE_VENDOR_ID 0x0bc7 +#define ATI_REMOTE_PRODUCT_ID 0x004 +#define LOLA_REMOTE_PRODUCT_ID 0x002 #define MEDION_REMOTE_PRODUCT_ID 0x006 -#define DRIVER_VERSION "2.2.1" +#define DRIVER_VERSION "2.2.1" #define DRIVER_AUTHOR "Torrey Hoffman " #define DRIVER_DESC "ATI/X10 RF USB Remote Control" @@ -124,7 +124,7 @@ MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) #undef err #define err(format, arg...) printk(KERN_ERR format , ## arg) - + static struct usb_device_id ati_remote_table[] = { { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) }, @@ -148,7 +148,7 @@ static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; /* Acceleration curve for directional control pad */ static char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; -/* Duplicate event filtering time. +/* Duplicate event filtering time. * Sequential, identical KIND_FILTERED inputs with less than * FILTER_TIME jiffies between them are considered as repeat * events. The hardware generates 5 events for the first keypress @@ -161,10 +161,10 @@ static char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; static DECLARE_MUTEX(disconnect_sem); struct ati_remote { - struct input_dev idev; + struct input_dev idev; struct usb_device *udev; struct usb_interface *interface; - + struct urb *irq_urb; struct urb *out_urb; struct usb_endpoint_descriptor *endpoint_in; @@ -175,12 +175,12 @@ struct ati_remote { dma_addr_t outbuf_dma; int open; /* open counter */ - + unsigned char old_data[2]; /* Detect duplicate events */ unsigned long old_jiffies; unsigned long acc_jiffies; /* handle acceleration */ unsigned int repeat_count; - + char name[NAME_BUFSIZE]; char phys[NAME_BUFSIZE]; @@ -206,14 +206,14 @@ static struct int type; unsigned int code; int value; -} ati_remote_tbl[] = +} ati_remote_tbl[] = { /* Directional control pad axes */ {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ {KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */ {KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */ - /* Directional control pad diagonals */ + /* Directional control pad diagonals */ {KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */ {KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */ {KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */ @@ -225,7 +225,7 @@ static struct {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ - /* Artificial "doubleclick" events are generated by the hardware. + /* Artificial "doubleclick" events are generated by the hardware. * They are mapped to the "side" and "extra" mouse buttons here. */ {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ @@ -273,15 +273,15 @@ static struct {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1}, /* ( >) */ {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */ {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */ - {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */ + {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */ {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */ {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1}, /* (<-) */ {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1}, /* (>+) */ {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1}, /* PLAYING */ {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1}, /* TOP */ {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1}, /* END */ - {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */ - + {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */ + {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} }; @@ -315,7 +315,7 @@ static void ati_remote_dump(unsigned char *data, unsigned int len) if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) warn("Weird byte 0x%02x", data[0]); else if (len == 4) - warn("Weird key %02x %02x %02x %02x", + warn("Weird key %02x %02x %02x %02x", data[0], data[1], data[2], data[3]); else warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...", @@ -338,7 +338,7 @@ static int ati_remote_open(struct input_dev *inputdev) /* On first open, submit the read urb which was set up previously. */ ati_remote->irq_urb->dev = ati_remote->udev; if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { - dev_err(&ati_remote->interface->dev, + dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb failed!\n", __FUNCTION__); ati_remote->open--; retval = -EIO; @@ -355,7 +355,7 @@ exit: static void ati_remote_close(struct input_dev *inputdev) { struct ati_remote *ati_remote = inputdev->private; - + if (!--ati_remote->open) usb_kill_urb(ati_remote->irq_urb); } @@ -366,13 +366,13 @@ static void ati_remote_close(struct input_dev *inputdev) static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs) { struct ati_remote *ati_remote = urb->context; - + if (urb->status) { dev_dbg(&ati_remote->interface->dev, "%s: status %d\n", __FUNCTION__, urb->status); return; } - + ati_remote->send_flags |= SEND_FLAG_COMPLETE; wmb(); wake_up(&ati_remote->wait); @@ -380,16 +380,16 @@ static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs) /* * ati_remote_sendpacket - * + * * Used to send device initialization strings */ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data) { int retval = 0; - + /* Set up out_urb */ memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd)); - ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd); + ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd); ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1; ati_remote->out_urb->dev = ati_remote->udev; @@ -397,17 +397,17 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigne retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC); if (retval) { - dev_dbg(&ati_remote->interface->dev, + dev_dbg(&ati_remote->interface->dev, "sendpacket: usb_submit_urb failed: %d\n", retval); return retval; } wait_event_timeout(ati_remote->wait, ((ati_remote->out_urb->status != -EINPROGRESS) || - (ati_remote->send_flags & SEND_FLAG_COMPLETE)), + (ati_remote->send_flags & SEND_FLAG_COMPLETE)), HZ); usb_kill_urb(ati_remote->out_urb); - + return retval; } @@ -419,15 +419,15 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) int i; for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { - /* - * Decide if the table entry matches the remote input. + /* + * Decide if the table entry matches the remote input. */ if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) && - ((((ati_remote_tbl[i].data1 >> 4) - - (d1 >> 4) + rem) & 0x0f) == 0x0f) && + ((((ati_remote_tbl[i].data1 >> 4) - + (d1 >> 4) + rem) & 0x0f) == 0x0f) && (ati_remote_tbl[i].data2 == d2)) return i; - + } return -1; } @@ -435,16 +435,16 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) /* * ati_remote_report_input */ -static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) +static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) { struct ati_remote *ati_remote = urb->context; unsigned char *data= ati_remote->inbuf; - struct input_dev *dev = &ati_remote->idev; + struct input_dev *dev = &ati_remote->idev; int index, acc; int remote_num; - + /* Deal with strange looking inputs */ - if ( (urb->actual_length != 4) || (data[0] != 0x14) || + if ( (urb->actual_length != 4) || (data[0] != 0x14) || ((data[3] & 0x0f) != 0x00) ) { ati_remote_dump(data, urb->actual_length); return; @@ -453,7 +453,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) /* Mask unwanted remote channels. */ /* note: remote_num is 0-based, channel 1 on remote == 0 here */ remote_num = (data[3] >> 4) & 0x0f; - if (channel_mask & (1 << (remote_num + 1))) { + if (channel_mask & (1 << (remote_num + 1))) { dbginfo(&ati_remote->interface->dev, "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n", remote_num, data[1], data[2], channel_mask); @@ -463,37 +463,36 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) /* Look up event code index in translation table */ index = ati_remote_event_lookup(remote_num, data[1], data[2]); if (index < 0) { - dev_warn(&ati_remote->interface->dev, - "Unknown input from channel 0x%02x: data %02x,%02x\n", + dev_warn(&ati_remote->interface->dev, + "Unknown input from channel 0x%02x: data %02x,%02x\n", remote_num, data[1], data[2]); return; - } - dbginfo(&ati_remote->interface->dev, + } + dbginfo(&ati_remote->interface->dev, "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n", remote_num, data[1], data[2], index, ati_remote_tbl[index].code); - + if (ati_remote_tbl[index].kind == KIND_LITERAL) { input_regs(dev, regs); input_event(dev, ati_remote_tbl[index].type, ati_remote_tbl[index].code, ati_remote_tbl[index].value); input_sync(dev); - + ati_remote->old_jiffies = jiffies; return; } - + if (ati_remote_tbl[index].kind == KIND_FILTERED) { /* Filter duplicate events which happen "too close" together. */ - if ((ati_remote->old_data[0] == data[1]) && - (ati_remote->old_data[1] == data[2]) && - ((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) { + if ((ati_remote->old_data[0] == data[1]) && + (ati_remote->old_data[1] == data[2]) && + ((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) { ati_remote->repeat_count++; - } - else { + } else { ati_remote->repeat_count = 0; } - + ati_remote->old_data[0] = data[1]; ati_remote->old_data[1] = data[2]; ati_remote->old_jiffies = jiffies; @@ -501,7 +500,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) if ((ati_remote->repeat_count > 0) && (ati_remote->repeat_count < 5)) return; - + input_regs(dev, regs); input_event(dev, ati_remote_tbl[index].type, @@ -511,13 +510,13 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) input_sync(dev); return; - } - - /* + } + + /* * Other event kinds are from the directional control pad, and have an * acceleration factor applied to them. Without this acceleration, the * control pad is mostly unusable. - * + * * If elapsed time since last event is > 1/4 second, user "stopped", * so reset acceleration. Otherwise, user is probably holding the control * pad down, so we increase acceleration, ramping up over two seconds to @@ -559,7 +558,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) input_report_rel(dev, REL_Y, acc); break; default: - dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", + dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", ati_remote_tbl[index].kind); } input_sync(dev); @@ -586,12 +585,12 @@ static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs) case -ESHUTDOWN: dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n", __FUNCTION__); - return; + return; default: /* error */ - dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", + dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", __FUNCTION__, urb->status); } - + retval = usb_submit_urb(urb, SLAB_ATOMIC); if (retval) dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", @@ -614,16 +613,16 @@ static void ati_remote_delete(struct ati_remote *ati_remote) input_unregister_device(&ati_remote->idev); if (ati_remote->inbuf) - usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, + usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, ati_remote->inbuf, ati_remote->inbuf_dma); - + if (ati_remote->outbuf) - usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, + usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, ati_remote->outbuf, ati_remote->outbuf_dma); - + if (ati_remote->irq_urb) usb_free_urb(ati_remote->irq_urb); - + if (ati_remote->out_urb) usb_free_urb(ati_remote->out_urb); @@ -636,21 +635,21 @@ static void ati_remote_input_init(struct ati_remote *ati_remote) int i; idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) | + idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_SIDE) | BIT(BTN_EXTRA) ); idev->relbit[0] = BIT(REL_X) | BIT(REL_Y); for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) if (ati_remote_tbl[i].type == EV_KEY) set_bit(ati_remote_tbl[i].code, idev->keybit); - + idev->private = ati_remote; idev->open = ati_remote_open; idev->close = ati_remote_close; - + idev->name = ati_remote->name; idev->phys = ati_remote->phys; - - idev->id.bustype = BUS_USB; + + idev->id.bustype = BUS_USB; idev->id.vendor = le16_to_cpu(ati_remote->udev->descriptor.idVendor); idev->id.product = le16_to_cpu(ati_remote->udev->descriptor.idProduct); idev->id.version = le16_to_cpu(ati_remote->udev->descriptor.bcdDevice); @@ -660,27 +659,27 @@ static int ati_remote_initialize(struct ati_remote *ati_remote) { struct usb_device *udev = ati_remote->udev; int pipe, maxp; - + init_waitqueue_head(&ati_remote->wait); /* Set up irq_urb */ pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress); maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; - - usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, - maxp, ati_remote_irq_in, ati_remote, + + usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, + maxp, ati_remote_irq_in, ati_remote, ati_remote->endpoint_in->bInterval); ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma; ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - + /* Set up out_urb */ pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress); maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; - usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, - maxp, ati_remote_irq_out, ati_remote, + usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, + maxp, ati_remote_irq_out, ati_remote, ati_remote->endpoint_out->bInterval); ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma; ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -688,11 +687,11 @@ static int ati_remote_initialize(struct ati_remote *ati_remote) /* send initialization strings */ if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) || (ati_remote_sendpacket(ati_remote, 0x8007, init2))) { - dev_err(&ati_remote->interface->dev, + dev_err(&ati_remote->interface->dev, "Initializing ati_remote hardware failed.\n"); return 1; } - + return 0; } @@ -769,7 +768,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de if (!strlen(ati_remote->name)) sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)", - le16_to_cpu(ati_remote->udev->descriptor.idVendor), + le16_to_cpu(ati_remote->udev->descriptor.idVendor), le16_to_cpu(ati_remote->udev->descriptor.idProduct)); /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ @@ -781,11 +780,11 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de ati_remote_input_init(ati_remote); input_register_device(&ati_remote->idev); - dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n", + dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n", ati_remote->name, path); usb_set_intfdata(interface, ati_remote); - + error: if (retval) ati_remote_delete(ati_remote); @@ -808,7 +807,7 @@ static void ati_remote_disconnect(struct usb_interface *interface) warn("%s - null device?\n", __FUNCTION__); return; } - + ati_remote_delete(ati_remote); up(&disconnect_sem); @@ -820,7 +819,7 @@ static void ati_remote_disconnect(struct usb_interface *interface) static int __init ati_remote_init(void) { int result; - + result = usb_register(&ati_remote_driver); if (result) err("usb_register error #%d\n", result); @@ -838,8 +837,8 @@ static void __exit ati_remote_exit(void) usb_deregister(&ati_remote_driver); } -/* - * module specification +/* + * module specification */ module_init(ati_remote_init); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 6bf39656adc7..08e701bc9f64 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -232,7 +232,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign report->size += parser->global.report_size * parser->global.report_count; if (!parser->local.usage_index) /* Ignore padding fields */ - return 0; + return 0; usages = max_t(int, parser->local.usage_index, parser->global.report_count); @@ -1622,7 +1622,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) /* Change the polling interval of mice. */ if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0) interval = hid_mousepoll_interval; - + if (endpoint->bEndpointAddress & USB_DIR_IN) { if (hid->urbin) continue; diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h index 2b91705740a7..52437e5e2e78 100644 --- a/drivers/usb/input/hid-debug.h +++ b/drivers/usb/input/hid-debug.h @@ -67,7 +67,7 @@ static const struct hid_usage_entry hid_usage_table[] = { {0, 0x44, "Vbry"}, {0, 0x45, "Vbrz"}, {0, 0x46, "Vno"}, - {0, 0x80, "SystemControl"}, + {0, 0x80, "SystemControl"}, {0, 0x81, "SystemPowerDown"}, {0, 0x82, "SystemSleep"}, {0, 0x83, "SystemWakeUp"}, @@ -347,7 +347,7 @@ __inline__ static void tab(int n) { static void hid_dump_field(struct hid_field *field, int n) { int j; - + if (field->physical) { tab(n); printk("Physical("); @@ -408,7 +408,7 @@ static void hid_dump_field(struct hid_field *field, int n) { printk("%s", units[sys][i]); if(nibble != 1) { /* This is a _signed_ nibble(!) */ - + int val = nibble & 0x7; if(nibble & 0x08) val = -((0x7 & ~val) +1); @@ -443,7 +443,7 @@ static void __attribute__((unused)) hid_dump_device(struct hid_device *device) { struct list_head *list; unsigned i,k; static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; - + for (i = 0; i < HID_REPORT_TYPES; i++) { report_enum = device->report_enum + i; list = report_enum->report_list.next; @@ -664,8 +664,8 @@ static char *keys[KEY_MAX + 1] = { static char *relatives[REL_MAX + 1] = { [REL_X] = "X", [REL_Y] = "Y", [REL_Z] = "Z", [REL_HWHEEL] = "HWheel", - [REL_DIAL] = "Dial", [REL_WHEEL] = "Wheel", - [REL_MISC] = "Misc", + [REL_DIAL] = "Dial", [REL_WHEEL] = "Wheel", + [REL_MISC] = "Misc", }; static char *absolutes[ABS_MAX + 1] = { @@ -690,9 +690,9 @@ static char *misc[MSC_MAX + 1] = { }; static char *leds[LED_MAX + 1] = { - [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", + [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", - [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", + [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", [LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute", [LED_MISC] = "Misc", }; diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 5553c3553e9d..9ac1e9095334 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -164,7 +164,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case HID_GD_X: case HID_GD_Y: case HID_GD_Z: case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: - if (field->flags & HID_MAIN_ITEM_RELATIVE) + if (field->flags & HID_MAIN_ITEM_RELATIVE) map_rel(usage->hid & 0xf); else map_abs(usage->hid & 0xf); @@ -297,7 +297,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case HID_UP_MSVENDOR: goto ignore; - + case HID_UP_PID: set_bit(EV_FF, input->evbit); @@ -349,7 +349,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel goto ignore; if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) && - (usage->type == EV_REL) && (usage->code == REL_WHEEL)) + (usage->type == EV_REL) && (usage->code == REL_WHEEL)) set_bit(REL_HWHEEL, bit); if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) @@ -365,11 +365,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel a = field->logical_minimum = 0; b = field->logical_maximum = 255; } - + if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK) input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4); else input_set_abs_params(input, usage->code, a, b, 0, 0); - + } if (usage->hat_min < usage->hat_max || usage->hat_dir) { @@ -420,7 +420,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; } - if (usage->hat_min < usage->hat_max || usage->hat_dir) { + if (usage->hat_min < usage->hat_max || usage->hat_dir) { int hat_dir = usage->hat_dir; if (!hat_dir) hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1; @@ -551,7 +551,7 @@ int hidinput_connect(struct hid_device *hid) for (i = 0; i < hid->maxcollection; i++) if (hid->collection[i].type == HID_COLLECTION_APPLICATION || hid->collection[i].type == HID_COLLECTION_PHYSICAL) - if (IS_INPUT_APPLICATION(hid->collection[i].usage)) + if (IS_INPUT_APPLICATION(hid->collection[i].usage)) break; if (i == hid->maxcollection) @@ -592,7 +592,7 @@ int hidinput_connect(struct hid_device *hid) for (j = 0; j < report->field[i]->maxusage; j++) hidinput_configure_usage(hidinput, report->field[i], report->field[i]->usage + j); - + if (hid->quirks & HID_QUIRK_MULTI_INPUT) { /* This will leave hidinput NULL, so that it * allocates another one if we have more inputs on diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index 0d7404bab92f..0c4c77aa31ea 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -94,7 +94,7 @@ struct lgff_device { isn't really necessary */ unsigned long flags[1]; /* Contains various information about the - state of the driver for this device */ + state of the driver for this device */ struct timer_list timer; }; @@ -234,7 +234,7 @@ static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report) kfree(ret); return NULL; } - memset(ret->field[0]->value, 0, sizeof(s32[8])); + memset(ret->field[0]->value, 0, sizeof(s32[8])); return ret; } @@ -295,11 +295,11 @@ static int hid_lgff_event(struct hid_device *hid, struct input_dev* input, unsigned long flags; if (type != EV_FF) return -EINVAL; - if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES; + if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES; if (value < 0) return -EINVAL; spin_lock_irqsave(&lgff->lock, flags); - + if (value > 0) { if (test_bit(EFFECT_STARTED, effect->flags)) { spin_unlock_irqrestore(&lgff->lock, flags); @@ -345,7 +345,7 @@ static int hid_lgff_flush(struct input_dev *dev, struct file *file) and perform ioctls on the same fd all at the same time */ if ( current->pid == lgff->effects[i].owner && test_bit(EFFECT_USED, lgff->effects[i].flags)) { - + if (hid_lgff_erase(dev, i)) warn("erase effect %d failed", i); } @@ -378,7 +378,7 @@ static int hid_lgff_upload_effect(struct input_dev* input, struct lgff_effect new; int id; unsigned long flags; - + dbg("ioctl rumble"); if (!test_bit(effect->type, input->ffbit)) return -EINVAL; @@ -441,7 +441,7 @@ static void hid_lgff_timer(unsigned long timer_data) spin_lock_irqsave(&lgff->lock, flags); - for (i=0; ieffects +i; if (test_bit(EFFECT_PLAYING, effect->flags)) { @@ -491,7 +491,7 @@ static void hid_lgff_timer(unsigned long timer_data) set_bit(EFFECT_PLAYING, lgff->effects[i].flags); } } - } + } #define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff @@ -524,5 +524,5 @@ static void hid_lgff_timer(unsigned long timer_data) add_timer(&lgff->timer); } - spin_unlock_irqrestore(&lgff->lock, flags); + spin_unlock_irqrestore(&lgff->lock, flags); } diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 6d9329c698d9..c1b6b69bc4a4 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -118,7 +118,7 @@ struct hid_item { #define HID_MAIN_ITEM_CONSTANT 0x001 #define HID_MAIN_ITEM_VARIABLE 0x002 #define HID_MAIN_ITEM_RELATIVE 0x004 -#define HID_MAIN_ITEM_WRAP 0x008 +#define HID_MAIN_ITEM_WRAP 0x008 #define HID_MAIN_ITEM_NONLINEAR 0x010 #define HID_MAIN_ITEM_NO_PREFERRED 0x020 #define HID_MAIN_ITEM_NULL_STATE 0x040 @@ -172,14 +172,14 @@ struct hid_item { #define HID_USAGE_PAGE 0xffff0000 #define HID_UP_UNDEFINED 0x00000000 -#define HID_UP_GENDESK 0x00010000 -#define HID_UP_KEYBOARD 0x00070000 -#define HID_UP_LED 0x00080000 -#define HID_UP_BUTTON 0x00090000 -#define HID_UP_ORDINAL 0x000a0000 +#define HID_UP_GENDESK 0x00010000 +#define HID_UP_KEYBOARD 0x00070000 +#define HID_UP_LED 0x00080000 +#define HID_UP_BUTTON 0x00090000 +#define HID_UP_ORDINAL 0x000a0000 #define HID_UP_CONSUMER 0x000c0000 -#define HID_UP_DIGITIZER 0x000d0000 -#define HID_UP_PID 0x000f0000 +#define HID_UP_DIGITIZER 0x000d0000 +#define HID_UP_PID 0x000f0000 #define HID_UP_HPVENDOR 0xff7f0000 #define HID_UP_MSVENDOR 0xff000000 @@ -406,7 +406,7 @@ struct hid_device { /* device report descriptor */ dma_addr_t outbuf_dma; /* Output buffer dma */ spinlock_t outlock; /* Output fifo spinlock */ - unsigned claimed; /* Claimed by hidinput, hiddev? */ + unsigned claimed; /* Claimed by hidinput, hiddev? */ unsigned quirks; /* Various quirks the device can pull on us */ struct list_head inputs; /* The list of inputs */ diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 96b7c9067951..4c13331b5f41 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -95,7 +95,7 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) return NULL; rinfo->report_id = ((struct hid_report *) list)->id; break; - + case HID_REPORT_ID_NEXT: list = (struct list_head *) report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK]; @@ -106,7 +106,7 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) return NULL; rinfo->report_id = ((struct hid_report *) list)->id; break; - + default: return NULL; } @@ -158,7 +158,7 @@ static void hiddev_send_event(struct hid_device *hid, if (uref->field_index != HID_FIELD_INDEX_NONE || (list->flags & HIDDEV_FLAG_REPORT) != 0) { list->buffer[list->head] = *uref; - list->head = (list->head + 1) & + list->head = (list->head + 1) & (HIDDEV_BUFFER_SIZE - 1); kill_fasync(&list->fasync, SIGIO, POLL_IN); } @@ -179,9 +179,9 @@ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, unsigned type = field->report_type; struct hiddev_usage_ref uref; - uref.report_type = + uref.report_type = (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : - ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : + ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); uref.report_id = field->report->id; uref.field_index = field->index; @@ -199,9 +199,9 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report) struct hiddev_usage_ref uref; memset(&uref, 0, sizeof(uref)); - uref.report_type = + uref.report_type = (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : - ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : + ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); uref.report_id = report->id; uref.field_index = HID_FIELD_INDEX_NONE; @@ -236,7 +236,7 @@ static int hiddev_release(struct inode * inode, struct file * file) *listptr = (*listptr)->next; if (!--list->hiddev->open) { - if (list->hiddev->exist) + if (list->hiddev->exist) hid_close(list->hiddev->hid); else kfree(list->hiddev); @@ -303,7 +303,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun if (list->head == list->tail) { add_wait_queue(&list->hiddev->wait, &wait); set_current_state(TASK_INTERRUPTIBLE); - + while (list->head == list->tail) { if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; @@ -317,7 +317,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun retval = -EIO; break; } - + schedule(); } @@ -329,7 +329,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun return retval; - while (list->head != list->tail && + while (list->head != list->tail && retval + event_size <= count) { if ((list->flags & HIDDEV_FLAG_UREF) == 0) { if (list->buffer[list->tail].field_index != @@ -405,10 +405,10 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd return -EINVAL; for (i = 0; i < hid->maxcollection; i++) - if (hid->collection[i].type == + if (hid->collection[i].type == HID_COLLECTION_APPLICATION && arg-- == 0) break; - + if (i == hid->maxcollection) return -EINVAL; @@ -562,7 +562,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd if (!uref_multi) return -ENOMEM; uref = &uref_multi->uref; - if (copy_from_user(uref, user_arg, sizeof(*uref))) + if (copy_from_user(uref, user_arg, sizeof(*uref))) goto fault; rinfo.report_type = uref->report_type; @@ -595,7 +595,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd return -ENOMEM; uref = &uref_multi->uref; if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (copy_from_user(uref_multi, user_arg, + if (copy_from_user(uref_multi, user_arg, sizeof(*uref_multi))) goto fault; } else { @@ -603,7 +603,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd goto fault; } - if (cmd != HIDIOCGUSAGE && + if (cmd != HIDIOCGUSAGE && cmd != HIDIOCGUSAGES && uref->report_type == HID_REPORT_TYPE_INPUT) goto inval; @@ -651,16 +651,16 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd return field->usage[uref->usage_index].collection_index; case HIDIOCGUSAGES: for (i = 0; i < uref_multi->num_values; i++) - uref_multi->values[i] = + uref_multi->values[i] = field->value[uref->usage_index + i]; - if (copy_to_user(user_arg, uref_multi, + if (copy_to_user(user_arg, uref_multi, sizeof(*uref_multi))) goto fault; goto goodreturn; case HIDIOCSUSAGES: for (i = 0; i < uref_multi->num_values; i++) - field->value[uref->usage_index + i] = - uref_multi->values[i]; + field->value[uref->usage_index + i] = + uref_multi->values[i]; goto goodreturn; } @@ -670,7 +670,7 @@ goodreturn: fault: kfree(uref_multi); return -EFAULT; -inval: +inval: kfree(uref_multi); return -EINVAL; @@ -734,7 +734,7 @@ static struct usb_class_driver hiddev_class = { .name = "usb/hid/hiddev%d", .fops = &hiddev_fops, .mode = S_IFCHR | S_IRUGO | S_IWUSR, - .minor_base = HIDDEV_MINOR_BASE, + .minor_base = HIDDEV_MINOR_BASE, }; /* @@ -747,7 +747,7 @@ int hiddev_connect(struct hid_device *hid) int retval; for (i = 0; i < hid->maxcollection; i++) - if (hid->collection[i].type == + if (hid->collection[i].type == HID_COLLECTION_APPLICATION && !IS_INPUT_APPLICATION(hid->collection[i].usage)) break; @@ -755,11 +755,11 @@ int hiddev_connect(struct hid_device *hid) if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0) return -1; - if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL))) + if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL))) return -1; memset(hiddev, 0, sizeof(struct hiddev)); - retval = usb_register_dev(hid->intf, &hiddev_class); + retval = usb_register_dev(hid->intf, &hiddev_class); if (retval) { err("Not able to get a minor for this device."); kfree(hiddev); @@ -768,12 +768,12 @@ int hiddev_connect(struct hid_device *hid) init_waitqueue_head(&hiddev->wait); - hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; + hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; hiddev->hid = hid; hiddev->exist = 1; - hid->minor = hid->intf->minor; + hid->minor = hid->intf->minor; hid->hiddev = hiddev; return 0; @@ -818,7 +818,7 @@ void hiddev_disconnect(struct hid_device *hid) /* We never attach in this manner, and rely on HID to connect us. This * is why there is no disconnect routine defined in the usb_driver either. */ -static int hiddev_usbd_probe(struct usb_interface *intf, +static int hiddev_usbd_probe(struct usb_interface *intf, const struct usb_device_id *hiddev_info) { return -ENODEV; diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c index 4c27c104f63e..5122a7f701a9 100644 --- a/drivers/usb/input/itmtouch.c +++ b/drivers/usb/input/itmtouch.c @@ -18,14 +18,14 @@ * Based upon original work by Chris Collins . * * Kudos to ITM for providing me with the datasheet for the panel, - * even though it was a day later than I had finished writing this + * even though it was a day later than I had finished writing this * driver. - * + * * It has meant that I've been able to correct my interpretation of the * protocol packets however. - * + * * CC -- 2003/9/29 - * + * * History * 1.0 & 1.1 2003 (CC) vojtech@suse.cz * Original version for 2.4.x kernels @@ -33,10 +33,10 @@ * 1.2 02/03/2005 (HCE) hc@mivu.no * Complete rewrite to support Linux 2.6.10, thanks to mtouchusb.c for hints. * Unfortunately no calibration support at this time. - * + * * 1.2.1 09/03/2005 (HCE) hc@mivu.no * Code cleanup and adjusting syntax to start matching kernel standards - * + * *****************************************************************************/ #include @@ -71,7 +71,7 @@ MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE( DRIVER_LICENSE ); struct itmtouch_dev { - struct usb_device *usbdev; /* usb device */ + struct usb_device *usbdev; /* usb device */ struct input_dev inputdev; /* input device */ struct urb *readurb; /* urb */ char rbuf[ITM_BUFSIZE]; /* data */ @@ -121,7 +121,7 @@ static void itmtouch_irq(struct urb *urb, struct pt_regs *regs) input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F)); input_report_abs(dev, ABS_Y, (data[1] & 0x1F) << 7 | (data[4] & 0x7F)); } - + input_report_abs(dev, ABS_PRESSURE, (data[2] & 1) << 7 | (data[5] & 0x7F)); input_report_key(dev, BTN_TOUCH, ~data[7] & 0x20); input_sync(dev); @@ -142,8 +142,7 @@ static int itmtouch_open(struct input_dev *input) itmtouch->readurb->dev = itmtouch->usbdev; - if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL)) - { + if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL)) { itmtouch->users--; return -EIO; } @@ -178,13 +177,13 @@ static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id } itmtouch->usbdev = udev; - + itmtouch->inputdev.private = itmtouch; itmtouch->inputdev.open = itmtouch_open; itmtouch->inputdev.close = itmtouch_close; usb_make_path(udev, path, PATH_SIZE); - + itmtouch->inputdev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); itmtouch->inputdev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); itmtouch->inputdev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); @@ -194,12 +193,12 @@ static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id itmtouch->inputdev.id.bustype = BUS_USB; itmtouch->inputdev.id.vendor = udev->descriptor.idVendor; itmtouch->inputdev.id.product = udev->descriptor.idProduct; - itmtouch->inputdev.id.version = udev->descriptor.bcdDevice; + itmtouch->inputdev.id.version = udev->descriptor.bcdDevice; itmtouch->inputdev.dev = &intf->dev; if (!strlen(itmtouch->name)) sprintf(itmtouch->name, "USB ITM touchscreen"); - + /* device limits */ /* as specified by the ITM datasheet, X and Y are 12bit, * Z (pressure) is 8 bit. However, the fields are defined up @@ -212,26 +211,20 @@ static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id /* initialise the URB so we can read from the transport stream */ pipe = usb_rcvintpipe(itmtouch->usbdev, endpoint->bEndpointAddress); maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); - + if (maxp > ITM_BUFSIZE) maxp = ITM_BUFSIZE; itmtouch->readurb = usb_alloc_urb(0, GFP_KERNEL); - + if (!itmtouch->readurb) { dbg("%s - usb_alloc_urb failed: itmtouch->readurb", __FUNCTION__); kfree(itmtouch); return -ENOMEM; } - - usb_fill_int_urb(itmtouch->readurb, - itmtouch->usbdev, - pipe, - itmtouch->rbuf, - maxp, - itmtouch_irq, - itmtouch, - endpoint->bInterval); + + usb_fill_int_urb(itmtouch->readurb, itmtouch->usbdev, pipe, itmtouch->rbuf, + maxp, itmtouch_irq, itmtouch, endpoint->bInterval); input_register_device(&itmtouch->inputdev); @@ -242,7 +235,7 @@ static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id } static void itmtouch_disconnect(struct usb_interface *intf) -{ +{ struct itmtouch_dev *itmtouch = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); @@ -258,11 +251,11 @@ static void itmtouch_disconnect(struct usb_interface *intf) MODULE_DEVICE_TABLE(usb, itmtouch_ids); static struct usb_driver itmtouch_driver = { - .owner = THIS_MODULE, - .name = "itmtouch", - .probe = itmtouch_probe, - .disconnect = itmtouch_disconnect, - .id_table = itmtouch_ids, + .owner = THIS_MODULE, + .name = "itmtouch", + .probe = itmtouch_probe, + .disconnect = itmtouch_disconnect, + .id_table = itmtouch_ids, }; static int __init itmtouch_init(void) diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index a68c5b4e7b37..fff5753b16ca 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c @@ -79,12 +79,12 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs) /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/ input_report_key(dev, BTN_RIGHT, data[0] & 0x02); - if( -1 == kb_pressure_click){ + if (-1 == kb_pressure_click) { input_report_abs(dev, ABS_PRESSURE, kbtab->pressure); } else { input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0); }; - + input_sync(dev); exit: @@ -161,7 +161,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i kbtab->dev.absmax[ABS_X] = 0x2000; kbtab->dev.absmax[ABS_Y] = 0x1750; kbtab->dev.absmax[ABS_PRESSURE] = 0xff; - + kbtab->dev.absfuzz[ABS_X] = 4; kbtab->dev.absfuzz[ABS_Y] = 4; diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c index 7fa2f9b9fb69..3975b309d55f 100644 --- a/drivers/usb/input/powermate.c +++ b/drivers/usb/input/powermate.c @@ -10,7 +10,7 @@ * back to the host when polled by the USB controller. * * Testing with the knob I have has shown that it measures approximately 94 "clicks" - * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was + * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was * a variable speed cordless electric drill) has shown that the device can measure * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from * the host. If it counts more than 7 clicks before it is polled, it will wrap back @@ -120,9 +120,9 @@ exit: /* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */ static void powermate_sync_state(struct powermate_device *pm) { - if (pm->requires_update == 0) + if (pm->requires_update == 0) return; /* no updates are required */ - if (pm->config->status == -EINPROGRESS) + if (pm->config->status == -EINPROGRESS) return; /* an update is already in progress; it'll issue this update when it completes */ if (pm->requires_update & UPDATE_PULSE_ASLEEP){ @@ -142,7 +142,7 @@ static void powermate_sync_state(struct powermate_device *pm) 2: multiply the speed the argument only has an effect for operations 0 and 2, and ranges between 1 (least effect) to 255 (maximum effect). - + thus, several states are equivalent and are coalesced into one state. we map this onto a range from 0 to 510, with: @@ -151,7 +151,7 @@ static void powermate_sync_state(struct powermate_device *pm) 256 -- 510 -- use multiple (510 = fastest). Only values of 'arg' quite close to 255 are particularly useful/spectacular. - */ + */ if (pm->pulse_speed < 255){ op = 0; // divide arg = 255 - pm->pulse_speed; @@ -199,14 +199,14 @@ static void powermate_config_complete(struct urb *urb, struct pt_regs *regs) if (urb->status) printk(KERN_ERR "powermate: config urb returned %d\n", urb->status); - + spin_lock_irqsave(&pm->lock, flags); powermate_sync_state(pm); spin_unlock_irqrestore(&pm->lock, flags); } /* Set the LED up as described and begin the sync with the hardware if required */ -static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, +static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, int pulse_table, int pulse_asleep, int pulse_awake) { unsigned long flags; @@ -229,7 +229,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne /* mark state updates which are required */ if (static_brightness != pm->static_brightness){ pm->static_brightness = static_brightness; - pm->requires_update |= UPDATE_STATIC_BRIGHTNESS; + pm->requires_update |= UPDATE_STATIC_BRIGHTNESS; } if (pulse_asleep != pm->pulse_asleep){ pm->pulse_asleep = pulse_asleep; @@ -246,7 +246,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne } powermate_sync_state(pm); - + spin_unlock_irqrestore(&pm->lock, flags); } @@ -257,19 +257,19 @@ static int powermate_input_event(struct input_dev *dev, unsigned int type, unsig struct powermate_device *pm = dev->private; if (type == EV_MSC && code == MSC_PULSELED){ - /* + /* bits 0- 7: 8 bits: LED brightness bits 8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster. bits 17-18: 2 bits: pulse table (0, 1, 2 valid) bit 19: 1 bit : pulse whilst asleep? bit 20: 1 bit : pulse constantly? - */ + */ int static_brightness = command & 0xFF; // bits 0-7 int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16 int pulse_table = (command >> 17) & 0x3; // bits 17-18 int pulse_asleep = (command >> 19) & 0x1; // bit 19 int pulse_awake = (command >> 20) & 0x1; // bit 20 - + powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake); } @@ -378,7 +378,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i switch (le16_to_cpu(udev->descriptor.idProduct)) { case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break; case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break; - default: + default: pm->input.name = pm_name_soundknob; printk(KERN_WARNING "powermate: unknown product id %04x\n", le16_to_cpu(udev->descriptor.idProduct)); @@ -402,11 +402,11 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i usb_make_path(udev, path, 64); snprintf(pm->phys, 64, "%s/input0", path); printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.phys); - + /* force an update of everything */ pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS; powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters - + usb_set_intfdata(intf, pm); return 0; } diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index 7038fb9d1ced..255b47a517b1 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -9,18 +9,18 @@ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -166,7 +166,7 @@ static void usb_kbd_led(struct urb *urb, struct pt_regs *regs) if (urb->status) warn("led urb status %d received", urb->status); - + if (*(kbd->leds) == kbd->newleds) return; @@ -230,7 +230,7 @@ static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd) usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma); } -static int usb_kbd_probe(struct usb_interface *iface, +static int usb_kbd_probe(struct usb_interface *iface, const struct usb_device_id *id) { struct usb_device * dev = interface_to_usbdev(iface); @@ -272,7 +272,7 @@ static int usb_kbd_probe(struct usb_interface *iface, for (i = 0; i < 255; i++) set_bit(usb_kbd_keycode[i], kbd->dev.keybit); clear_bit(0, kbd->dev.keybit); - + kbd->dev.private = kbd; kbd->dev.event = usb_kbd_event; kbd->dev.open = usb_kbd_open; @@ -294,7 +294,7 @@ static int usb_kbd_probe(struct usb_interface *iface, sprintf(kbd->phys, "%s/input0", path); kbd->dev.name = kbd->name; - kbd->dev.phys = kbd->phys; + kbd->dev.phys = kbd->phys; kbd->dev.id.bustype = BUS_USB; kbd->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor); kbd->dev.id.product = le16_to_cpu(dev->descriptor.idProduct); @@ -329,7 +329,7 @@ static int usb_kbd_probe(struct usb_interface *iface, static void usb_kbd_disconnect(struct usb_interface *intf) { struct usb_kbd *kbd = usb_get_intfdata (intf); - + usb_set_intfdata(intf, NULL); if (kbd) { usb_kill_urb(kbd->irq); diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index 01155bbddd43..8ca2811fd174 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c @@ -9,18 +9,18 @@ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic @@ -132,19 +132,19 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_ interface = intf->cur_altsetting; - if (interface->desc.bNumEndpoints != 1) + if (interface->desc.bNumEndpoints != 1) return -ENODEV; endpoint = &interface->endpoint[0].desc; - if (!(endpoint->bEndpointAddress & 0x80)) + if (!(endpoint->bEndpointAddress & 0x80)) return -ENODEV; - if ((endpoint->bmAttributes & 3) != 3) + if ((endpoint->bmAttributes & 3) != 3) return -ENODEV; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) + if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return -ENOMEM; memset(mouse, 0, sizeof(struct usb_mouse)); @@ -209,7 +209,7 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_ static void usb_mouse_disconnect(struct usb_interface *intf) { struct usb_mouse *mouse = usb_get_intfdata (intf); - + usb_set_intfdata(intf, NULL); if (mouse) { usb_kill_urb(mouse->irq); @@ -238,7 +238,7 @@ static struct usb_driver usb_mouse_driver = { static int __init usb_mouse_init(void) { int retval = usb_register(&usb_mouse_driver); - if (retval == 0) + if (retval == 0) info(DRIVER_VERSION ":" DRIVER_DESC); return retval; } diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index fec04dda088e..b3420e12ae4f 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -18,7 +18,7 @@ * v0.4 (sm) - Support for more Intuos models, menustrip * relative mode, proximity. * v0.5 (vp) - Big cleanup, nifty features removed, - * they belong in userspace + * they belong in userspace * v1.8 (vp) - Submit URB only when operating, moved to CVS, * use input_report_key instead of report_btn and * other cleanups @@ -149,7 +149,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs) prox = data[1] & 0x40; input_regs(dev, regs); - + if (prox) { pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); @@ -545,7 +545,7 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) /* process general packets */ wacom_intuos_general(urb); - + if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) { /* 4D mouse or Lens cursor packets */ if (data[1] & 0x02) { /* Rotation packet */ @@ -555,7 +555,7 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) } else { - if ((data[1] & 0x10) == 0) { /* 4D mouse packets */ + if ((data[1] & 0x10) == 0) { /* 4D mouse packets */ input_report_key(dev, BTN_LEFT, data[8] & 0x01); input_report_key(dev, BTN_MIDDLE, data[8] & 0x02); @@ -567,11 +567,11 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t); } else { - if (wacom->tool[idx] == BTN_TOOL_MOUSE) { /* 2D mouse packets */ + if (wacom->tool[idx] == BTN_TOOL_MOUSE) { /* 2D mouse packets */ input_report_key(dev, BTN_LEFT, data[8] & 0x04); input_report_key(dev, BTN_MIDDLE, data[8] & 0x08); input_report_key(dev, BTN_RIGHT, data[8] & 0x10); - input_report_rel(dev, REL_WHEEL, + input_report_rel(dev, REL_WHEEL, (-(__u32)(data[8] & 0x01) + (__u32)((data[8] & 0x02) >> 1))); } else { /* Lens cursor packets */ @@ -584,7 +584,7 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) } } } - + input_report_key(dev, wacom->tool[idx], 1); input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); input_sync(dev); @@ -705,20 +705,20 @@ static struct wacom_features wacom_features[] = { { "Wacom Penpartner", 7, 5040, 3780, 255, 32, 0, wacom_penpartner_irq }, { "Wacom Graphire", 8, 10206, 7422, 511, 32, 1, wacom_graphire_irq }, { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, 1, wacom_graphire_irq }, - { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, 1, wacom_graphire_irq }, + { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, 1, wacom_graphire_irq }, { "Wacom Graphire3", 8, 10208, 7424, 511, 32, 1, wacom_graphire_irq }, { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, 1, wacom_graphire_irq }, - { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom PL400", 8, 5408, 4056, 255, 32, 3, wacom_pl_irq }, - { "Wacom PL500", 8, 6144, 4608, 255, 32, 3, wacom_pl_irq }, - { "Wacom PL600", 8, 6126, 4604, 255, 32, 3, wacom_pl_irq }, - { "Wacom PL600SX", 8, 6260, 5016, 255, 32, 3, wacom_pl_irq }, - { "Wacom PL550", 8, 6144, 4608, 511, 32, 3, wacom_pl_irq }, - { "Wacom PL800", 8, 7220, 5780, 511, 32, 3, wacom_pl_irq }, + { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom PL400", 8, 5408, 4056, 255, 32, 3, wacom_pl_irq }, + { "Wacom PL500", 8, 6144, 4608, 255, 32, 3, wacom_pl_irq }, + { "Wacom PL600", 8, 6126, 4604, 255, 32, 3, wacom_pl_irq }, + { "Wacom PL600SX", 8, 6260, 5016, 255, 32, 3, wacom_pl_irq }, + { "Wacom PL550", 8, 6144, 4608, 511, 32, 3, wacom_pl_irq }, + { "Wacom PL800", 8, 7220, 5780, 511, 32, 3, wacom_pl_irq }, { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq }, @@ -730,7 +730,7 @@ static struct wacom_features wacom_features[] = { { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, 4, wacom_intuos3_irq }, { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, 4, wacom_intuos3_irq }, { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, - { } + { } }; static struct usb_device_id wacom_ids[] = { @@ -828,7 +828,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i wacom->dev.relbit[0] |= BIT(REL_WHEEL); wacom->dev.absbit[0] |= BIT(ABS_DISTANCE); wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2); + wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2); break; case 4: /* new functions for Intuos3 */ @@ -842,13 +842,13 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i wacom->dev.mscbit[0] |= BIT(MSC_SERIAL); wacom->dev.relbit[0] |= BIT(REL_WHEEL); wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH) + wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2); wacom->dev.absbit[0] |= BIT(ABS_DISTANCE) | BIT(ABS_WHEEL) | BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE); break; case 3: - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER); + wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER); break; } diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index d65edb22e545..a8076ccc0b2e 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c @@ -104,11 +104,11 @@ MODULE_DEVICE_TABLE (usb, xpad_table); struct usb_xpad { struct input_dev dev; /* input device interface */ struct usb_device *udev; /* usb device */ - + struct urb *irq_in; /* urb for interrupt in report */ unsigned char *idata; /* input data */ dma_addr_t idata_dma; - + char phys[65]; /* physical device path */ int open_count; /* reference count */ }; @@ -128,35 +128,35 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d struct input_dev *dev = &xpad->dev; input_regs(dev, regs); - + /* left stick */ input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12])); input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14])); - + /* right stick */ input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16])); input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18])); - + /* triggers left/right */ input_report_abs(dev, ABS_Z, data[10]); input_report_abs(dev, ABS_RZ, data[11]); - + /* digital pad */ input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); - + /* start/back buttons and stick press left/right */ input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4); input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5); input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6); input_report_key(dev, BTN_THUMBR, data[2] >> 7); - + /* "analog" buttons A, B, X, Y */ input_report_key(dev, BTN_A, data[4]); input_report_key(dev, BTN_B, data[5]); input_report_key(dev, BTN_X, data[6]); input_report_key(dev, BTN_Y, data[7]); - + /* "analog" buttons black, white */ input_report_key(dev, BTN_C, data[8]); input_report_key(dev, BTN_Z, data[9]); @@ -168,7 +168,7 @@ static void xpad_irq_in(struct urb *urb, struct pt_regs *regs) { struct usb_xpad *xpad = urb->context; int retval; - + switch (urb->status) { case 0: /* success */ @@ -183,7 +183,7 @@ static void xpad_irq_in(struct urb *urb, struct pt_regs *regs) dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); goto exit; } - + xpad_process_packet(xpad, 0, xpad->idata, regs); exit: @@ -196,23 +196,23 @@ exit: static int xpad_open (struct input_dev *dev) { struct usb_xpad *xpad = dev->private; - + if (xpad->open_count++) return 0; - + xpad->irq_in->dev = xpad->udev; if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) { xpad->open_count--; return -EIO; } - + return 0; } static void xpad_close (struct input_dev *dev) { struct usb_xpad *xpad = dev->private; - + if (!--xpad->open_count) usb_kill_urb(xpad->irq_in); } @@ -224,19 +224,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id struct usb_endpoint_descriptor *ep_irq_in; char path[64]; int i; - + for (i = 0; xpad_device[i].idVendor; i++) { if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) && (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct)) break; } - + if ((xpad = kmalloc (sizeof(struct usb_xpad), GFP_KERNEL)) == NULL) { err("cannot allocate memory for new pad"); return -ENOMEM; } memset(xpad, 0, sizeof(struct usb_xpad)); - + xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN, SLAB_ATOMIC, &xpad->idata_dma); if (!xpad->idata) { @@ -251,18 +251,18 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id kfree(xpad); return -ENOMEM; } - + ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; - + usb_fill_int_urb(xpad->irq_in, udev, usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), xpad->idata, XPAD_PKT_LEN, xpad_irq_in, xpad, ep_irq_in->bInterval); xpad->irq_in->transfer_dma = xpad->idata_dma; xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - + xpad->udev = udev; - + xpad->dev.id.bustype = BUS_USB; xpad->dev.id.vendor = le16_to_cpu(udev->descriptor.idVendor); xpad->dev.id.product = le16_to_cpu(udev->descriptor.idProduct); @@ -273,21 +273,21 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->dev.phys = xpad->phys; xpad->dev.open = xpad_open; xpad->dev.close = xpad_close; - + usb_make_path(udev, path, 64); snprintf(xpad->phys, 64, "%s/input0", path); - + xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - + for (i = 0; xpad_btn[i] >= 0; i++) set_bit(xpad_btn[i], xpad->dev.keybit); - + for (i = 0; xpad_abs[i] >= 0; i++) { - + signed short t = xpad_abs[i]; - + set_bit(t, xpad->dev.absbit); - + switch (t) { case ABS_X: case ABS_Y: @@ -310,11 +310,11 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id break; } } - + input_register_device(&xpad->dev); - + printk(KERN_INFO "input: %s on %s", xpad->dev.name, path); - + usb_set_intfdata(intf, xpad); return 0; } @@ -322,7 +322,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id static void xpad_disconnect(struct usb_interface *intf) { struct usb_xpad *xpad = usb_get_intfdata (intf); - + usb_set_intfdata(intf, NULL); if (xpad) { usb_kill_urb(xpad->irq_in); -- cgit v1.2.3 From 8baf9ed400a0ff7ee21ccd8b2e086aa61c00add5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 29 May 2005 02:29:08 -0500 Subject: Input: mtouchusb was indented with spaces instead of tabs, pass through Lindent and adjust results. Signed-off-by: Dmitry Torokhov --- drivers/usb/input/mtouchusb.c | 415 ++++++++++++++++++++---------------------- 1 file changed, 201 insertions(+), 214 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index ab1a2a30ce7c..ec1dd6278f7b 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c @@ -42,9 +42,9 @@ #include #ifdef CONFIG_USB_DEBUG - #define DEBUG + #define DEBUG #else - #undef DEBUG + #undef DEBUG #endif #include @@ -93,275 +93,262 @@ module_param(raw_coordinates, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(raw_coordinates, "report raw coordinate values (y, default) or hardware-calibrated coordinate values (n)"); struct mtouch_usb { - unsigned char *data; - dma_addr_t data_dma; - struct urb *irq; - struct usb_device *udev; - struct input_dev input; - int open; - char name[128]; - char phys[64]; + unsigned char *data; + dma_addr_t data_dma; + struct urb *irq; + struct usb_device *udev; + struct input_dev input; + int open; + char name[128]; + char phys[64]; }; -static struct usb_device_id mtouchusb_devices [] = { - { USB_DEVICE(0x0596, 0x0001) }, - { } +static struct usb_device_id mtouchusb_devices[] = { + { USB_DEVICE(0x0596, 0x0001) }, + { } }; static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs) { - struct mtouch_usb *mtouch = urb->context; - int retval; - - switch (urb->status) { - case 0: - /* success */ - break; - case -ETIMEDOUT: - /* this urb is timing out */ - dbg("%s - urb timed out - was the device unplugged?", - __FUNCTION__); - return; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __FUNCTION__, urb->status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __FUNCTION__, urb->status); - goto exit; - } - - input_regs(&mtouch->input, regs); - input_report_key(&mtouch->input, BTN_TOUCH, - MTOUCHUSB_GET_TOUCHED(mtouch->data)); - input_report_abs(&mtouch->input, ABS_X, - MTOUCHUSB_GET_XC(mtouch->data)); - input_report_abs(&mtouch->input, ABS_Y, + struct mtouch_usb *mtouch = urb->context; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ETIMEDOUT: + /* this urb is timing out */ + dbg("%s - urb timed out - was the device unplugged?", + __FUNCTION__); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + input_regs(&mtouch->input, regs); + input_report_key(&mtouch->input, BTN_TOUCH, + MTOUCHUSB_GET_TOUCHED(mtouch->data)); + input_report_abs(&mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data)); + input_report_abs(&mtouch->input, ABS_Y, (raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC) - - MTOUCHUSB_GET_YC(mtouch->data)); - input_sync(&mtouch->input); + - MTOUCHUSB_GET_YC(mtouch->data)); + input_sync(&mtouch->input); exit: - retval = usb_submit_urb (urb, GFP_ATOMIC); - if (retval) - err ("%s - usb_submit_urb failed with result: %d", - __FUNCTION__, retval); + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err("%s - usb_submit_urb failed with result: %d", + __FUNCTION__, retval); } -static int mtouchusb_open (struct input_dev *input) +static int mtouchusb_open(struct input_dev *input) { - struct mtouch_usb *mtouch = input->private; + struct mtouch_usb *mtouch = input->private; - if (mtouch->open++) - return 0; + if (mtouch->open++) + return 0; - mtouch->irq->dev = mtouch->udev; + mtouch->irq->dev = mtouch->udev; - if (usb_submit_urb (mtouch->irq, GFP_ATOMIC)) { - mtouch->open--; - return -EIO; - } + if (usb_submit_urb(mtouch->irq, GFP_ATOMIC)) { + mtouch->open--; + return -EIO; + } - return 0; + return 0; } -static void mtouchusb_close (struct input_dev *input) +static void mtouchusb_close(struct input_dev *input) { - struct mtouch_usb *mtouch = input->private; + struct mtouch_usb *mtouch = input->private; - if (!--mtouch->open) - usb_kill_urb (mtouch->irq); + if (!--mtouch->open) + usb_kill_urb(mtouch->irq); } static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) { - dbg("%s - called", __FUNCTION__); + dbg("%s - called", __FUNCTION__); - mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE, - SLAB_ATOMIC, &mtouch->data_dma); + mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE, + SLAB_ATOMIC, &mtouch->data_dma); - if (!mtouch->data) - return -1; + if (!mtouch->data) + return -1; - return 0; + return 0; } static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) { - dbg("%s - called", __FUNCTION__); + dbg("%s - called", __FUNCTION__); - if (mtouch->data) - usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE, - mtouch->data, mtouch->data_dma); + if (mtouch->data) + usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE, + mtouch->data, mtouch->data_dma); } static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct mtouch_usb *mtouch; - struct usb_host_interface *interface; - struct usb_endpoint_descriptor *endpoint; - struct usb_device *udev = interface_to_usbdev (intf); - char path[64]; - int nRet; - - dbg("%s - called", __FUNCTION__); - - dbg("%s - setting interface", __FUNCTION__); - interface = intf->cur_altsetting; - - dbg("%s - setting endpoint", __FUNCTION__); - endpoint = &interface->endpoint[0].desc; - - if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) { - err("%s - Out of memory.", __FUNCTION__); - return -ENOMEM; - } - - memset(mtouch, 0, sizeof(struct mtouch_usb)); - mtouch->udev = udev; - - dbg("%s - allocating buffers", __FUNCTION__); - if (mtouchusb_alloc_buffers(udev, mtouch)) { - mtouchusb_free_buffers(udev, mtouch); - kfree(mtouch); - return -ENOMEM; - } - - mtouch->input.private = mtouch; - mtouch->input.open = mtouchusb_open; - mtouch->input.close = mtouchusb_close; - - usb_make_path(udev, path, 64); - sprintf(mtouch->phys, "%s/input0", path); - - mtouch->input.name = mtouch->name; - mtouch->input.phys = mtouch->phys; - mtouch->input.id.bustype = BUS_USB; - mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor); - mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct); - mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice); - mtouch->input.dev = &intf->dev; - - mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - - /* Used to Scale Compensated Data and Flip Y */ - mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC; - mtouch->input.absmax[ABS_X] = raw_coordinates ? \ - MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC; - mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ; - mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT; - mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC; - mtouch->input.absmax[ABS_Y] = raw_coordinates ? \ - MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC; - mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ; - mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT; + struct mtouch_usb *mtouch; + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = interface_to_usbdev(intf); + char path[64]; + int nRet; + + dbg("%s - called", __FUNCTION__); + + dbg("%s - setting interface", __FUNCTION__); + interface = intf->cur_altsetting; + + dbg("%s - setting endpoint", __FUNCTION__); + endpoint = &interface->endpoint[0].desc; + + if (!(mtouch = kmalloc(sizeof(struct mtouch_usb), GFP_KERNEL))) { + err("%s - Out of memory.", __FUNCTION__); + return -ENOMEM; + } + + memset(mtouch, 0, sizeof(struct mtouch_usb)); + mtouch->udev = udev; + + dbg("%s - allocating buffers", __FUNCTION__); + if (mtouchusb_alloc_buffers(udev, mtouch)) { + mtouchusb_free_buffers(udev, mtouch); + kfree(mtouch); + return -ENOMEM; + } + + mtouch->input.private = mtouch; + mtouch->input.open = mtouchusb_open; + mtouch->input.close = mtouchusb_close; + + usb_make_path(udev, path, 64); + sprintf(mtouch->phys, "%s/input0", path); + + mtouch->input.name = mtouch->name; + mtouch->input.phys = mtouch->phys; + mtouch->input.id.bustype = BUS_USB; + mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor); + mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct); + mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice); + mtouch->input.dev = &intf->dev; + + mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + + /* Used to Scale Compensated Data and Flip Y */ + mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC; + mtouch->input.absmax[ABS_X] = raw_coordinates ? + MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC; + mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ; + mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT; + mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC; + mtouch->input.absmax[ABS_Y] = raw_coordinates ? + MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC; + mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ; + mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT; 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); - - nRet = usb_control_msg(mtouch->udev, - usb_rcvctrlpipe(udev, 0), - MTOUCHUSB_RESET, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 1, - 0, - NULL, - 0, - USB_CTRL_SET_TIMEOUT); - dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d", - __FUNCTION__, nRet); - - dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__); - mtouch->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!mtouch->irq) { - dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__); - mtouchusb_free_buffers(udev, mtouch); - kfree(mtouch); - return -ENOMEM; - } - - dbg("%s - usb_fill_int_urb", __FUNCTION__); - usb_fill_int_urb(mtouch->irq, - mtouch->udev, - usb_rcvintpipe(mtouch->udev, 0x81), - mtouch->data, - MTOUCHUSB_REPORT_DATA_SIZE, - mtouchusb_irq, - mtouch, - endpoint->bInterval); - - dbg("%s - input_register_device", __FUNCTION__); - input_register_device(&mtouch->input); - - nRet = usb_control_msg(mtouch->udev, - usb_rcvctrlpipe(udev, 0), - MTOUCHUSB_ASYNC_REPORT, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 1, - 1, - NULL, - 0, - USB_CTRL_SET_TIMEOUT); - dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d", - __FUNCTION__, nRet); - - printk(KERN_INFO "input: %s on %s\n", mtouch->name, path); - usb_set_intfdata(intf, mtouch); - - return 0; + if (!strlen(mtouch->name)) + sprintf(mtouch->name, "USB Touchscreen %04x:%04x", + mtouch->input.id.vendor, mtouch->input.id.product); + + nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0), + MTOUCHUSB_RESET, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d", + __FUNCTION__, nRet); + + dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__); + mtouch->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!mtouch->irq) { + dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__); + mtouchusb_free_buffers(udev, mtouch); + kfree(mtouch); + return -ENOMEM; + } + + dbg("%s - usb_fill_int_urb", __FUNCTION__); + usb_fill_int_urb(mtouch->irq, mtouch->udev, + usb_rcvintpipe(mtouch->udev, 0x81), + mtouch->data, MTOUCHUSB_REPORT_DATA_SIZE, + mtouchusb_irq, mtouch, endpoint->bInterval); + + dbg("%s - input_register_device", __FUNCTION__); + input_register_device(&mtouch->input); + + nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0), + MTOUCHUSB_ASYNC_REPORT, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT); + dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d", + __FUNCTION__, nRet); + + printk(KERN_INFO "input: %s on %s\n", mtouch->name, path); + usb_set_intfdata(intf, mtouch); + + return 0; } static void mtouchusb_disconnect(struct usb_interface *intf) { - struct mtouch_usb *mtouch = usb_get_intfdata (intf); - - dbg("%s - called", __FUNCTION__); - usb_set_intfdata(intf, NULL); - if (mtouch) { - dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__); - usb_kill_urb(mtouch->irq); - input_unregister_device(&mtouch->input); - usb_free_urb(mtouch->irq); - mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch); - kfree(mtouch); - } + struct mtouch_usb *mtouch = usb_get_intfdata(intf); + + dbg("%s - called", __FUNCTION__); + usb_set_intfdata(intf, NULL); + if (mtouch) { + dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__); + usb_kill_urb(mtouch->irq); + input_unregister_device(&mtouch->input); + usb_free_urb(mtouch->irq); + mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch); + kfree(mtouch); + } } -MODULE_DEVICE_TABLE (usb, mtouchusb_devices); +MODULE_DEVICE_TABLE(usb, mtouchusb_devices); static struct usb_driver mtouchusb_driver = { - .owner = THIS_MODULE, - .name = "mtouchusb", - .probe = mtouchusb_probe, - .disconnect = mtouchusb_disconnect, - .id_table = mtouchusb_devices, + .owner = THIS_MODULE, + .name = "mtouchusb", + .probe = mtouchusb_probe, + .disconnect = mtouchusb_disconnect, + .id_table = mtouchusb_devices, }; -static int __init mtouchusb_init(void) { - dbg("%s - called", __FUNCTION__); - return usb_register(&mtouchusb_driver); +static int __init mtouchusb_init(void) +{ + dbg("%s - called", __FUNCTION__); + return usb_register(&mtouchusb_driver); } -static void __exit mtouchusb_cleanup(void) { - dbg("%s - called", __FUNCTION__); - usb_deregister(&mtouchusb_driver); +static void __exit mtouchusb_cleanup(void) +{ + dbg("%s - called", __FUNCTION__); + usb_deregister(&mtouchusb_driver); } module_init(mtouchusb_init); module_exit(mtouchusb_cleanup); -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 65cde54b8b0299d7e46b8705338b01d1e44a5eb0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 29 May 2005 02:29:38 -0500 Subject: Input: remove user counters from drivers/usb/input since input core takes care of calling open and close methods only when needed. Signed-off-by: Dmitry Torokhov --- drivers/usb/input/aiptek.c | 14 ++------------ drivers/usb/input/ati_remote.c | 28 +++++----------------------- drivers/usb/input/itmtouch.c | 10 ++-------- drivers/usb/input/kbtab.c | 11 ++--------- drivers/usb/input/mtouchusb.c | 11 ++--------- drivers/usb/input/touchkitusb.c | 11 ++--------- drivers/usb/input/usbkbd.c | 11 ++--------- drivers/usb/input/usbmouse.c | 11 ++--------- drivers/usb/input/wacom.c | 11 ++--------- drivers/usb/input/xpad.c | 11 ++--------- 10 files changed, 23 insertions(+), 106 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index 68d9d281386c..a6921856a112 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -324,7 +324,6 @@ struct aiptek { struct aiptek_settings curSetting; /* tablet's current programmable */ struct aiptek_settings newSetting; /* ... and new param settings */ unsigned int ifnum; /* interface number for IO */ - int openCount; /* module use counter */ int diagnostic; /* tablet diagnostic codes */ unsigned long eventCount; /* event count */ int inDelay; /* jitter: in jitter delay? */ @@ -814,15 +813,9 @@ static int aiptek_open(struct input_dev *inputdev) { struct aiptek *aiptek = inputdev->private; - if (aiptek->openCount++ > 0) { - return 0; - } - aiptek->urb->dev = aiptek->usbdev; - if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0) { - aiptek->openCount--; + if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0) return -EIO; - } return 0; } @@ -834,9 +827,7 @@ static void aiptek_close(struct input_dev *inputdev) { struct aiptek *aiptek = inputdev->private; - if (--aiptek->openCount == 0) { - usb_kill_urb(aiptek->urb); - } + usb_kill_urb(aiptek->urb); } /*********************************************************************** @@ -2252,7 +2243,6 @@ static void aiptek_disconnect(struct usb_interface *intf) AIPTEK_PACKET_LENGTH, aiptek->data, aiptek->data_dma); kfree(aiptek); - aiptek = NULL; } } diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index cf45add81713..db95c975952b 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -113,11 +113,11 @@ #define DATA_BUFSIZE 63 /* size of URB data buffers */ #define ATI_INPUTNUM 1 /* Which input device to register as */ -static unsigned long channel_mask = 0; +static unsigned long channel_mask; module_param(channel_mask, ulong, 0444); MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); -static int debug = 0; +static int debug; module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); @@ -174,8 +174,6 @@ struct ati_remote { dma_addr_t inbuf_dma; dma_addr_t outbuf_dma; - int open; /* open counter */ - unsigned char old_data[2]; /* Detect duplicate events */ unsigned long old_jiffies; unsigned long acc_jiffies; /* handle acceleration */ @@ -328,25 +326,16 @@ static void ati_remote_dump(unsigned char *data, unsigned int len) static int ati_remote_open(struct input_dev *inputdev) { struct ati_remote *ati_remote = inputdev->private; - int retval = 0; - - down(&disconnect_sem); - - if (ati_remote->open++) - goto exit; /* On first open, submit the read urb which was set up previously. */ ati_remote->irq_urb->dev = ati_remote->udev; if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb failed!\n", __FUNCTION__); - ati_remote->open--; - retval = -EIO; + return -EIO; } -exit: - up(&disconnect_sem); - return retval; + return 0; } /* @@ -356,8 +345,7 @@ static void ati_remote_close(struct input_dev *inputdev) { struct ati_remote *ati_remote = inputdev->private; - if (!--ati_remote->open) - usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->irq_urb); } /* @@ -602,8 +590,6 @@ static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs) */ static void ati_remote_delete(struct ati_remote *ati_remote) { - if (!ati_remote) return; - if (ati_remote->irq_urb) usb_kill_urb(ati_remote->irq_urb); @@ -799,8 +785,6 @@ static void ati_remote_disconnect(struct usb_interface *interface) { struct ati_remote *ati_remote; - down(&disconnect_sem); - ati_remote = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); if (!ati_remote) { @@ -809,8 +793,6 @@ static void ati_remote_disconnect(struct usb_interface *interface) } ati_remote_delete(ati_remote); - - up(&disconnect_sem); } /* diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c index 5122a7f701a9..47dec6a1b344 100644 --- a/drivers/usb/input/itmtouch.c +++ b/drivers/usb/input/itmtouch.c @@ -137,15 +137,10 @@ static int itmtouch_open(struct input_dev *input) { struct itmtouch_dev *itmtouch = input->private; - if (itmtouch->users++) - return 0; - itmtouch->readurb->dev = itmtouch->usbdev; - if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL)) { - itmtouch->users--; + if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL)) return -EIO; - } return 0; } @@ -154,8 +149,7 @@ static void itmtouch_close(struct input_dev *input) { struct itmtouch_dev *itmtouch = input->private; - if (!--itmtouch->users) - usb_kill_urb(itmtouch->readurb); + usb_kill_urb(itmtouch->readurb); } static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id *id) diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index fff5753b16ca..d2f0f90a9bcd 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c @@ -36,7 +36,6 @@ struct kbtab { struct input_dev dev; struct usb_device *usbdev; struct urb *irq; - int open; int x, y; int button; int pressure; @@ -105,14 +104,9 @@ static int kbtab_open(struct input_dev *dev) { struct kbtab *kbtab = dev->private; - if (kbtab->open++) - return 0; - kbtab->irq->dev = kbtab->usbdev; - if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) { - kbtab->open--; + if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) return -EIO; - } return 0; } @@ -121,8 +115,7 @@ static void kbtab_close(struct input_dev *dev) { struct kbtab *kbtab = dev->private; - if (!--kbtab->open) - usb_kill_urb(kbtab->irq); + usb_kill_urb(kbtab->irq); } static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id) diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index ec1dd6278f7b..09b5cc7c66de 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c @@ -98,7 +98,6 @@ struct mtouch_usb { struct urb *irq; struct usb_device *udev; struct input_dev input; - int open; char name[128]; char phys[64]; }; @@ -155,15 +154,10 @@ static int mtouchusb_open(struct input_dev *input) { struct mtouch_usb *mtouch = input->private; - if (mtouch->open++) - return 0; - mtouch->irq->dev = mtouch->udev; - if (usb_submit_urb(mtouch->irq, GFP_ATOMIC)) { - mtouch->open--; + if (usb_submit_urb(mtouch->irq, GFP_ATOMIC)) return -EIO; - } return 0; } @@ -172,8 +166,7 @@ static void mtouchusb_close(struct input_dev *input) { struct mtouch_usb *mtouch = input->private; - if (!--mtouch->open) - usb_kill_urb(mtouch->irq); + usb_kill_urb(mtouch->irq); } static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c index a71f1bbd0a17..386595ee21c0 100644 --- a/drivers/usb/input/touchkitusb.c +++ b/drivers/usb/input/touchkitusb.c @@ -69,7 +69,6 @@ struct touchkit_usb { struct urb *irq; struct usb_device *udev; struct input_dev input; - int open; char name[128]; char phys[64]; }; @@ -134,15 +133,10 @@ static int touchkit_open(struct input_dev *input) { struct touchkit_usb *touchkit = input->private; - if (touchkit->open++) - return 0; - touchkit->irq->dev = touchkit->udev; - if (usb_submit_urb(touchkit->irq, GFP_ATOMIC)) { - touchkit->open--; + if (usb_submit_urb(touchkit->irq, GFP_ATOMIC)) return -EIO; - } return 0; } @@ -151,8 +145,7 @@ static void touchkit_close(struct input_dev *input) { struct touchkit_usb *touchkit = input->private; - if (!--touchkit->open) - usb_kill_urb(touchkit->irq); + usb_kill_urb(touchkit->irq); } static int touchkit_alloc_buffers(struct usb_device *udev, diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index 255b47a517b1..f35db1974c42 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -72,7 +72,6 @@ struct usb_kbd { unsigned char newleds; char name[128]; char phys[64]; - int open; unsigned char *new; struct usb_ctrlrequest *cr; @@ -180,14 +179,9 @@ static int usb_kbd_open(struct input_dev *dev) { struct usb_kbd *kbd = dev->private; - if (kbd->open++) - return 0; - kbd->irq->dev = kbd->usbdev; - if (usb_submit_urb(kbd->irq, GFP_KERNEL)) { - kbd->open--; + if (usb_submit_urb(kbd->irq, GFP_KERNEL)) return -EIO; - } return 0; } @@ -196,8 +190,7 @@ static void usb_kbd_close(struct input_dev *dev) { struct usb_kbd *kbd = dev->private; - if (!--kbd->open) - usb_kill_urb(kbd->irq); + usb_kill_urb(kbd->irq); } static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd) diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index 8ca2811fd174..1ec41b5effe6 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c @@ -51,7 +51,6 @@ struct usb_mouse { struct usb_device *usbdev; struct input_dev dev; struct urb *irq; - int open; signed char *data; dma_addr_t data_dma; @@ -101,14 +100,9 @@ static int usb_mouse_open(struct input_dev *dev) { struct usb_mouse *mouse = dev->private; - if (mouse->open++) - return 0; - mouse->irq->dev = mouse->usbdev; - if (usb_submit_urb(mouse->irq, GFP_KERNEL)) { - mouse->open--; + if (usb_submit_urb(mouse->irq, GFP_KERNEL)) return -EIO; - } return 0; } @@ -117,8 +111,7 @@ static void usb_mouse_close(struct input_dev *dev) { struct usb_mouse *mouse = dev->private; - if (!--mouse->open) - usb_kill_urb(mouse->irq); + usb_kill_urb(mouse->irq); } static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_id * id) diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index b3420e12ae4f..e37d31b57b23 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -102,7 +102,6 @@ struct wacom { struct urb *irq; struct wacom_features *features; int tool[2]; - int open; __u32 serial[2]; char phys[32]; }; @@ -771,14 +770,9 @@ static int wacom_open(struct input_dev *dev) { struct wacom *wacom = dev->private; - if (wacom->open++) - return 0; - wacom->irq->dev = wacom->usbdev; - if (usb_submit_urb(wacom->irq, GFP_KERNEL)) { - wacom->open--; + if (usb_submit_urb(wacom->irq, GFP_KERNEL)) return -EIO; - } return 0; } @@ -787,8 +781,7 @@ static void wacom_close(struct input_dev *dev) { struct wacom *wacom = dev->private; - if (!--wacom->open) - usb_kill_urb(wacom->irq); + usb_kill_urb(wacom->irq); } static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index a8076ccc0b2e..a7fa1b17dcfe 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c @@ -110,7 +110,6 @@ struct usb_xpad { dma_addr_t idata_dma; char phys[65]; /* physical device path */ - int open_count; /* reference count */ }; /* @@ -197,14 +196,9 @@ static int xpad_open (struct input_dev *dev) { struct usb_xpad *xpad = dev->private; - if (xpad->open_count++) - return 0; - xpad->irq_in->dev = xpad->udev; - if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) { - xpad->open_count--; + if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) return -EIO; - } return 0; } @@ -213,8 +207,7 @@ static void xpad_close (struct input_dev *dev) { struct usb_xpad *xpad = dev->private; - if (!--xpad->open_count) - usb_kill_urb(xpad->irq_in); + usb_kill_urb(xpad->irq_in); } static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) -- cgit v1.2.3 From bef3768d8fdee7e1f1488e7017937eb4bf5797a2 Mon Sep 17 00:00:00 2001 From: Adam Kropelin Date: Sun, 29 May 2005 02:30:08 -0500 Subject: Input: HID items of width 32 (bits) or greater are incorrectly extracted due to a masking bug in hid-core.c:extract(). This patch fixes it up by forcing the mask to be 64 bits wide. Signed-off-by: Adam Kropelin Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/usb/input/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 08e701bc9f64..43215a981814 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -765,7 +765,7 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n) static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) { report += (offset >> 5) << 2; offset &= 31; - return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1 << n) - 1); + return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1); } static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) -- cgit v1.2.3 From 53880546979605dae20ee0404a0e998e188fe7ad Mon Sep 17 00:00:00 2001 From: Stephane VOLTZ Date: Mon, 6 Jun 2005 02:22:37 -0500 Subject: Input: add driver for Acecad Flair USB tablets Signed-off-by: Dmitry Torokhov --- drivers/usb/Makefile | 1 + drivers/usb/input/Kconfig | 12 ++ drivers/usb/input/Makefile | 1 + drivers/usb/input/acecad.c | 285 +++++++++++++++++++++++++++++++++++++++++++ drivers/usb/input/hid-core.c | 7 ++ 5 files changed, 306 insertions(+) create mode 100644 drivers/usb/input/acecad.c (limited to 'drivers/usb') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index a61d4433a989..a708a1dbb530 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_USB_MOUSE) += input/ obj-$(CONFIG_USB_MTOUCH) += input/ obj-$(CONFIG_USB_POWERMATE) += input/ obj-$(CONFIG_USB_WACOM) += input/ +obj-$(CONFIG_USB_ACECAD) += input/ obj-$(CONFIG_USB_XPAD) += input/ obj-$(CONFIG_USB_DABUSB) += media/ diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index fcae574f3106..fd59f6bdd67f 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -151,6 +151,18 @@ config USB_WACOM To compile this driver as a module, choose M here: the module will be called wacom. +config USB_ACECAD + tristate "Acecad Flair tablet support" + depends on USB && INPUT + help + Say Y here if you want to use the USB version of the Acecad Flair + tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + To compile this driver as a module, choose M here: the + module will be called acecad. + config USB_KBTAB tristate "KB Gear JamStudio tablet support" depends on USB && INPUT diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index f0fd02e00d32..831b2b0f1f05 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -37,4 +37,5 @@ obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o obj-$(CONFIG_USB_EGALAX) += touchkitusb.o obj-$(CONFIG_USB_POWERMATE) += powermate.o obj-$(CONFIG_USB_WACOM) += wacom.o +obj-$(CONFIG_USB_ACECAD) += acecad.o obj-$(CONFIG_USB_XPAD) += xpad.o diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c new file mode 100644 index 000000000000..ebcf7c955800 --- /dev/null +++ b/drivers/usb/input/acecad.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2001-2005 Edouard TISSERANT + * Copyright (c) 2004-2005 Stephane VOLTZ + * + * USB Acecad "Acecad Flair" tablet support + * + * Changelog: + * v3.2 - Added sysfs support + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include + +/* + * Version Information + */ +#define DRIVER_VERSION "v3.2" +#define DRIVER_DESC "USB Acecad Flair tablet driver" +#define DRIVER_LICENSE "GPL" +#define DRIVER_AUTHOR "Edouard TISSERANT " + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); + +#define USB_VENDOR_ID_ACECAD 0x0460 +#define USB_DEVICE_ID_FLAIR 0x0004 +#define USB_DEVICE_ID_302 0x0008 + +struct usb_acecad { + char name[128]; + char phys[64]; + struct usb_device *usbdev; + struct input_dev dev; + struct urb *irq; + + signed char *data; + dma_addr_t data_dma; +}; + +static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs) +{ + struct usb_acecad *acecad = urb->context; + unsigned char *data = acecad->data; + struct input_dev *dev = &acecad->dev; + int prox, status; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + goto resubmit; + } + + prox = (data[0] & 0x04) >> 2; + input_report_key(dev, BTN_TOOL_PEN, prox); + + if (prox) { + int x = data[1] | (data[2] << 8); + int y = data[3] | (data[4] << 8); + /*Pressure should compute the same way for flair and 302*/ + int pressure = data[5] | ((int)data[6] << 8); + int touch = data[0] & 0x01; + int stylus = (data[0] & 0x10) >> 4; + int stylus2 = (data[0] & 0x20) >> 5; + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + input_report_abs(dev, ABS_PRESSURE, pressure); + input_report_key(dev, BTN_TOUCH, touch); + input_report_key(dev, BTN_STYLUS, stylus); + input_report_key(dev, BTN_STYLUS2, stylus2); + } + + /* event termination */ + input_sync(dev); + +resubmit: + status = usb_submit_urb (urb, GFP_ATOMIC); + if (status) + err ("can't resubmit intr, %s-%s/input0, status %d", + acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status); +} + +static int usb_acecad_open(struct input_dev *dev) +{ + struct usb_acecad *acecad = dev->private; + + acecad->irq->dev = acecad->usbdev; + if (usb_submit_urb(acecad->irq, GFP_KERNEL)) + return -EIO; + + return 0; +} + +static void usb_acecad_close(struct input_dev *dev) +{ + struct usb_acecad *acecad = dev->private; + + usb_kill_urb(acecad->irq); +} + +static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_host_interface *interface = intf->cur_altsetting; + struct usb_endpoint_descriptor *endpoint; + struct usb_acecad *acecad; + int pipe, maxp; + char path[64]; + + if (interface->desc.bNumEndpoints != 1) + return -ENODEV; + + endpoint = &interface->endpoint[0].desc; + + if (!(endpoint->bEndpointAddress & 0x80)) + return -ENODEV; + + if ((endpoint->bmAttributes & 3) != 3) + return -ENODEV; + + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + acecad = kcalloc(1, sizeof(struct usb_acecad), GFP_KERNEL); + if (!acecad) + return -ENOMEM; + + acecad->data = usb_buffer_alloc(dev, 8, SLAB_KERNEL, &acecad->data_dma); + if (!acecad->data) + goto fail1; + + acecad->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!acecad->irq) + goto fail2; + + if (dev->manufacturer) + strlcpy(acecad->name, dev->manufacturer, sizeof(acecad->name)); + + if (dev->product) { + if (dev->manufacturer) + strlcat(acecad->name, " ", sizeof(acecad->name)); + strlcat(acecad->name, dev->product, sizeof(acecad->name)); + } + + usb_make_path(dev, path, sizeof(path)); + snprintf(acecad->phys, sizeof(acecad->phys), "%s/input0", path); + + acecad->usbdev = dev; + + acecad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + acecad->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + acecad->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + acecad->dev.keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2); + + switch (id->driver_info) { + case 0: + acecad->dev.absmax[ABS_X] = 5000; + acecad->dev.absmax[ABS_Y] = 3750; + acecad->dev.absmax[ABS_PRESSURE] = 512; + if (!strlen(acecad->name)) + snprintf(acecad->name, sizeof(acecad->name), + "USB Acecad Flair Tablet %04x:%04x", + dev->descriptor.idVendor, dev->descriptor.idProduct); + break; + case 1: + acecad->dev.absmax[ABS_X] = 3000; + acecad->dev.absmax[ABS_Y] = 2250; + acecad->dev.absmax[ABS_PRESSURE] = 1024; + if (!strlen(acecad->name)) + snprintf(acecad->name, sizeof(acecad->name), + "USB Acecad 302 Tablet %04x:%04x", + dev->descriptor.idVendor, dev->descriptor.idProduct); + break; + } + + acecad->dev.absfuzz[ABS_X] = 4; + acecad->dev.absfuzz[ABS_Y] = 4; + + acecad->dev.private = acecad; + acecad->dev.open = usb_acecad_open; + acecad->dev.close = usb_acecad_close; + + acecad->dev.name = acecad->name; + acecad->dev.phys = acecad->phys; + acecad->dev.id.bustype = BUS_USB; + acecad->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor); + acecad->dev.id.product = le16_to_cpu(dev->descriptor.idProduct); + acecad->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice); + acecad->dev.dev = &intf->dev; + + usb_fill_int_urb(acecad->irq, dev, pipe, + acecad->data, maxp > 8 ? 8 : maxp, + usb_acecad_irq, acecad, endpoint->bInterval); + acecad->irq->transfer_dma = acecad->data_dma; + acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + input_register_device(&acecad->dev); + + printk(KERN_INFO "input: %s with packet size %d on %s\n", + acecad->name, maxp, path); + + usb_set_intfdata(intf, acecad); + + return 0; + + fail2: usb_buffer_free(dev, 8, acecad->data, acecad->data_dma); + fail1: kfree(acecad); + return -ENOMEM; +} + +static void usb_acecad_disconnect(struct usb_interface *intf) +{ + struct usb_acecad *acecad = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + if (acecad) { + usb_kill_urb(acecad->irq); + input_unregister_device(&acecad->dev); + usb_free_urb(acecad->irq); + usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma); + kfree(acecad); + } +} + +static struct usb_device_id usb_acecad_id_table [] = { + { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_FLAIR), .driver_info = 0 }, + { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_302), .driver_info = 1 }, + { } +}; + +MODULE_DEVICE_TABLE(usb, usb_acecad_id_table); + +static struct usb_driver usb_acecad_driver = { + .owner = THIS_MODULE, + .name = "usb_acecad", + .probe = usb_acecad_probe, + .disconnect = usb_acecad_disconnect, + .id_table = usb_acecad_id_table, +}; + +static int __init usb_acecad_init(void) +{ + int result = usb_register(&usb_acecad_driver); + if (result == 0) + info(DRIVER_VERSION ":" DRIVER_DESC); + return result; +} + +static void __exit usb_acecad_exit(void) +{ + usb_deregister(&usb_acecad_driver); +} + +module_init(usb_acecad_init); +module_exit(usb_acecad_exit); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 96959ec590a3..d88e588ff178 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1321,6 +1321,10 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_WACOM_INTUOS3 0x00B0 #define USB_DEVICE_ID_WACOM_CINTIQ 0x003F +#define USB_VENDOR_ID_ACECAD 0x0460 +#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004 +#define USB_DEVICE_ID_ACECAD_302 0x0008 + #define USB_VENDOR_ID_KBGEAR 0x084e #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 @@ -1505,6 +1509,9 @@ static struct hid_blacklist { { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, -- cgit v1.2.3 From b2f86369e3e999a70f98e2a812aa5ec1b3c7bd0b Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Mon, 6 Jun 2005 02:25:50 -0500 Subject: Input: Wacom driver update - add support for Cintiq 21UX - fix a Graphire bug - merge wacom_intuos3_irq into wacom_intuos_irq Signed-off-by: Ping Cheng Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/usb/input/wacom.c | 336 +++++++++++++++++++++------------------------- 1 file changed, 153 insertions(+), 183 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index e37d31b57b23..60df242ba67f 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -9,7 +9,7 @@ * Copyright (c) 2000 Daniel Egger * Copyright (c) 2001 Frederic Lepied * Copyright (c) 2004 Panagiotis Issaris - * Copyright (c) 2002-2004 Ping Cheng + * Copyright (c) 2002-2005 Ping Cheng * * ChangeLog: * v0.1 (vp) - Initial release @@ -51,6 +51,9 @@ * - Cleanups here and there * v1.30.1 (pi) - Added Graphire3 support * v1.40 (pc) - Add support for several new devices, fix eraser reporting, ... + * v1.43 (pc) - Added support for Cintiq 21UX + - Fixed a Graphire bug + - Merged wacom_intuos3_irq into wacom_intuos_irq */ /* @@ -72,7 +75,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.40" +#define DRIVER_VERSION "v1.43" #define DRIVER_AUTHOR "Vojtech Pavlik " #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" #define DRIVER_LICENSE "GPL" @@ -83,6 +86,16 @@ MODULE_LICENSE(DRIVER_LICENSE); #define USB_VENDOR_ID_WACOM 0x056a +enum { + PENPARTNER = 0, + GRAPHIRE, + PL, + INTUOS, + INTUOS3, + CINTIQ, + MAX_TYPE +}; + struct wacom_features { char *name; int pktlen; @@ -181,8 +194,8 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs) wacom->tool[1] = BTN_TOOL_PEN; } input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */ - input_report_abs(dev, ABS_X, data[3] | ((__u32)data[2] << 7) | ((__u32)(data[1] & 0x03) << 14)); - input_report_abs(dev, ABS_Y, data[6] | ((__u32)data[5] << 7) | ((__u32)(data[4] & 0x03) << 14)); + input_report_abs(dev, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); + input_report_abs(dev, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); input_report_abs(dev, ABS_PRESSURE, pressure); input_report_key(dev, BTN_TOUCH, data[4] & 0x08); @@ -339,44 +352,44 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) input_regs(dev, regs); - switch ((data[1] >> 5) & 3) { - - case 0: /* Pen */ - input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x80); - break; - - case 1: /* Rubber */ - input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x80); - break; + if ( data[1] & 0x10 ) /* in prox */ + { + switch ((data[1] >> 5) & 3) { - case 2: /* Mouse with wheel */ - input_report_key(dev, BTN_MIDDLE, data[1] & 0x04); - input_report_rel(dev, REL_WHEEL, (signed char) data[6]); - /* fall through */ + case 0: /* Pen */ + wacom->tool[0] = BTN_TOOL_PEN; + break; - case 3: /* Mouse without wheel */ - input_report_key(dev, BTN_TOOL_MOUSE, data[7] > 24); - input_report_key(dev, BTN_LEFT, data[1] & 0x01); - input_report_key(dev, BTN_RIGHT, data[1] & 0x02); - input_report_abs(dev, ABS_DISTANCE, data[7]); + case 1: /* Rubber */ + wacom->tool[0] = BTN_TOOL_RUBBER; + break; - input_report_abs(dev, ABS_X, x); - input_report_abs(dev, ABS_Y, y); + case 2: /* Mouse with wheel */ + input_report_key(dev, BTN_MIDDLE, data[1] & 0x04); + input_report_rel(dev, REL_WHEEL, (signed char) data[6]); + /* fall through */ - input_sync(dev); - goto exit; + case 3: /* Mouse without wheel */ + wacom->tool[0] = BTN_TOOL_MOUSE; + input_report_key(dev, BTN_LEFT, data[1] & 0x01); + input_report_key(dev, BTN_RIGHT, data[1] & 0x02); + input_report_abs(dev, ABS_DISTANCE, data[7]); + break; + } } if (data[1] & 0x80) { input_report_abs(dev, ABS_X, x); input_report_abs(dev, ABS_Y, y); } + if (wacom->tool[0] != BTN_TOOL_MOUSE) { + input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6])); + input_report_key(dev, BTN_TOUCH, data[1] & 0x01); + input_report_key(dev, BTN_STYLUS, data[1] & 0x02); + input_report_key(dev, BTN_STYLUS2, data[1] & 0x04); + } - input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6])); - input_report_key(dev, BTN_TOUCH, data[1] & 0x01); - input_report_key(dev, BTN_STYLUS, data[1] & 0x02); - input_report_key(dev, BTN_STYLUS2, data[1] & 0x04); - + input_report_key(dev, wacom->tool[0], data[1] & 0x10); input_sync(dev); exit: @@ -400,11 +413,11 @@ static int wacom_intuos_inout(struct urb *urb) if ((data[1] & 0xfc) == 0xc0) { /* serial number of the tool */ - wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) + - ((__u32)data[4] << 20) + ((__u32)data[5] << 12) + - ((__u32)data[6] << 4) + (data[7] >> 4); + wacom->serial[idx] = ((data[3] & 0x0f) << 28) + + (data[4] << 20) + (data[5] << 12) + + (data[6] << 4) + (data[7] >> 4); - switch (((__u32)data[2] << 4) | (data[3] >> 4)) { + switch ((data[2] << 4) | (data[3] >> 4)) { case 0x812: /* Inking pen */ case 0x801: /* Intuos3 Inking pen */ case 0x012: @@ -448,7 +461,7 @@ static int wacom_intuos_inout(struct urb *urb) case 0x112: case 0x913: /* Intuos3 Airbrush */ wacom->tool[idx] = BTN_TOOL_AIRBRUSH; - break; /* Airbrush */ + break; default: /* Unknown tool */ wacom->tool[idx] = BTN_TOOL_PEN; } @@ -479,7 +492,7 @@ static void wacom_intuos_general(struct urb *urb) /* general pen packet */ if ((data[1] & 0xb8) == 0xa0) { - t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3); + t = (data[6] << 2) | ((data[7] >> 6) & 3); input_report_abs(dev, ABS_PRESSURE, t); input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7)); @@ -493,7 +506,7 @@ static void wacom_intuos_general(struct urb *urb) if ((data[1] & 0xbc) == 0xb4) { input_report_abs(dev, ABS_WHEEL, - ((__u32)data[6] << 2) | ((data[7] >> 6) & 3)); + (data[6] << 2) | ((data[7] >> 6) & 3)); input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7)); input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f); @@ -525,7 +538,7 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - if (data[0] != 2 && data[0] != 5 && data[0] != 6) { + if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) { dbg("wacom_intuos_irq: received unknown report #%d", data[0]); goto exit; } @@ -535,101 +548,6 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) /* tool number */ idx = data[1] & 0x01; - /* process in/out prox events */ - if (wacom_intuos_inout(urb)) goto exit; - - input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2])); - input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4])); - input_report_abs(dev, ABS_DISTANCE, data[9]); - - /* process general packets */ - wacom_intuos_general(urb); - - if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) { /* 4D mouse or Lens cursor packets */ - - if (data[1] & 0x02) { /* Rotation packet */ - - t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7); - input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ? ((t - 1) / 2) : -t / 2); - - } else { - - if ((data[1] & 0x10) == 0) { /* 4D mouse packets */ - - input_report_key(dev, BTN_LEFT, data[8] & 0x01); - input_report_key(dev, BTN_MIDDLE, data[8] & 0x02); - input_report_key(dev, BTN_RIGHT, data[8] & 0x04); - - input_report_key(dev, BTN_SIDE, data[8] & 0x20); - input_report_key(dev, BTN_EXTRA, data[8] & 0x10); - t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3); - input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t); - - } else { - if (wacom->tool[idx] == BTN_TOOL_MOUSE) { /* 2D mouse packets */ - input_report_key(dev, BTN_LEFT, data[8] & 0x04); - input_report_key(dev, BTN_MIDDLE, data[8] & 0x08); - input_report_key(dev, BTN_RIGHT, data[8] & 0x10); - input_report_rel(dev, REL_WHEEL, - (-(__u32)(data[8] & 0x01) + (__u32)((data[8] & 0x02) >> 1))); - } - else { /* Lens cursor packets */ - input_report_key(dev, BTN_LEFT, data[8] & 0x01); - input_report_key(dev, BTN_MIDDLE, data[8] & 0x02); - input_report_key(dev, BTN_RIGHT, data[8] & 0x04); - input_report_key(dev, BTN_SIDE, data[8] & 0x10); - input_report_key(dev, BTN_EXTRA, data[8] & 0x08); - } - } - } - } - - input_report_key(dev, wacom->tool[idx], 1); - input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); - input_sync(dev); - -exit: - retval = usb_submit_urb (urb, GFP_ATOMIC); - if (retval) - err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, retval); -} - -static void wacom_intuos3_irq(struct urb *urb, struct pt_regs *regs) -{ - struct wacom *wacom = urb->context; - unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; - unsigned int t; - int idx, retval; - - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); - return; - default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); - goto exit; - } - - /* check for valid report */ - if (data[0] != 2 && data[0] != 5 && data[0] != 12) - { - printk(KERN_INFO "wacom_intuos3_irq: received unknown report #%d\n", data[0]); - goto exit; - } - - input_regs(dev, regs); - - /* tool index is always 0 here since there is no dual input tool */ - idx = data[1] & 0x01; - /* pad packets. Works as a second tool and is always in prox */ if (data[0] == 12) { @@ -657,35 +575,84 @@ static void wacom_intuos3_irq(struct urb *urb, struct pt_regs *regs) /* process in/out prox events */ if (wacom_intuos_inout(urb)) goto exit; - input_report_abs(dev, ABS_X, ((__u32)data[2] << 9) | ((__u32)data[3] << 1) | ((data[9] >> 1) & 1)); - input_report_abs(dev, ABS_Y, ((__u32)data[4] << 9) | ((__u32)data[5] << 1) | (data[9] & 1)); - input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f)); + /* Cintiq doesn't send data when RDY bit isn't set */ + if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40)) return; + + if(wacom->features->type >= INTUOS3) + { + input_report_abs(dev, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1)); + input_report_abs(dev, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1)); + input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f)); + } + else + { + input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2])); + input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4])); + input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 3) & 0x1f)); + } /* process general packets */ wacom_intuos_general(urb); - if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) - { - /* Marker pen rotation packet. Reported as wheel due to valuator limitation */ + /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */ + if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) { + /* Rotation packet */ if (data[1] & 0x02) { - t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7); - t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) : - ((t-1) / 2 + 450)) : (450 - t / 2) ; - input_report_abs(dev, ABS_WHEEL, t); + if(wacom->features->type >= INTUOS3) + { + /* I3 marker pen rotation reported as wheel + * due to valuator limitation + */ + t = (data[6] << 3) | ((data[7] >> 5) & 7); + t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) : + ((t-1) / 2 + 450)) : (450 - t / 2) ; + input_report_abs(dev, ABS_WHEEL, t); + } + else + { + /* 4D mouse rotation packet */ + t = (data[6] << 3) | ((data[7] >> 5) & 7); + input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ? + ((t - 1) / 2) : -t / 2); + } + } + /* 4D mouse packets */ + else if ( !(data[1] & 0x10) && wacom->features->type < INTUOS3) + { + input_report_key(dev, BTN_LEFT, data[8] & 0x01); + input_report_key(dev, BTN_MIDDLE, data[8] & 0x02); + input_report_key(dev, BTN_RIGHT, data[8] & 0x04); + + input_report_key(dev, BTN_SIDE, data[8] & 0x20); + input_report_key(dev, BTN_EXTRA, data[8] & 0x10); + t = (data[6] << 2) | ((data[7] >> 6) & 3); + input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t); } - /* 2D mouse packets */ - if (wacom->tool[idx] == BTN_TOOL_MOUSE) + else if (wacom->tool[idx] == BTN_TOOL_MOUSE) { input_report_key(dev, BTN_LEFT, data[8] & 0x04); input_report_key(dev, BTN_MIDDLE, data[8] & 0x08); input_report_key(dev, BTN_RIGHT, data[8] & 0x10); - input_report_key(dev, BTN_SIDE, data[8] & 0x40); - input_report_key(dev, BTN_EXTRA, data[8] & 0x20); - /* mouse wheel is positive when rolled backwards */ - input_report_rel(dev, REL_WHEEL, ((__u32)((data[8] & 0x02) >> 1) - - (__u32)(data[8] & 0x01))); + input_report_rel(dev, REL_WHEEL, ((data[8] & 0x02) >> 1) + - (data[8] & 0x01)); + + /* I3 2D mouse side buttons */ + if (wacom->features->type == INTUOS3) + { + input_report_key(dev, BTN_SIDE, data[8] & 0x40); + input_report_key(dev, BTN_EXTRA, data[8] & 0x20); + } + } + /* Lens cursor packets */ + else if (wacom->features->type < INTUOS3) + { + input_report_key(dev, BTN_LEFT, data[8] & 0x01); + input_report_key(dev, BTN_MIDDLE, data[8] & 0x02); + input_report_key(dev, BTN_RIGHT, data[8] & 0x04); + input_report_key(dev, BTN_SIDE, data[8] & 0x10); + input_report_key(dev, BTN_EXTRA, data[8] & 0x08); } } @@ -701,34 +668,35 @@ exit: } static struct wacom_features wacom_features[] = { - { "Wacom Penpartner", 7, 5040, 3780, 255, 32, 0, wacom_penpartner_irq }, - { "Wacom Graphire", 8, 10206, 7422, 511, 32, 1, wacom_graphire_irq }, - { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, 1, wacom_graphire_irq }, - { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, 1, wacom_graphire_irq }, - { "Wacom Graphire3", 8, 10208, 7424, 511, 32, 1, wacom_graphire_irq }, - { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, 1, wacom_graphire_irq }, - { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom PL400", 8, 5408, 4056, 255, 32, 3, wacom_pl_irq }, - { "Wacom PL500", 8, 6144, 4608, 255, 32, 3, wacom_pl_irq }, - { "Wacom PL600", 8, 6126, 4604, 255, 32, 3, wacom_pl_irq }, - { "Wacom PL600SX", 8, 6260, 5016, 255, 32, 3, wacom_pl_irq }, - { "Wacom PL550", 8, 6144, 4608, 511, 32, 3, wacom_pl_irq }, - { "Wacom PL800", 8, 7220, 5780, 511, 32, 3, wacom_pl_irq }, - { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Volito", 8, 5104, 3712, 511, 32, 1, wacom_graphire_irq }, - { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, 3, wacom_ptu_irq }, - { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, 4, wacom_intuos3_irq }, - { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, 4, wacom_intuos3_irq }, - { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, 4, wacom_intuos3_irq }, - { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_penpartner_irq }, + { "Wacom Graphire", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_graphire_irq }, + { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_graphire_irq }, + { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_graphire_irq }, + { "Wacom Graphire3", 8, 10208, 7424, 511, 32, GRAPHIRE, wacom_graphire_irq }, + { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, GRAPHIRE, wacom_graphire_irq }, + { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_pl_irq }, + { "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_pl_irq }, + { "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_pl_irq }, + { "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_pl_irq }, + { "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_pl_irq }, + { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_pl_irq }, + { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Volito", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_graphire_irq }, + { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PL, wacom_ptu_irq }, + { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_intuos_irq }, + { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_intuos_irq }, + { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_intuos_irq }, + { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_intuos_irq }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq }, { } }; @@ -760,6 +728,7 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, { } }; @@ -816,7 +785,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS); switch (wacom->features->type) { - case 1: + case GRAPHIRE: wacom->dev.evbit[0] |= BIT(EV_REL); wacom->dev.relbit[0] |= BIT(REL_WHEEL); wacom->dev.absbit[0] |= BIT(ABS_DISTANCE); @@ -824,13 +793,14 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2); break; - case 4: /* new functions for Intuos3 */ + case INTUOS3: + case CINTIQ: wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); wacom->dev.absbit[0] |= BIT(ABS_RX) | BIT(ABS_RY); /* fall through */ - case 2: + case INTUOS: wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL); wacom->dev.mscbit[0] |= BIT(MSC_SERIAL); wacom->dev.relbit[0] |= BIT(REL_WHEEL); @@ -840,7 +810,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i wacom->dev.absbit[0] |= BIT(ABS_DISTANCE) | BIT(ABS_WHEEL) | BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE); break; - case 3: + case PL: wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER); break; } -- cgit v1.2.3 From e5119885f00874453e837e3407014b73de2f4741 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jun 2005 02:28:29 -0500 Subject: Input: wacom - fix formatting in accordance to CodingStyle Signed-off-by: Dmitry Torokhov --- drivers/usb/input/wacom.c | 123 ++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 71 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index 60df242ba67f..f6b34af66b3d 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -178,8 +178,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs) if (!wacom->tool[0]) { /* Going into proximity select tool */ wacom->tool[1] = (data[4] & 0x20)? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - } - else { + } else { /* was entered with stylus2 pressed */ if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20) ) { /* report out proximity for previous tool */ @@ -202,8 +201,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs) input_report_key(dev, BTN_STYLUS, data[4] & 0x10); /* Only allow the stylus2 button to be reported for the pen tool. */ input_report_key(dev, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20)); - } - else { + } else { /* report proximity-out of a (valid) tool */ if (wacom->tool[1] != BTN_TOOL_RUBBER) { /* Unknown tool selected default to pen tool */ @@ -215,7 +213,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs) wacom->tool[0] = prox; /* Save proximity state */ input_sync(dev); -exit: + exit: retval = usb_submit_urb (urb, GFP_ATOMIC); if (retval) err ("%s - usb_submit_urb failed with result %d", @@ -244,20 +242,16 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - if (data[0] != 2) - { + if (data[0] != 2) { printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]); goto exit; } input_regs(dev, regs); - if (data[1] & 0x04) - { + if (data[1] & 0x04) { input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20); input_report_key(dev, BTN_TOUCH, data[1] & 0x08); - } - else - { + } else { input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20); input_report_key(dev, BTN_TOUCH, data[1] & 0x01); } @@ -269,7 +263,7 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs) input_sync(dev); -exit: + exit: retval = usb_submit_urb (urb, GFP_ATOMIC); if (retval) err ("%s - usb_submit_urb failed with result %d", @@ -312,7 +306,7 @@ static void wacom_penpartner_irq(struct urb *urb, struct pt_regs *regs) input_report_key(dev, BTN_STYLUS, (data[5] & 0x40)); input_sync(dev); -exit: + exit: retval = usb_submit_urb (urb, GFP_ATOMIC); if (retval) err ("%s - usb_submit_urb failed with result %d", @@ -352,8 +346,8 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) input_regs(dev, regs); - if ( data[1] & 0x10 ) /* in prox */ - { + if (data[1] & 0x10) { /* in prox */ + switch ((data[1] >> 5) & 3) { case 0: /* Pen */ @@ -369,7 +363,7 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) input_report_rel(dev, REL_WHEEL, (signed char) data[6]); /* fall through */ - case 3: /* Mouse without wheel */ + case 3: /* Mouse without wheel */ wacom->tool[0] = BTN_TOOL_MOUSE; input_report_key(dev, BTN_LEFT, data[1] & 0x01); input_report_key(dev, BTN_RIGHT, data[1] & 0x02); @@ -392,7 +386,7 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) input_report_key(dev, wacom->tool[0], data[1] & 0x10); input_sync(dev); -exit: + exit: retval = usb_submit_urb (urb, GFP_ATOMIC); if (retval) err ("%s - usb_submit_urb failed with result %d", @@ -410,8 +404,7 @@ static int wacom_intuos_inout(struct urb *urb) idx = data[1] & 0x01; /* Enter report */ - if ((data[1] & 0xfc) == 0xc0) - { + if ((data[1] & 0xfc) == 0xc0) { /* serial number of the tool */ wacom->serial[idx] = ((data[3] & 0x0f) << 28) + (data[4] << 20) + (data[5] << 12) + @@ -490,8 +483,7 @@ static void wacom_intuos_general(struct urb *urb) unsigned int t; /* general pen packet */ - if ((data[1] & 0xb8) == 0xa0) - { + if ((data[1] & 0xb8) == 0xa0) { t = (data[6] << 2) | ((data[7] >> 6) & 3); input_report_abs(dev, ABS_PRESSURE, t); input_report_abs(dev, ABS_TILT_X, @@ -503,8 +495,7 @@ static void wacom_intuos_general(struct urb *urb) } /* airbrush second packet */ - if ((data[1] & 0xbc) == 0xb4) - { + if ((data[1] & 0xbc) == 0xb4) { input_report_abs(dev, ABS_WHEEL, (data[6] << 2) | ((data[7] >> 6) & 3)); input_report_abs(dev, ABS_TILT_X, @@ -549,11 +540,9 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) idx = data[1] & 0x01; /* pad packets. Works as a second tool and is always in prox */ - if (data[0] == 12) - { + if (data[0] == 12) { /* initiate the pad as a device */ - if (wacom->tool[1] != BTN_TOOL_FINGER) - { + if (wacom->tool[1] != BTN_TOOL_FINGER) { wacom->tool[1] = BTN_TOOL_FINGER; input_report_key(dev, wacom->tool[1], 1); } @@ -573,19 +562,18 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) } /* process in/out prox events */ - if (wacom_intuos_inout(urb)) goto exit; + if (wacom_intuos_inout(urb)) + goto exit; /* Cintiq doesn't send data when RDY bit isn't set */ - if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40)) return; + if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40)) + return; - if(wacom->features->type >= INTUOS3) - { + if (wacom->features->type >= INTUOS3) { input_report_abs(dev, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1)); input_report_abs(dev, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1)); input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f)); - } - else - { + } else { input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2])); input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4])); input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 3) & 0x1f)); @@ -596,11 +584,10 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */ if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) { - /* Rotation packet */ - if (data[1] & 0x02) - { - if(wacom->features->type >= INTUOS3) - { + + if (data[1] & 0x02) { + /* Rotation packet */ + if (wacom->features->type >= INTUOS3) { /* I3 marker pen rotation reported as wheel * due to valuator limitation */ @@ -608,18 +595,15 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) : ((t-1) / 2 + 450)) : (450 - t / 2) ; input_report_abs(dev, ABS_WHEEL, t); - } - else - { + } else { /* 4D mouse rotation packet */ t = (data[6] << 3) | ((data[7] >> 5) & 7); input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ? ((t - 1) / 2) : -t / 2); } - } - /* 4D mouse packets */ - else if ( !(data[1] & 0x10) && wacom->features->type < INTUOS3) - { + + } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) { + /* 4D mouse packet */ input_report_key(dev, BTN_LEFT, data[8] & 0x01); input_report_key(dev, BTN_MIDDLE, data[8] & 0x02); input_report_key(dev, BTN_RIGHT, data[8] & 0x04); @@ -628,26 +612,23 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) input_report_key(dev, BTN_EXTRA, data[8] & 0x10); t = (data[6] << 2) | ((data[7] >> 6) & 3); input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t); - } - /* 2D mouse packets */ - else if (wacom->tool[idx] == BTN_TOOL_MOUSE) - { + + } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) { + /* 2D mouse packet */ input_report_key(dev, BTN_LEFT, data[8] & 0x04); input_report_key(dev, BTN_MIDDLE, data[8] & 0x08); input_report_key(dev, BTN_RIGHT, data[8] & 0x10); input_report_rel(dev, REL_WHEEL, ((data[8] & 0x02) >> 1) - - (data[8] & 0x01)); + - (data[8] & 0x01)); /* I3 2D mouse side buttons */ - if (wacom->features->type == INTUOS3) - { + if (wacom->features->type == INTUOS3) { input_report_key(dev, BTN_SIDE, data[8] & 0x40); input_report_key(dev, BTN_EXTRA, data[8] & 0x20); } - } - /* Lens cursor packets */ - else if (wacom->features->type < INTUOS3) - { + + } else if (wacom->features->type < INTUOS3) { + /* Lens cursor packets */ input_report_key(dev, BTN_LEFT, data[8] & 0x01); input_report_key(dev, BTN_MIDDLE, data[8] & 0x02); input_report_key(dev, BTN_RIGHT, data[8] & 0x04); @@ -668,23 +649,23 @@ exit: } static struct wacom_features wacom_features[] = { - { "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_penpartner_irq }, + { "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_penpartner_irq }, { "Wacom Graphire", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_graphire_irq }, { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_graphire_irq }, - { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_graphire_irq }, + { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_graphire_irq }, { "Wacom Graphire3", 8, 10208, 7424, 511, 32, GRAPHIRE, wacom_graphire_irq }, { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, GRAPHIRE, wacom_graphire_irq }, - { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq }, - { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq }, - { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq }, - { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_intuos_irq }, - { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_intuos_irq }, - { "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_pl_irq }, - { "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_pl_irq }, - { "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_pl_irq }, - { "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_pl_irq }, - { "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_pl_irq }, - { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_pl_irq }, + { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_intuos_irq }, + { "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_pl_irq }, + { "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_pl_irq }, + { "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_pl_irq }, + { "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_pl_irq }, + { "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_pl_irq }, + { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_pl_irq }, { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq }, { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq }, { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq }, -- cgit v1.2.3 From 479f6ea85e513551510ad52f37e69e1c596ad356 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Wed, 22 Jun 2005 17:53:28 +0200 Subject: [PATCH] USB: fix hid core to return proper error code from probe Drivers need to return -ENODEV when they can't bind to a device. Anything else stops the "bind a device to a driver" search. From: Stelian Pop Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 2d8bd9dcc6ed..740dec1f521d 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1762,7 +1762,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) intf->altsetting->desc.bInterfaceNumber); if (!(hid = usb_hid_configure(intf))) - return -EIO; + return -ENODEV; hid_init_reports(hid); hid_dump_device(hid); @@ -1777,7 +1777,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) if (!hid->claimed) { printk ("HID device not claimed by input or hiddev\n"); hid_disconnect(intf); - return -EIO; + return -ENODEV; } printk(KERN_INFO); -- cgit v1.2.3 From 5f45f1a78fbac3cc859ec10c5366e97d20d40fa2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 23 Jun 2005 00:09:12 -0700 Subject: [PATCH] remove duplicate get_dentry functions in various places Various filesystem drivers have grown a get_dentry() function that's a duplicate of lookup_one_len, except that it doesn't take a maximum length argument and doesn't check for \0 or / in the passed in filename. Switch all these places to use lookup_one_len. Signed-off-by: Christoph Hellwig Cc: Greg KH Cc: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/core/inode.c | 13 +------------ fs/debugfs/inode.c | 12 +----------- fs/sysfs/dir.c | 5 +++-- fs/sysfs/file.c | 5 +++-- fs/sysfs/group.c | 4 +++- fs/sysfs/inode.c | 10 ---------- fs/sysfs/sysfs.h | 1 - kernel/cpuset.c | 8 +------- 8 files changed, 12 insertions(+), 46 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index f9f9561c6bad..c3e3a95d3804 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -453,17 +453,6 @@ static int usbfs_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static struct dentry * get_dentry(struct dentry *parent, const char *name) -{ - struct qstr qstr; - - qstr.name = name; - qstr.len = strlen(name); - qstr.hash = full_name_hash(name,qstr.len); - return lookup_hash(&qstr,parent); -} - - /* * fs_create_by_name - create a file, given a name * @name: name of file @@ -496,7 +485,7 @@ static int fs_create_by_name (const char *name, mode_t mode, *dentry = NULL; down(&parent->d_inode->i_sem); - *dentry = get_dentry (parent, name); + *dentry = lookup_one_len(name, parent, strlen(name)); if (!IS_ERR(dentry)) { if ((mode & S_IFMT) == S_IFDIR) error = usbfs_mkdir (parent->d_inode, *dentry, mode); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index b529786699e7..a86ac4aeaedb 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -110,16 +110,6 @@ static int debug_fill_super(struct super_block *sb, void *data, int silent) return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); } -static struct dentry * get_dentry(struct dentry *parent, const char *name) -{ - struct qstr qstr; - - qstr.name = name; - qstr.len = strlen(name); - qstr.hash = full_name_hash(name,qstr.len); - return lookup_hash(&qstr,parent); -} - static struct super_block *debug_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) @@ -157,7 +147,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode, *dentry = NULL; down(&parent->d_inode->i_sem); - *dentry = get_dentry (parent, name); + *dentry = lookup_one_len(name, parent, strlen(name)); if (!IS_ERR(dentry)) { if ((mode & S_IFMT) == S_IFDIR) error = debugfs_mkdir(parent->d_inode, *dentry, mode); diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 37d7a6875d86..59734ba1ee60 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "sysfs.h" DECLARE_RWSEM(sysfs_rename_sem); @@ -99,7 +100,7 @@ static int create_dir(struct kobject * k, struct dentry * p, umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; down(&p->d_inode->i_sem); - *d = sysfs_get_dentry(p,n); + *d = lookup_one_len(n, p, strlen(n)); if (!IS_ERR(*d)) { error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR); if (!error) { @@ -315,7 +316,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) down(&parent->d_inode->i_sem); - new_dentry = sysfs_get_dentry(parent, new_name); + new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); if (!IS_ERR(new_dentry)) { if (!new_dentry->d_inode) { error = kobject_set_name(kobj, "%s", new_name); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 849aac115460..e9cfa39f4099 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -400,7 +401,7 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) int res = -ENOENT; down(&dir->d_inode->i_sem); - victim = sysfs_get_dentry(dir, attr->name); + victim = lookup_one_len(attr->name, dir, strlen(attr->name)); if (!IS_ERR(victim)) { /* make sure dentry is really there */ if (victim->d_inode && @@ -443,7 +444,7 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) int res = -ENOENT; down(&dir->d_inode->i_sem); - victim = sysfs_get_dentry(dir, attr->name); + victim = lookup_one_len(attr->name, dir, strlen(attr->name)); if (!IS_ERR(victim)) { if (victim->d_inode && (victim->d_parent->d_inode == dir->d_inode)) { diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index f11ac5ea7021..122145b0895c 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "sysfs.h" @@ -68,7 +69,8 @@ void sysfs_remove_group(struct kobject * kobj, struct dentry * dir; if (grp->name) - dir = sysfs_get_dentry(kobj->dentry,grp->name); + dir = lookup_one_len(grp->name, kobj->dentry, + strlen(grp->name)); else dir = dget(kobj->dentry); diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 565cac1d4200..8de13bafaa76 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -166,16 +166,6 @@ int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) return error; } -struct dentry * sysfs_get_dentry(struct dentry * parent, const char * name) -{ - struct qstr qstr; - - qstr.name = name; - qstr.len = strlen(name); - qstr.hash = full_name_hash(name,qstr.len); - return lookup_hash(&qstr,parent); -} - /* * Get the name for corresponding element represented by the given sysfs_dirent */ diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 29da6f5f07c8..3f8953e0e5d0 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -7,7 +7,6 @@ extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, umode_t, int); -extern struct dentry * sysfs_get_dentry(struct dentry *, const char *); extern int sysfs_add_file(struct dentry *, const struct attribute *, int); extern void sysfs_hash_and_remove(struct dentry * dir, const char * name); diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 00e8f2575512..79dd929f4084 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -228,13 +228,7 @@ static struct dentry_operations cpuset_dops = { static struct dentry *cpuset_get_dentry(struct dentry *parent, const char *name) { - struct qstr qstr; - struct dentry *d; - - qstr.name = name; - qstr.len = strlen(name); - qstr.hash = full_name_hash(name, qstr.len); - d = lookup_hash(&qstr, parent); + struct dentry *d = lookup_one_len(name, parent, strlen(name)); if (!IS_ERR(d)) d->d_op = &cpuset_dops; return d; -- cgit v1.2.3 From 790a19cd5711133f40daad7c55bf148de2b1d12c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 23 Jun 2005 00:10:31 -0700 Subject: [PATCH] pwc-uncompress warning fix drivers/usb/media/pwc/pwc-uncompress.c: In function `pwc_decompress': drivers/usb/media/pwc/pwc-uncompress.c:140: warning: unreachable code at beginning of switch statement Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/media/pwc/pwc-uncompress.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/media/pwc/pwc-uncompress.c b/drivers/usb/media/pwc/pwc-uncompress.c index bc3b1635eab0..ef4204eab6c4 100644 --- a/drivers/usb/media/pwc/pwc-uncompress.c +++ b/drivers/usb/media/pwc/pwc-uncompress.c @@ -118,9 +118,9 @@ int pwc_decompress(struct pwc_device *pdev) return -ENXIO; /* No such device or address: missing decompressor */ } +#if 0 switch (pdev->type) { -#if 0 case 675: case 680: case 690: @@ -128,18 +128,17 @@ int pwc_decompress(struct pwc_device *pdev) case 730: case 740: case 750: - pwc_dec23_decompress(&pdev->image, &pdev->view, &pdev->offset, - yuv, image, - flags, + pwc_dec23_decompress(&pdev->image, &pdev->view, + &pdev->offset, yuv, image, flags, pdev->decompress_data, pdev->vbandlength); break; case 645: case 646: /* TODO & FIXME */ -#endif - return -ENXIO; /* No such device or address: missing decompressor */ + return -ENXIO; /* Missing decompressor */ break; } +#endif } return 0; } -- cgit v1.2.3 From 4749f32da939d4e4160541b2cadc22492bb507ec Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 23 Jun 2005 11:36:56 +0200 Subject: [PATCH] better USB_MON dependencies This makes the USB_MON less confusing. Signed-off-by: Adrian Bunk Signed-off-by: Linus Torvalds --- drivers/usb/core/hcd.c | 2 +- drivers/usb/core/hcd.h | 2 +- drivers/usb/mon/Kconfig | 13 ++++--------- drivers/usb/mon/Makefile | 2 +- include/linux/usb.h | 2 +- 5 files changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index d041782e0c8b..0da23732e807 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1794,7 +1794,7 @@ EXPORT_SYMBOL (usb_remove_hcd); /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) +#if defined(CONFIG_USB_MON) struct usb_mon_operations *mon_ops; diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index f67cf1e634fc..325a51656c3f 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -399,7 +399,7 @@ static inline void usbfs_cleanup(void) { } /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) +#if defined(CONFIG_USB_MON) struct usb_mon_operations { void (*urb_submit)(struct usb_bus *bus, struct urb *urb); diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig index 4e6152aa5f19..777642e26b9a 100644 --- a/drivers/usb/mon/Kconfig +++ b/drivers/usb/mon/Kconfig @@ -2,13 +2,9 @@ # 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 + bool "USB Monitor" + depends on USB!=n default y help If you say Y here, a component which captures the USB traffic @@ -17,6 +13,5 @@ config USB_MON 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. + as long as you aren't using modular USB and try to remove this + module. diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile index 3cff8d444bb1..f18d10ce91f9 100644 --- a/drivers/usb/mon/Makefile +++ b/drivers/usb/mon/Makefile @@ -4,4 +4,4 @@ usbmon-objs := mon_main.o mon_stat.o mon_text.o -obj-$(CONFIG_USB_MON) += usbmon.o +obj-$(CONFIG_USB) += usbmon.o diff --git a/include/linux/usb.h b/include/linux/usb.h index 3d508bf08402..eb282b581546 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -290,7 +290,7 @@ struct usb_bus { struct class_device *class_dev; /* class device for this bus */ struct kref kref; /* handles reference counting 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) +#if defined(CONFIG_USB_MON) struct mon_bus *mon_bus; /* non-null when associated */ int monitored; /* non-zero when monitored */ #endif -- cgit v1.2.3 From 3e1d1d28d99dabe63c64f7f40f1ca1d646de1f73 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 24 Jun 2005 23:13:50 -0700 Subject: [PATCH] Cleanup patch for process freezing 1. Establish a simple API for process freezing defined in linux/include/sched.h: frozen(process) Check for frozen process freezing(process) Check if a process is being frozen freeze(process) Tell a process to freeze (go to refrigerator) thaw_process(process) Restart process frozen_process(process) Process is frozen now 2. Remove all references to PF_FREEZE and PF_FROZEN from all kernel sources except sched.h 3. Fix numerous locations where try_to_freeze is manually done by a driver 4. Remove the argument that is no longer necessary from two function calls. 5. Some whitespace cleanup 6. Clear potential race in refrigerator (provides an open window of PF_FREEZE cleared before setting PF_FROZEN, recalc_sigpending does not check PF_FROZEN). This patch does not address the problem of freeze_processes() violating the rule that a task may only modify its own flags by setting PF_FREEZE. This is not clean in an SMP environment. freeze(process) is therefore not SMP safe! Signed-off-by: Christoph Lameter Signed-off-by: Linus Torvalds --- Documentation/power/kernel_threads.txt | 3 +- Documentation/power/swsusp.txt | 3 +- arch/frv/kernel/signal.c | 4 +- arch/h8300/kernel/signal.c | 4 +- arch/i386/kernel/io_apic.c | 2 +- arch/i386/kernel/signal.c | 4 +- arch/m32r/kernel/signal.c | 4 +- arch/ppc/kernel/signal.c | 3 +- arch/x86_64/kernel/signal.c | 2 +- drivers/block/pktcdvd.c | 3 +- drivers/ieee1394/ieee1394_core.c | 4 +- drivers/ieee1394/nodemgr.c | 2 +- drivers/input/gameport/gameport.c | 2 +- drivers/input/serio/serio.c | 2 +- drivers/macintosh/therm_adt746x.c | 4 +- drivers/md/md.c | 3 +- drivers/media/dvb/dvb-core/dvb_frontend.c | 3 +- drivers/media/video/msp3400.c | 3 +- drivers/media/video/video-buf-dvb.c | 3 +- drivers/net/8139too.c | 2 +- drivers/net/irda/sir_kthread.c | 3 +- drivers/net/irda/stir4200.c | 4 +- drivers/net/wireless/airo.c | 2 +- drivers/pcmcia/cs.c | 2 +- drivers/pnp/pnpbios/core.c | 2 +- drivers/usb/core/hub.c | 2 +- drivers/usb/gadget/file_storage.c | 3 +- drivers/usb/storage/usb.c | 4 +- drivers/w1/w1.c | 4 +- fs/afs/kafsasyncd.c | 2 +- fs/afs/kafstimod.c | 2 +- fs/jbd/journal.c | 4 +- fs/jfs/jfs_logmgr.c | 4 +- fs/jfs/jfs_txnmgr.c | 8 ++-- fs/lockd/clntproc.c | 2 +- fs/xfs/linux-2.6/xfs_buf.c | 4 +- fs/xfs/linux-2.6/xfs_super.c | 2 +- include/linux/sched.h | 73 +++++++++++++++++++++++++------ kernel/power/process.c | 26 +++++------ kernel/sched.c | 3 +- kernel/signal.c | 5 +-- mm/pdflush.c | 2 +- mm/vmscan.c | 4 +- net/rxrpc/krxiod.c | 2 +- net/rxrpc/krxsecd.c | 2 +- net/rxrpc/krxtimod.c | 2 +- net/sunrpc/svcsock.c | 6 +-- 47 files changed, 126 insertions(+), 113 deletions(-) (limited to 'drivers/usb') diff --git a/Documentation/power/kernel_threads.txt b/Documentation/power/kernel_threads.txt index 60b548105edf..fb57784986b1 100644 --- a/Documentation/power/kernel_threads.txt +++ b/Documentation/power/kernel_threads.txt @@ -12,8 +12,7 @@ refrigerator. Code to do this looks like this: do { hub_events(); wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); } while (!signal_pending(current)); from drivers/usb/core/hub.c::hub_thread() diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt index c7c3459fde43..4e1627cc5b51 100644 --- a/Documentation/power/swsusp.txt +++ b/Documentation/power/swsusp.txt @@ -164,8 +164,7 @@ place where the thread is safe to be frozen (no kernel semaphores should be held at that point and it must be safe to sleep there), and add: - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); If the thread is needed for writing the image to storage, you should instead set the PF_NOFREEZE process flag when creating the thread. diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index d8d8f3d4304d..36a2dffc8ebd 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -536,10 +536,8 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) if (!user_mode(regs)) return 1; - if (current->flags & PF_FREEZE) { - refrigerator(0); + if (try_to_freeze()) goto no_signal; - } if (!oldset) oldset = ¤t->blocked; diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index a4799d633ef4..5aab87eae1f9 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -517,10 +517,8 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset) if ((regs->ccr & 0x10)) return 1; - if (current->flags & PF_FREEZE) { - refrigerator(0); + if (try_to_freeze()) goto no_signal; - } current->thread.esp0 = (unsigned long) regs; diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 08540bc4ba3e..2451a3a99440 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -573,7 +573,7 @@ static int balanced_irq(void *unused) for ( ; ; ) { set_current_state(TASK_INTERRUPTIBLE); time_remaining = schedule_timeout(time_remaining); - try_to_freeze(PF_FREEZE); + try_to_freeze(); if (time_after(jiffies, prev_balance_time+balanced_irq_interval)) { do_irq_balance(); diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index b9b8f4e20fad..ac5b1e975c5c 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -608,10 +608,8 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset) if (!user_mode(regs)) return 1; - if (current->flags & PF_FREEZE) { - refrigerator(0); + if (try_to_freeze) goto no_signal; - } if (!oldset) oldset = ¤t->blocked; diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index 50311eb07a24..5aef7e406ef5 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -371,10 +371,8 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) if (!user_mode(regs)) return 1; - if (current->flags & PF_FREEZE) { - refrigerator(0); + if (try_to_freeze()) goto no_signal; - } if (!oldset) oldset = ¤t->blocked; diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 7c8437da09d5..8aaeb6f4e750 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -705,8 +705,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) unsigned long frame, newsp; int signr, ret; - if (current->flags & PF_FREEZE) { - refrigerator(PF_FREEZE); + if (try_to_freeze()) { signr = 0; if (!signal_pending(current)) goto no_signal; diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index 98b7ba95d581..98590a989f3d 100644 --- a/arch/x86_64/kernel/signal.c +++ b/arch/x86_64/kernel/signal.c @@ -425,7 +425,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) if (!user_mode(regs)) return 1; - if (try_to_freeze(0)) + if (try_to_freeze()) goto no_signal; if (!oldset) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 7f3d78de265c..7b838342f0a3 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1251,8 +1251,7 @@ static int kcdrwd(void *foobar) VPRINTK("kcdrwd: wake up\n"); /* make swsusp happy with our thread */ - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { if (!pkt->sleep_time) diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 2d9a9b74e687..629070b83a33 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -1041,10 +1041,8 @@ static int hpsbpkt_thread(void *__hi) while (1) { if (down_interruptible(&khpsbpkt_sig)) { - if (current->flags & PF_FREEZE) { - refrigerator(0); + if (try_to_freeze()) continue; - } printk("khpsbpkt: received unexpected signal?!\n" ); break; } diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 32abb6dda888..9a46c3b44bf8 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -1510,7 +1510,7 @@ static int nodemgr_host_thread(void *__hi) if (down_interruptible(&hi->reset_sem) || down_interruptible(&nodemgr_serialize)) { - if (try_to_freeze(PF_FREEZE)) + if (try_to_freeze()) continue; printk("NodeMgr: received unexpected signal?!\n" ); break; diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index e152d0fa0cdd..c77a82e46055 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -439,7 +439,7 @@ static int gameport_thread(void *nothing) do { gameport_handle_events(); wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list)); - try_to_freeze(PF_FREEZE); + try_to_freeze(); } while (!signal_pending(current)); printk(KERN_DEBUG "gameport: kgameportd exiting\n"); diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index feab4970406e..341824c48529 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -344,7 +344,7 @@ static int serio_thread(void *nothing) do { serio_handle_events(); wait_event_interruptible(serio_wait, !list_empty(&serio_event_list)); - try_to_freeze(PF_FREEZE); + try_to_freeze(); } while (!signal_pending(current)); printk(KERN_DEBUG "serio: kseriod exiting\n"); diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 5ba190ce14a0..c9ca1118e449 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -328,9 +328,7 @@ static int monitor_task(void *arg) struct thermostat* th = arg; while(!kthread_should_stop()) { - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); - + try_to_freeze(); msleep_interruptible(2000); #ifndef DEBUG diff --git a/drivers/md/md.c b/drivers/md/md.c index 0c6b5b6baff6..3802f7a17f16 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2976,8 +2976,7 @@ static int md_thread(void * arg) wait_event_interruptible_timeout(thread->wqueue, test_bit(THREAD_WAKEUP, &thread->flags), thread->timeout); - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); clear_bit(THREAD_WAKEUP, &thread->flags); diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index d6b7a9de471e..f11daae91cd4 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -391,8 +391,7 @@ static int dvb_frontend_thread(void *data) break; } - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); if (down_interruptible(&fepriv->sem)) break; diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 1b7d38e96f14..b4ee9dfe6d42 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -750,8 +750,7 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout) #endif } } - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); remove_wait_queue(&msp->wq, &wait); return msp->restart; } diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index 5f870075b55e..15f5bb486963 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -62,8 +62,7 @@ static int videobuf_dvb_thread(void *data) break; if (kthread_should_stop()) break; - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); /* feed buffer data to demux */ if (buf->state == STATE_DONE) diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 047202c4d9a8..5a4a08a7c951 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1606,7 +1606,7 @@ static int rtl8139_thread (void *data) do { timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout); /* make swsusp happy with our thread */ - try_to_freeze(PF_FREEZE); + try_to_freeze(); } while (!signal_pending (current) && (timeout > 0)); if (signal_pending (current)) { diff --git a/drivers/net/irda/sir_kthread.c b/drivers/net/irda/sir_kthread.c index 18cea1099530..c65054364bca 100644 --- a/drivers/net/irda/sir_kthread.c +++ b/drivers/net/irda/sir_kthread.c @@ -135,8 +135,7 @@ static int irda_thread(void *startup) remove_wait_queue(&irda_rq_queue.kick, &wait); /* make swsusp happy with our thread */ - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); run_irda_queue(); } diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 66f488c13717..15f207323d97 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -763,7 +763,7 @@ static int stir_transmit_thread(void *arg) { #ifdef CONFIG_PM /* if suspending, then power off and wait */ - if (unlikely(current->flags & PF_FREEZE)) { + if (unlikely(freezing(current))) { if (stir->receiving) receive_stop(stir); else @@ -771,7 +771,7 @@ static int stir_transmit_thread(void *arg) write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD); - refrigerator(PF_FREEZE); + refrigerator(); if (change_speed(stir, stir->speed)) break; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index fb10a2db63ad..d72e0385e4f2 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2918,7 +2918,7 @@ static int airo_thread(void *data) { flush_signals(current); /* make swsusp happy with our thread */ - try_to_freeze(PF_FREEZE); + try_to_freeze(); if (test_bit(JOB_DIE, &ai->flags)) break; diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index d136b3c8fac9..48e4f04530d8 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -718,7 +718,7 @@ static int pccardd(void *__skt) } schedule(); - try_to_freeze(PF_FREEZE); + try_to_freeze(); if (!skt->thread) break; diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index e939c93a931c..778a324028f4 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -182,7 +182,7 @@ static int pnp_dock_thread(void * unused) msleep_interruptible(2000); if(signal_pending(current)) { - if (try_to_freeze(PF_FREEZE)) + if (try_to_freeze()) continue; break; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index d2d648ee8640..a8d879a85d04 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2808,7 +2808,7 @@ static int hub_thread(void *__unused) do { hub_events(); wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); - try_to_freeze(PF_FREEZE); + try_to_freeze(); } while (!signal_pending(current)); pr_debug ("%s: khubd exiting\n", usbcore_name); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 037a7f163822..a9be85103d23 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1554,8 +1554,7 @@ static int sleep_thread(struct fsg_dev *fsg) rc = wait_event_interruptible(fsg->thread_wqh, fsg->thread_wakeup_needed); fsg->thread_wakeup_needed = 0; - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); return (rc ? -EINTR : 0); } diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 35c1ca6b5a8e..77e7fc258aa2 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -847,10 +847,8 @@ retry: wait_event_interruptible_timeout(us->delay_wait, test_bit(US_FLIDX_DISCONNECTING, &us->flags), delay_use * HZ); - if (current->flags & PF_FREEZE) { - refrigerator(PF_FREEZE); + if (try_to_freeze()) goto retry; - } } /* If the device is still connected, perform the scanning */ diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index b460927ec32a..312cf3220f12 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -646,7 +646,7 @@ static int w1_control(void *data) while (!control_needs_exit || have_to_wait) { have_to_wait = 0; - try_to_freeze(PF_FREEZE); + try_to_freeze(); msleep_interruptible(w1_timeout * 1000); if (signal_pending(current)) @@ -725,7 +725,7 @@ int w1_process(void *data) allow_signal(SIGTERM); while (!test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { - try_to_freeze(PF_FREEZE); + try_to_freeze(); msleep_interruptible(w1_timeout * 1000); if (signal_pending(current)) diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c index 6fc88ae8ad94..7ac07d0d47b9 100644 --- a/fs/afs/kafsasyncd.c +++ b/fs/afs/kafsasyncd.c @@ -116,7 +116,7 @@ static int kafsasyncd(void *arg) remove_wait_queue(&kafsasyncd_sleepq, &myself); set_current_state(TASK_RUNNING); - try_to_freeze(PF_FREEZE); + try_to_freeze(); /* discard pending signals */ afs_discard_my_signals(); diff --git a/fs/afs/kafstimod.c b/fs/afs/kafstimod.c index 86e710dd057e..65bc05ab8182 100644 --- a/fs/afs/kafstimod.c +++ b/fs/afs/kafstimod.c @@ -91,7 +91,7 @@ static int kafstimod(void *arg) complete_and_exit(&kafstimod_dead, 0); } - try_to_freeze(PF_FREEZE); + try_to_freeze(); /* discard pending signals */ afs_discard_my_signals(); diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 1e6f2e2ad4a3..5e7b43949517 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -167,7 +167,7 @@ loop: } wake_up(&journal->j_wait_done_commit); - if (current->flags & PF_FREEZE) { + if (freezing(current)) { /* * The simpler the better. Flushing journal isn't a * good idea, because that depends on threads that may @@ -175,7 +175,7 @@ loop: */ jbd_debug(1, "Now suspending kjournald\n"); spin_unlock(&journal->j_state_lock); - refrigerator(PF_FREEZE); + refrigerator(); spin_lock(&journal->j_state_lock); } else { /* diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 7c8387ed4192..79d07624bfe1 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -2359,9 +2359,9 @@ int jfsIOWait(void *arg) lbmStartIO(bp); spin_lock_irq(&log_redrive_lock); } - if (current->flags & PF_FREEZE) { + if (freezing(current)) { spin_unlock_irq(&log_redrive_lock); - refrigerator(PF_FREEZE); + refrigerator(); } else { add_wait_queue(&jfs_IO_thread_wait, &wq); set_current_state(TASK_INTERRUPTIBLE); diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 8cbaaff1d5fa..121c981ff453 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -2788,9 +2788,9 @@ int jfs_lazycommit(void *arg) /* In case a wakeup came while all threads were active */ jfs_commit_thread_waking = 0; - if (current->flags & PF_FREEZE) { + if (freezing(current)) { LAZY_UNLOCK(flags); - refrigerator(PF_FREEZE); + refrigerator(); } else { DECLARE_WAITQUEUE(wq, current); @@ -2987,9 +2987,9 @@ int jfs_sync(void *arg) /* Add anon_list2 back to anon_list */ list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list); - if (current->flags & PF_FREEZE) { + if (freezing(current)) { TXN_UNLOCK(); - refrigerator(PF_FREEZE); + refrigerator(); } else { DECLARE_WAITQUEUE(wq, current); diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index fd77ed1d710d..14b3ce87fa29 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -313,7 +313,7 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue) prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE); if (!signalled ()) { schedule_timeout(NLMCLNT_GRACE_WAIT); - try_to_freeze(PF_FREEZE); + try_to_freeze(); if (!signalled ()) status = 0; } diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index c60e69431e11..df0cba239dd5 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1771,9 +1771,9 @@ xfsbufd( INIT_LIST_HEAD(&tmp); do { - if (unlikely(current->flags & PF_FREEZE)) { + if (unlikely(freezing(current))) { xfsbufd_force_sleep = 1; - refrigerator(PF_FREEZE); + refrigerator(); } else { xfsbufd_force_sleep = 0; } diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 5fe9af38aa20..f6dd7de25927 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -483,7 +483,7 @@ xfssyncd( set_current_state(TASK_INTERRUPTIBLE); timeleft = schedule_timeout(timeleft); /* swsusp */ - try_to_freeze(PF_FREEZE); + try_to_freeze(); if (vfsp->vfs_flag & VFS_UMOUNT) break; diff --git a/include/linux/sched.h b/include/linux/sched.h index 2c69682b0444..e7fd09b0557f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1245,33 +1245,78 @@ extern void normalize_rt_tasks(void); #endif -/* try_to_freeze - * - * Checks whether we need to enter the refrigerator - * and returns 1 if we did so. - */ #ifdef CONFIG_PM -extern void refrigerator(unsigned long); +/* + * Check if a process has been frozen + */ +static inline int frozen(struct task_struct *p) +{ + return p->flags & PF_FROZEN; +} + +/* + * Check if there is a request to freeze a process + */ +static inline int freezing(struct task_struct *p) +{ + return p->flags & PF_FREEZE; +} + +/* + * Request that a process be frozen + * FIXME: SMP problem. We may not modify other process' flags! + */ +static inline void freeze(struct task_struct *p) +{ + p->flags |= PF_FREEZE; +} + +/* + * Wake up a frozen process + */ +static inline int thaw_process(struct task_struct *p) +{ + if (frozen(p)) { + p->flags &= ~PF_FROZEN; + wake_up_process(p); + return 1; + } + return 0; +} + +/* + * freezing is complete, mark process as frozen + */ +static inline void frozen_process(struct task_struct *p) +{ + p->flags = (p->flags & ~PF_FREEZE) | PF_FROZEN; +} + +extern void refrigerator(void); extern int freeze_processes(void); extern void thaw_processes(void); -static inline int try_to_freeze(unsigned long refrigerator_flags) +static inline int try_to_freeze(void) { - if (unlikely(current->flags & PF_FREEZE)) { - refrigerator(refrigerator_flags); + if (freezing(current)) { + refrigerator(); return 1; } else return 0; } #else -static inline void refrigerator(unsigned long flag) {} +static inline int frozen(struct task_struct *p) { return 0; } +static inline int freezing(struct task_struct *p) { return 0; } +static inline void freeze(struct task_struct *p) { BUG(); } +static inline int thaw_process(struct task_struct *p) { return 1; } +static inline void frozen_process(struct task_struct *p) { BUG(); } + +static inline void refrigerator(void) {} static inline int freeze_processes(void) { BUG(); return 0; } static inline void thaw_processes(void) {} -static inline int try_to_freeze(unsigned long refrigerator_flags) -{ - return 0; -} +static inline int try_to_freeze(void) { return 0; } + #endif /* CONFIG_PM */ #endif /* __KERNEL__ */ diff --git a/kernel/power/process.c b/kernel/power/process.c index 78d92dc6a1ed..0a086640bcfc 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -32,7 +32,7 @@ static inline int freezeable(struct task_struct * p) } /* Refrigerator is place where frozen processes are stored :-). */ -void refrigerator(unsigned long flag) +void refrigerator(void) { /* Hmm, should we be allowed to suspend when there are realtime processes around? */ @@ -41,14 +41,13 @@ void refrigerator(unsigned long flag) current->state = TASK_UNINTERRUPTIBLE; pr_debug("%s entered refrigerator\n", current->comm); printk("="); - current->flags &= ~PF_FREEZE; + frozen_process(current); spin_lock_irq(¤t->sighand->siglock); recalc_sigpending(); /* We sent fake signal, clean it up */ spin_unlock_irq(¤t->sighand->siglock); - current->flags |= PF_FROZEN; - while (current->flags & PF_FROZEN) + while (frozen(current)) schedule(); pr_debug("%s left refrigerator\n", current->comm); current->state = save; @@ -57,10 +56,10 @@ void refrigerator(unsigned long flag) /* 0 = success, else # of processes that we failed to stop */ int freeze_processes(void) { - int todo; - unsigned long start_time; + int todo; + unsigned long start_time; struct task_struct *g, *p; - + printk( "Stopping tasks: " ); start_time = jiffies; do { @@ -70,14 +69,12 @@ int freeze_processes(void) unsigned long flags; if (!freezeable(p)) continue; - if ((p->flags & PF_FROZEN) || + if ((frozen(p)) || (p->state == TASK_TRACED) || (p->state == TASK_STOPPED)) continue; - /* FIXME: smp problem here: we may not access other process' flags - without locking */ - p->flags |= PF_FREEZE; + freeze(p); spin_lock_irqsave(&p->sighand->siglock, flags); signal_wake_up(p, 0); spin_unlock_irqrestore(&p->sighand->siglock, flags); @@ -91,7 +88,7 @@ int freeze_processes(void) return todo; } } while(todo); - + printk( "|\n" ); BUG_ON(in_atomic()); return 0; @@ -106,10 +103,7 @@ void thaw_processes(void) do_each_thread(g, p) { if (!freezeable(p)) continue; - if (p->flags & PF_FROZEN) { - p->flags &= ~PF_FROZEN; - wake_up_process(p); - } else + if (!thaw_process(p)) printk(KERN_INFO " Strange, %s not stopped\n", p->comm ); } while_each_thread(g, p); diff --git a/kernel/sched.c b/kernel/sched.c index 76080d142e3d..6fa9ea4ae44c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4174,8 +4174,7 @@ static int migration_thread(void * data) struct list_head *head; migration_req_t *req; - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); spin_lock_irq(&rq->lock); diff --git a/kernel/signal.c b/kernel/signal.c index d1258729a5f9..ca1186eef938 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -213,7 +213,7 @@ static inline int has_pending_signals(sigset_t *signal, sigset_t *blocked) fastcall void recalc_sigpending_tsk(struct task_struct *t) { if (t->signal->group_stop_count > 0 || - (t->flags & PF_FREEZE) || + (freezing(t)) || PENDING(&t->pending, &t->blocked) || PENDING(&t->signal->shared_pending, &t->blocked)) set_tsk_thread_flag(t, TIF_SIGPENDING); @@ -2231,8 +2231,7 @@ sys_rt_sigtimedwait(const sigset_t __user *uthese, current->state = TASK_INTERRUPTIBLE; timeout = schedule_timeout(timeout); - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); spin_lock_irq(¤t->sighand->siglock); sig = dequeue_signal(current, &these, &info); current->blocked = current->real_blocked; diff --git a/mm/pdflush.c b/mm/pdflush.c index 38ce279cc8cd..d6781951267e 100644 --- a/mm/pdflush.c +++ b/mm/pdflush.c @@ -105,7 +105,7 @@ static int __pdflush(struct pdflush_work *my_work) spin_unlock_irq(&pdflush_lock); schedule(); - if (try_to_freeze(PF_FREEZE)) { + if (try_to_freeze()) { spin_lock_irq(&pdflush_lock); continue; } diff --git a/mm/vmscan.c b/mm/vmscan.c index 4b8e62a19370..1fa312a8db77 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1216,8 +1216,8 @@ static int kswapd(void *p) order = 0; for ( ; ; ) { unsigned long new_order; - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + + try_to_freeze(); prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE); new_order = pgdat->kswapd_max_order; diff --git a/net/rxrpc/krxiod.c b/net/rxrpc/krxiod.c index 2b537f425a17..dada34a77b21 100644 --- a/net/rxrpc/krxiod.c +++ b/net/rxrpc/krxiod.c @@ -138,7 +138,7 @@ static int rxrpc_krxiod(void *arg) _debug("### End Work"); - try_to_freeze(PF_FREEZE); + try_to_freeze(); /* discard pending signals */ rxrpc_discard_my_signals(); diff --git a/net/rxrpc/krxsecd.c b/net/rxrpc/krxsecd.c index 6020c89d9228..1aadd026d354 100644 --- a/net/rxrpc/krxsecd.c +++ b/net/rxrpc/krxsecd.c @@ -107,7 +107,7 @@ static int rxrpc_krxsecd(void *arg) _debug("### End Inbound Calls"); - try_to_freeze(PF_FREEZE); + try_to_freeze(); /* discard pending signals */ rxrpc_discard_my_signals(); diff --git a/net/rxrpc/krxtimod.c b/net/rxrpc/krxtimod.c index 249c2b0290bb..3ac81cdd1211 100644 --- a/net/rxrpc/krxtimod.c +++ b/net/rxrpc/krxtimod.c @@ -90,7 +90,7 @@ static int krxtimod(void *arg) complete_and_exit(&krxtimod_dead, 0); } - try_to_freeze(PF_FREEZE); + try_to_freeze(); /* discard pending signals */ rxrpc_discard_my_signals(); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 05907035bc96..56db8f13e6cb 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1185,8 +1185,8 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) arg->page_len = (pages-2)*PAGE_SIZE; arg->len = (pages-1)*PAGE_SIZE; arg->tail[0].iov_len = 0; - - try_to_freeze(PF_FREEZE); + + try_to_freeze(); if (signalled()) return -EINTR; @@ -1227,7 +1227,7 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) schedule_timeout(timeout); - try_to_freeze(PF_FREEZE); + try_to_freeze(); spin_lock_bh(&serv->sv_lock); remove_wait_queue(&rqstp->rq_wait, &wait); -- cgit v1.2.3 From e8d997952bbea4f408f56a55f18667f2817dbb44 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 25 May 2005 16:06:59 +0900 Subject: [PATCH] NETDEV: Elecom (Laneed) LD-USBL/TX support. Elecom (Laneed) LD-USBL/TX support. Signed-off-by: YOSHIFUJI Hideaki --- drivers/usb/net/pegasus.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h index 13ccedef5c7e..b98f2a833442 100644 --- a/drivers/usb/net/pegasus.h +++ b/drivers/usb/net/pegasus.h @@ -249,6 +249,8 @@ PEGASUS_DEV( "Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a, DEFAULT_GPIO_RESET) PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002, DEFAULT_GPIO_RESET ) +PEGASUS_DEV( "LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005, + DEFAULT_GPIO_RESET | PEGASUS_II) PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1, -- cgit v1.2.3 From ae0a97bfda598088b6f97db9d9f65cd6c4f439c6 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 25 May 2005 16:07:04 +0900 Subject: [PATCH] NETDEV: fix receiving multicast frames. Some USB ethernet drivers did not accept multicast frames appropriately. IPv6 did not work with those drivers without this patch. Signed-off-by: YOSHIFUJI Hideaki --- drivers/usb/net/pegasus.c | 2 +- drivers/usb/net/rtl8150.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index d976790312aa..5f4496d8dbac 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -1166,7 +1166,7 @@ static void pegasus_set_multicast(struct net_device *net) pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS; if (netif_msg_link(pegasus)) pr_info("%s: Promiscuous mode enabled.\n", net->name); - } else if ((net->mc_count > multicast_filter_limit) || + } else if (net->mc_count || (net->flags & IFF_ALLMULTI)) { pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index 8fb223385f2f..626b016addff 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -667,7 +667,7 @@ static void rtl8150_set_multicast(struct net_device *netdev) if (netdev->flags & IFF_PROMISC) { dev->rx_creg |= cpu_to_le16(0x0001); info("%s: promiscuous mode", netdev->name); - } else if ((netdev->mc_count > multicast_filter_limit) || + } else if (netdev->mc_count || (netdev->flags & IFF_ALLMULTI)) { dev->rx_creg &= cpu_to_le16(0xfffe); dev->rx_creg |= cpu_to_le16(0x0002); -- cgit v1.2.3 From 76f4af8efc72b6091d230cbe718cedca06d2d79e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 5 Apr 2005 11:56:54 -0400 Subject: [PATCH] USB: g_file_storage: Consolidate min()s This patch simplifies the g_file_storage driver by consolidating a bunch of min() calculations at a single spot. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index a9be85103d23..507a24924177 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1312,7 +1312,7 @@ static int class_setup_req(struct fsg_dev *fsg, } VDBG(fsg, "get max LUN\n"); *(u8 *) req->buf = fsg->nluns - 1; - value = min(w_length, (u16) 1); + value = 1; break; } } @@ -1360,7 +1360,6 @@ static int standard_setup_req(struct fsg_dev *fsg, int value = -EOPNOTSUPP; u16 w_index = ctrl->wIndex; u16 w_value = ctrl->wValue; - u16 w_length = ctrl->wLength; /* Usually this just stores reply data in the pre-allocated ep0 buffer, * but config change events will also reconfigure hardware. */ @@ -1374,7 +1373,7 @@ static int standard_setup_req(struct fsg_dev *fsg, case USB_DT_DEVICE: VDBG(fsg, "get device descriptor\n"); - value = min(w_length, (u16) sizeof device_desc); + value = sizeof device_desc; memcpy(req->buf, &device_desc, value); break; #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -1382,7 +1381,7 @@ static int standard_setup_req(struct fsg_dev *fsg, VDBG(fsg, "get device qualifier\n"); if (!fsg->gadget->is_dualspeed) break; - value = min(w_length, (u16) sizeof dev_qualifier); + value = sizeof dev_qualifier; memcpy(req->buf, &dev_qualifier, value); break; @@ -1401,8 +1400,6 @@ static int standard_setup_req(struct fsg_dev *fsg, req->buf, w_value >> 8, w_value & 0xff); - if (value >= 0) - value = min(w_length, (u16) value); break; case USB_DT_STRING: @@ -1411,8 +1408,6 @@ static int standard_setup_req(struct fsg_dev *fsg, /* wIndex == language code */ value = usb_gadget_get_string(&stringtab, w_value & 0xff, req->buf); - if (value >= 0) - value = min(w_length, (u16) value); break; } break; @@ -1438,7 +1433,7 @@ static int standard_setup_req(struct fsg_dev *fsg, break; VDBG(fsg, "get configuration\n"); *(u8 *) req->buf = fsg->config; - value = min(w_length, (u16) 1); + value = 1; break; case USB_REQ_SET_INTERFACE: @@ -1466,14 +1461,14 @@ static int standard_setup_req(struct fsg_dev *fsg, } VDBG(fsg, "get interface\n"); *(u8 *) req->buf = 0; - value = min(w_length, (u16) 1); + value = 1; break; default: VDBG(fsg, "unknown control req %02x.%02x v%04x i%04x l%u\n", ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, w_length); + w_value, w_index, ctrl->wLength); } return value; @@ -1485,6 +1480,7 @@ static int fsg_setup(struct usb_gadget *gadget, { struct fsg_dev *fsg = get_gadget_data(gadget); int rc; + int w_length = ctrl->wLength; ++fsg->ep0_req_tag; // Record arrival of a new request fsg->ep0req->context = NULL; @@ -1498,8 +1494,9 @@ static int fsg_setup(struct usb_gadget *gadget, /* Respond with data/status or defer until later? */ if (rc >= 0 && rc != DELAYED_STATUS) { + rc = min(rc, w_length); fsg->ep0req->length = rc; - fsg->ep0req->zero = (rc < ctrl->wLength && + fsg->ep0req->zero = (rc < w_length && (rc % gadget->ep0->maxpacket) == 0); fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"); -- cgit v1.2.3 From d794ac7ae3613c2abfb678617ac7d74c8ff0099c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 18 Apr 2005 12:43:25 -0400 Subject: [PATCH] USB: g_file_storage: export "stall" parameter This patch changes the g_file_storage driver to make the "stall" module parameter generally available; currently it is available only if the testing version of the module has been configured. It also fixes a typo in a comment -- thanks, Pat! Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 507a24924177..f5ce45c4b2a3 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -81,6 +81,10 @@ * removable Default false, boolean for removable media * luns=N Default N = number of filenames, number of * LUNs to support + * stall Default determined according to the type of + * USB device controller (usually true), + * boolean to permit the driver to halt + * bulk endpoints * transport=XXX Default BBB, transport name (CB, CBI, or BBB) * protocol=YYY Default SCSI, protocol name (RBC, 8020 or * ATAPI, QIC, UFI, 8070, or SCSI; @@ -91,14 +95,10 @@ * buflen=N Default N=16384, buffer size used (will be * rounded down to a multiple of * PAGE_CACHE_SIZE) - * stall Default determined according to the type of - * USB device controller (usually true), - * boolean to permit the driver to halt - * bulk endpoints * * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", - * "removable", and "luns" options are available; default values are used - * for everything else. + * "removable", "luns", and "stall" options are available; default values + * are used for everything else. * * The pathnames of the backing files and the ro settings are available in * the attribute files "file" and "ro" in the lun subdirectory of the @@ -342,14 +342,15 @@ static struct { int num_ros; unsigned int nluns; + int removable; + int can_stall; + char *transport_parm; char *protocol_parm; - int removable; unsigned short vendor; unsigned short product; unsigned short release; unsigned int buflen; - int can_stall; int transport_type; char *transport_name; @@ -360,11 +361,11 @@ static struct { .transport_parm = "BBB", .protocol_parm = "SCSI", .removable = 0, + .can_stall = 1, .vendor = DRIVER_VENDOR_ID, .product = DRIVER_PRODUCT_ID, .release = 0xffff, // Use controller chip type .buflen = 16384, - .can_stall = 1, }; @@ -380,6 +381,9 @@ MODULE_PARM_DESC(luns, "number of LUNs"); module_param_named(removable, mod_data.removable, bool, S_IRUGO); MODULE_PARM_DESC(removable, "true to simulate removable media"); +module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); +MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); + /* In the non-TEST version, only the module parameters listed above * are available. */ @@ -404,9 +408,6 @@ MODULE_PARM_DESC(release, "USB release number"); module_param_named(buflen, mod_data.buflen, uint, S_IRUGO); MODULE_PARM_DESC(buflen, "I/O buffer size"); -module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); -MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); - #endif /* CONFIG_USB_FILE_STORAGE_TEST */ @@ -2657,7 +2658,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, } } - /* Check that the LUN values are oonsistent */ + /* Check that the LUN values are consistent */ if (transport_is_bbb()) { if (fsg->lun != lun) DBG(fsg, "using LUN %d from CBW, " -- cgit v1.2.3 From 313980c92724cf42877a7bdafdef439ee9d68ccb Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 11 Apr 2005 15:38:25 -0700 Subject: [PATCH] USB: omap_udc updates (mostly cleanups) Various USB patches, mostly for portability: - Fifo mode 1 didn't work previously (oopsed), so now it's fixed and (why not) defines even more endpoints for composite devices. - OMAP 1710 doesn't have an internal transceiver. - Small PM update: if the USB link is suspended, don't disconnect on entry to deep sleep. - Be more correct about handling zero length control reads. OMAP seems to mis-handle that protocol peculiarity though; best avoided. - Platform device resources (for UDC and OTG controllers) now use physical addresses, so /proc/iomem is more consistent. - Minor cleanups, notably (by volume) for "sparse" NULL warnings. Signed-off-by: David Brownell --- arch/arm/mach-omap/usb.c | 8 +-- drivers/usb/gadget/omap_udc.c | 150 ++++++++++++++++++++++++++---------------- 2 files changed, 97 insertions(+), 61 deletions(-) (limited to 'drivers/usb') diff --git a/arch/arm/mach-omap/usb.c b/arch/arm/mach-omap/usb.c index 6e805d451d0e..7f37857b1a28 100644 --- a/arch/arm/mach-omap/usb.c +++ b/arch/arm/mach-omap/usb.c @@ -288,8 +288,8 @@ static void usb_release(struct device *dev) static struct resource udc_resources[] = { /* order is significant! */ { /* registers */ - .start = IO_ADDRESS(UDC_BASE), - .end = IO_ADDRESS(UDC_BASE + 0xff), + .start = UDC_BASE, + .end = UDC_BASE + 0xff, .flags = IORESOURCE_MEM, }, { /* general IRQ */ .start = IH2_BASE + 20, @@ -355,8 +355,8 @@ static struct platform_device ohci_device = { static struct resource otg_resources[] = { /* order is significant! */ { - .start = IO_ADDRESS(OTG_BASE), - .end = IO_ADDRESS(OTG_BASE + 0xff), + .start = OTG_BASE, + .end = OTG_BASE + 0xff, .flags = IORESOURCE_MEM, }, { .start = IH2_BASE + 8, diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 98cbcbc16cc1..4ec91a68f96c 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -52,7 +52,6 @@ #include #include -#include #include #include "omap_udc.h" @@ -253,7 +252,7 @@ static int omap_ep_disable(struct usb_ep *_ep) } spin_lock_irqsave(&ep->udc->lock, flags); - ep->desc = 0; + ep->desc = NULL; nuke (ep, -ESHUTDOWN); ep->ep.maxpacket = ep->maxpacket; ep->has_dma = 0; @@ -388,8 +387,8 @@ done(struct omap_ep *ep, struct omap_req *req, int status) /*-------------------------------------------------------------------------*/ -#define FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL) -#define FIFO_UNWRITABLE (UDC_EP_HALTED | FIFO_FULL) +#define UDC_FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL) +#define UDC_FIFO_UNWRITABLE (UDC_EP_HALTED | UDC_FIFO_FULL) #define FIFO_EMPTY (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY) #define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY) @@ -433,7 +432,7 @@ static int write_fifo(struct omap_ep *ep, struct omap_req *req) /* PIO-IN isn't double buffered except for iso */ ep_stat = UDC_STAT_FLG_REG; - if (ep_stat & FIFO_UNWRITABLE) + if (ep_stat & UDC_FIFO_UNWRITABLE) return 0; count = ep->ep.maxpacket; @@ -504,7 +503,7 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req) if (ep_stat & UDC_EP_HALTED) break; - if (ep_stat & FIFO_FULL) + if (ep_stat & UDC_FIFO_FULL) avail = ep->ep.maxpacket; else { avail = UDC_RXFSTAT_REG; @@ -856,7 +855,7 @@ static void dma_channel_release(struct omap_ep *ep) if (!list_empty(&ep->queue)) req = container_of(ep->queue.next, struct omap_req, queue); else - req = 0; + req = NULL; active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0; @@ -997,18 +996,19 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) UDC_IRQ_EN_REG = irq_en; } - /* STATUS is reverse direction */ - UDC_EP_NUM_REG = is_in - ? UDC_EP_SEL - : (UDC_EP_SEL|UDC_EP_DIR); + /* STATUS for zero length DATA stages is + * always an IN ... even for IN transfers, + * a wierd case which seem to stall OMAP. + */ + UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR); UDC_CTRL_REG = UDC_CLR_EP; UDC_CTRL_REG = UDC_SET_FIFO_EN; - UDC_EP_NUM_REG = udc->ep0_in ? 0 : UDC_EP_DIR; + UDC_EP_NUM_REG = UDC_EP_DIR; /* cleanup */ udc->ep0_pending = 0; done(ep, req, 0); - req = 0; + req = NULL; /* non-empty DATA stage */ } else if (is_in) { @@ -1029,7 +1029,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) (is_in ? next_in_dma : next_out_dma)(ep, req); else if (req) { if ((is_in ? write_fifo : read_fifo)(ep, req) == 1) - req = 0; + req = NULL; deselect_ep(); if (!is_in) { UDC_CTRL_REG = UDC_SET_FIFO_EN; @@ -1041,7 +1041,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) irq_wait: /* irq handler advances the queue */ - if (req != 0) + if (req != NULL) list_add_tail(&req->queue, &ep->queue); spin_unlock_irqrestore(&udc->lock, flags); @@ -1238,6 +1238,8 @@ static int can_pullup(struct omap_udc *udc) static void pullup_enable(struct omap_udc *udc) { + udc->gadget.dev.parent->power.power_state = PMSG_ON; + udc->gadget.dev.power.power_state = PMSG_ON; UDC_SYSCON1_REG |= UDC_PULLUP_EN; #ifndef CONFIG_USB_OTG if (!cpu_is_omap15xx()) @@ -1382,7 +1384,7 @@ static void update_otg(struct omap_udc *udc) static void ep0_irq(struct omap_udc *udc, u16 irq_src) { struct omap_ep *ep0 = &udc->ep[0]; - struct omap_req *req = 0; + struct omap_req *req = NULL; ep0->irqs++; @@ -1438,7 +1440,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) if (req) done(ep0, req, 0); } - req = 0; + req = NULL; } else if (stat & UDC_STALL) { UDC_CTRL_REG = UDC_CLR_HALT; UDC_EP_NUM_REG = UDC_EP_DIR; @@ -1511,9 +1513,6 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) u.word[3] = UDC_DATA_REG; UDC_EP_NUM_REG = 0; } while (UDC_IRQ_SRC_REG & UDC_SETUP); - le16_to_cpus (&u.r.wValue); - le16_to_cpus (&u.r.wIndex); - le16_to_cpus (&u.r.wLength); /* Delegate almost all control requests to the gadget driver, * except for a handful of ch9 status/feature requests that @@ -1566,6 +1565,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) UDC_CTRL_REG = UDC_SET_FIFO_EN; ep->ackwait = 1 + ep->double_buf; } + /* NOTE: assumes the host behaves sanely, + * only clearing real halts. Else we may + * need to kill pending transfers and then + * restart the queue... very messy for DMA! + */ } VDBG("%s halt cleared by host\n", ep->name); goto ep0out_status_stage; @@ -2013,7 +2017,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) udc->softconnect = 1; /* hook up the driver */ - driver->driver.bus = 0; + driver->driver.bus = NULL; udc->driver = driver; udc->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc->lock, flags); @@ -2021,8 +2025,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) status = driver->bind (&udc->gadget); if (status) { DBG("bind to %s --> %d\n", driver->driver.name, status); - udc->gadget.dev.driver = 0; - udc->driver = 0; + udc->gadget.dev.driver = NULL; + udc->driver = NULL; goto done; } DBG("bound to driver %s\n", driver->driver.name); @@ -2035,8 +2039,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) if (status < 0) { ERR("can't bind to transceiver\n"); driver->unbind (&udc->gadget); - udc->gadget.dev.driver = 0; - udc->driver = 0; + udc->gadget.dev.driver = NULL; + udc->driver = NULL; goto done; } } else { @@ -2071,7 +2075,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) omap_vbus_session(&udc->gadget, 0); if (udc->transceiver) - (void) otg_set_peripheral(udc->transceiver, 0); + (void) otg_set_peripheral(udc->transceiver, NULL); else pullup_disable(udc); @@ -2080,9 +2084,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) spin_unlock_irqrestore(&udc->lock, flags); driver->unbind(&udc->gadget); - udc->gadget.dev.driver = 0; - udc->driver = 0; - + udc->gadget.dev.driver = NULL; + udc->driver = NULL; DBG("unregistered driver '%s'\n", driver->driver.name); return status; @@ -2178,7 +2181,7 @@ static int proc_otg_show(struct seq_file *s) tmp = OTG_REV_REG; trans = USB_TRANSCEIVER_CTRL_REG; - seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %03x\n", + seq_printf(s, "\nOTG 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," @@ -2235,6 +2238,7 @@ static int proc_otg_show(struct seq_file *s) seq_printf(s, "otg_outctrl %04x" "\n", tmp); tmp = OTG_TEST_REG; seq_printf(s, "otg_test %04x" "\n", tmp); + return 0; } static int proc_udc_show(struct seq_file *s, void *_) @@ -2378,7 +2382,7 @@ static int proc_udc_show(struct seq_file *s, void *_) static int proc_udc_open(struct inode *inode, struct file *file) { - return single_open(file, proc_udc_show, 0); + return single_open(file, proc_udc_show, NULL); } static struct file_operations proc_ops = { @@ -2399,7 +2403,7 @@ static void create_proc_file(void) static void remove_proc_file(void) { - remove_proc_entry(proc_filename, 0); + remove_proc_entry(proc_filename, NULL); } #else @@ -2505,7 +2509,7 @@ static void omap_udc_release(struct device *dev) { complete(udc->done); kfree (udc); - udc = 0; + udc = NULL; } static int __init @@ -2577,23 +2581,33 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv) case 1: OMAP_BULK_EP("ep1in", USB_DIR_IN | 1); OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2); + OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16); + OMAP_BULK_EP("ep3in", USB_DIR_IN | 3); OMAP_BULK_EP("ep4out", USB_DIR_OUT | 4); + OMAP_INT_EP("ep10in", USB_DIR_IN | 10, 16); OMAP_BULK_EP("ep5in", USB_DIR_IN | 5); OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5); + OMAP_INT_EP("ep11in", USB_DIR_IN | 11, 16); + OMAP_BULK_EP("ep6in", USB_DIR_IN | 6); OMAP_BULK_EP("ep6out", USB_DIR_OUT | 6); + OMAP_INT_EP("ep12in", USB_DIR_IN | 12, 16); OMAP_BULK_EP("ep7in", USB_DIR_IN | 7); OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7); + OMAP_INT_EP("ep13in", USB_DIR_IN | 13, 16); + OMAP_INT_EP("ep13out", USB_DIR_OUT | 13, 16); + OMAP_BULK_EP("ep8in", USB_DIR_IN | 8); OMAP_BULK_EP("ep8out", USB_DIR_OUT | 8); + OMAP_INT_EP("ep14in", USB_DIR_IN | 14, 16); + OMAP_INT_EP("ep14out", USB_DIR_OUT | 14, 16); + + OMAP_BULK_EP("ep15in", USB_DIR_IN | 15); + OMAP_BULK_EP("ep15out", USB_DIR_OUT | 15); - OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16); - OMAP_INT_EP("ep10out", USB_DIR_IN | 10, 16); - OMAP_INT_EP("ep11in", USB_DIR_IN | 9, 16); - OMAP_INT_EP("ep12out", USB_DIR_IN | 10, 16); break; #ifdef USE_ISO @@ -2640,8 +2654,8 @@ static int __init omap_udc_probe(struct device *dev) struct platform_device *odev = to_platform_device(dev); int status = -ENODEV; int hmc; - struct otg_transceiver *xceiv = 0; - const char *type = 0; + struct otg_transceiver *xceiv = NULL; + const char *type = NULL; struct omap_usb_config *config = dev->platform_data; /* NOTE: "knows" the order of the resources! */ @@ -2678,6 +2692,15 @@ static int __init omap_udc_probe(struct device *dev) } else { hmc = HMC_1610; switch (hmc) { + case 0: /* POWERUP DEFAULT == 0 */ + case 4: + case 12: + case 20: + if (!cpu_is_omap1710()) { + type = "integrated"; + break; + } + /* FALL THROUGH */ case 3: case 11: case 16: @@ -2688,21 +2711,15 @@ static int __init omap_udc_probe(struct device *dev) DBG("external transceiver not registered!\n"); if (config->otg) goto cleanup0; - type = "(unknown external)"; + type = "unknown"; } else type = xceiv->label; break; - case 0: /* POWERUP DEFAULT == 0 */ - case 4: - case 12: - case 20: - type = "INTEGRATED"; - break; case 21: /* internal loopback */ - type = "(loopback)"; + type = "loopback"; break; case 14: /* transceiverless */ - type = "(none)"; + type = "no"; break; default: @@ -2710,14 +2727,14 @@ static int __init omap_udc_probe(struct device *dev) return -ENODEV; } } - INFO("hmc mode %d, transceiver %s\n", hmc, type); + INFO("hmc mode %d, %s transceiver\n", hmc, type); /* a "gadget" abstracts/virtualizes the controller */ status = omap_udc_setup(odev, xceiv); if (status) { goto cleanup0; } - xceiv = 0; + xceiv = NULL; // "udc" is now valid pullup_disable(udc); #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) @@ -2765,7 +2782,7 @@ cleanup2: cleanup1: kfree (udc); - udc = 0; + udc = NULL; cleanup0: if (xceiv) @@ -2788,7 +2805,7 @@ static int __exit omap_udc_remove(struct device *dev) pullup_disable(udc); if (udc->transceiver) { put_device(udc->transceiver->dev); - udc->transceiver = 0; + udc->transceiver = NULL; } UDC_SYSCON1_REG = 0; @@ -2809,13 +2826,32 @@ static int __exit omap_udc_remove(struct device *dev) return 0; } -static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level) +/* suspend/resume/wakeup from sysfs (echo > power/state) or when the + * system is forced into deep sleep + * + * REVISIT we should probably reject suspend requests when there's a host + * session active, rather than disconnecting, at least on boards that can + * report VBUS irqs (UDC_DEVSTAT_REG.UDC_ATT). And in any case, we need to + * make host resumes and VBUS detection trigger OMAP wakeup events; that + * may involve talking to an external transceiver (e.g. isp1301). + */ +static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level) { - if (level != 0) + u32 devstat; + + if (level != SUSPEND_POWER_DOWN) return 0; + devstat = UDC_DEVSTAT_REG; + + /* we're requesting 48 MHz clock if the pullup is enabled + * (== we're attached to the host) and we're not suspended, + * which would prevent entry to deep sleep... + */ + if ((devstat & UDC_ATT) != 0 && (devstat & UDC_SUS) == 0) { + WARN("session active; suspend requires disconnect\n"); + omap_pullup(&udc->gadget, 0); + } - DBG("suspend, state %d\n", state); - omap_pullup(&udc->gadget, 0); udc->gadget.dev.power.power_state = PMSG_SUSPEND; udc->gadget.dev.parent->power.power_state = PMSG_SUSPEND; return 0; @@ -2823,7 +2859,7 @@ static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level) static int omap_udc_resume(struct device *dev, u32 level) { - if (level != 0) + if (level != RESUME_POWER_ON) return 0; DBG("resume + wakeup/SRP\n"); -- cgit v1.2.3 From 4808a1c0261176f9c7e28e7f108d41a381a7d0fc Mon Sep 17 00:00:00 2001 From: Olav Kongas Date: Sat, 9 Apr 2005 22:57:39 +0300 Subject: [PATCH] USB: Add isp116x-hcd USB host controller driver This patch provides an "isp116x-hcd" driver for Philips' ISP1160/ISP1161 USB host controllers. The driver: - is relatively small, meant for use on embedded platforms. - runs usbtests 1-14 without problems for days. - has been in use by 6-7 different people on ARM and PPC platforms, running a range of devices including USB hubs. - supports suspend/resume of both the platform device and the root hub; supports remote wakeup of the root hub (but NOT the platform device) by USB devices. - does NOT support ISO transfers (nobody has asked for them). - is PIO-only. Signed-off-by: Olav Kongas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + drivers/usb/host/Kconfig | 13 + drivers/usb/host/Makefile | 1 + drivers/usb/host/isp116x-hcd.c | 1882 ++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/isp116x.h | 583 +++++++++++++ include/linux/usb_isp116x.h | 47 + 6 files changed, 2527 insertions(+) create mode 100644 drivers/usb/host/isp116x-hcd.c create mode 100644 drivers/usb/host/isp116x.h create mode 100644 include/linux/usb_isp116x.h (limited to 'drivers/usb') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index a61d4433a989..c149c06388be 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_USB) += core/ obj-$(CONFIG_USB_MON) += mon/ obj-$(CONFIG_USB_EHCI_HCD) += host/ +obj-$(CONFIG_USB_ISP116X_HCD) += host/ obj-$(CONFIG_USB_OHCI_HCD) += host/ obj-$(CONFIG_USB_UHCI_HCD) += host/ obj-$(CONFIG_USB_SL811_HCD) += host/ diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 19e598c9641f..ed1899d307db 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -49,6 +49,19 @@ config USB_EHCI_ROOT_HUB_TT This supports the EHCI implementation from TransDimension Inc. +config USB_ISP116X_HCD + tristate "ISP116X HCD support" + depends on USB + default N + ---help--- + The ISP1160 and ISP1161 chips are USB host controllers. Enable this + option if your board has this chip. If unsure, say N. + + This driver does not support isochronous transfers. + + To compile this driver as a module, choose M here: the + module will be called isp116x-hcd. + config USB_OHCI_HCD tristate "OHCI HCD support" depends on USB && USB_ARCH_HAS_OHCI diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 5dbd3e7a27c7..350d14fc1cc9 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -4,6 +4,7 @@ # obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o +obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c new file mode 100644 index 000000000000..69e7433d9ce8 --- /dev/null +++ b/drivers/usb/host/isp116x-hcd.c @@ -0,0 +1,1882 @@ +/* + * ISP116x HCD (Host Controller Driver) for USB. + * + * Derived from the SL811 HCD, rewritten for ISP116x. + * Copyright (C) 2005 Olav Kongas + * + * Portions: + * Copyright (C) 2004 Psion Teklogix (for NetBook PRO) + * Copyright (C) 2004 David Brownell + * + * Periodic scheduling is based on Roman's OHCI code + * Copyright (C) 1999 Roman Weissgaerber + * + */ + +/* + * The driver basically works. A number of people have used it with a range + * of devices. + * + *The driver passes all usbtests 1-14. + * + * Suspending/resuming of root hub via sysfs works. Remote wakeup works too. + * And suspending/resuming of platform device works too. Suspend/resume + * via HCD operations vector is not implemented. + * + * Iso transfer support is not implemented. Adding this would include + * implementing recovery from the failure to service the processed ITL + * fifo ram in time, which will involve chip reset. + * + * TODO: + + More testing of suspend/resume. +*/ + +/* + ISP116x chips require certain delays between accesses to its + registers. The following timing options exist. + + 1. Configure your memory controller (the best) + 2. Implement platform-specific delay function possibly + combined with configuring the memory controller; see + include/linux/usb-isp116x.h for more info. Some broken + memory controllers line LH7A400 SMC need this. Also, + uncomment for that to work the following + USE_PLATFORM_DELAY macro. + 3. Use ndelay (easiest, poorest). For that, uncomment + the following USE_NDELAY macro. +*/ +#define USE_PLATFORM_DELAY +//#define USE_NDELAY + +//#define DEBUG +//#define VERBOSE +/* Transfer descriptors. See dump_ptd() for printout format */ +//#define PTD_TRACE +/* enqueuing/finishing log of urbs */ +//#define URB_TRACE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef DEBUG +# define STUB_DEBUG_FILE +#endif + +#include "../core/hcd.h" +#include "isp116x.h" + +#define DRIVER_VERSION "08 Apr 2005" +#define DRIVER_DESC "ISP116x USB Host Controller Driver" + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +static const char hcd_name[] = "isp116x-hcd"; + +/*-----------------------------------------------------------------*/ + +/* + Write len bytes to fifo, pad till 32-bit boundary + */ +static void write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, int len) +{ + u8 *dp = (u8 *) buf; + u16 *dp2 = (u16 *) buf; + u16 w; + int quot = len % 4; + + if ((unsigned long)dp2 & 1) { + /* not aligned */ + for (; len > 1; len -= 2) { + w = *dp++; + w |= *dp++ << 8; + isp116x_raw_write_data16(isp116x, w); + } + if (len) + isp116x_write_data16(isp116x, (u16) * dp); + } else { + /* aligned */ + for (; len > 1; len -= 2) + isp116x_raw_write_data16(isp116x, *dp2++); + if (len) + isp116x_write_data16(isp116x, 0xff & *((u8 *) dp2)); + } + if (quot == 1 || quot == 2) + isp116x_raw_write_data16(isp116x, 0); +} + +/* + Read len bytes from fifo and then read till 32-bit boundary. + */ +static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len) +{ + u8 *dp = (u8 *) buf; + u16 *dp2 = (u16 *) buf; + u16 w; + int quot = len % 4; + + if ((unsigned long)dp2 & 1) { + /* not aligned */ + for (; len > 1; len -= 2) { + w = isp116x_raw_read_data16(isp116x); + *dp++ = w & 0xff; + *dp++ = (w >> 8) & 0xff; + } + if (len) + *dp = 0xff & isp116x_read_data16(isp116x); + } else { + /* aligned */ + for (; len > 1; len -= 2) + *dp2++ = isp116x_raw_read_data16(isp116x); + if (len) + *(u8 *) dp2 = 0xff & isp116x_read_data16(isp116x); + } + if (quot == 1 || quot == 2) + isp116x_raw_read_data16(isp116x); +} + +/* + Write ptd's and data for scheduled transfers into + the fifo ram. Fifo must be empty and ready. +*/ +static void pack_fifo(struct isp116x *isp116x) +{ + struct isp116x_ep *ep; + struct ptd *ptd; + int buflen = isp116x->atl_last_dir == PTD_DIR_IN + ? isp116x->atl_bufshrt : isp116x->atl_buflen; + int ptd_count = 0; + + isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT); + isp116x_write_reg16(isp116x, HCXFERCTR, buflen); + isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET); + for (ep = isp116x->atl_active; ep; ep = ep->active) { + ++ptd_count; + ptd = &ep->ptd; + dump_ptd(ptd); + dump_ptd_out_data(ptd, ep->data); + isp116x_write_data16(isp116x, ptd->count); + isp116x_write_data16(isp116x, ptd->mps); + isp116x_write_data16(isp116x, ptd->len); + isp116x_write_data16(isp116x, ptd->faddr); + buflen -= sizeof(struct ptd); + /* Skip writing data for last IN PTD */ + if (ep->active || (isp116x->atl_last_dir != PTD_DIR_IN)) { + write_ptddata_to_fifo(isp116x, ep->data, ep->length); + buflen -= ALIGN(ep->length, 4); + } + } + BUG_ON(buflen); +} + +/* + Read the processed ptd's and data from fifo ram back to + URBs' buffers. Fifo must be full and done +*/ +static void unpack_fifo(struct isp116x *isp116x) +{ + struct isp116x_ep *ep; + struct ptd *ptd; + int buflen = isp116x->atl_last_dir == PTD_DIR_IN + ? isp116x->atl_buflen : isp116x->atl_bufshrt; + + isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT); + isp116x_write_reg16(isp116x, HCXFERCTR, buflen); + isp116x_write_addr(isp116x, HCATLPORT); + for (ep = isp116x->atl_active; ep; ep = ep->active) { + ptd = &ep->ptd; + ptd->count = isp116x_read_data16(isp116x); + ptd->mps = isp116x_read_data16(isp116x); + ptd->len = isp116x_read_data16(isp116x); + ptd->faddr = isp116x_read_data16(isp116x); + buflen -= sizeof(struct ptd); + /* Skip reading data for last Setup or Out PTD */ + if (ep->active || (isp116x->atl_last_dir == PTD_DIR_IN)) { + read_ptddata_from_fifo(isp116x, ep->data, ep->length); + buflen -= ALIGN(ep->length, 4); + } + dump_ptd(ptd); + dump_ptd_in_data(ptd, ep->data); + } + BUG_ON(buflen); +} + +/*---------------------------------------------------------------*/ + +/* + Set up PTD's. +*/ +static void preproc_atl_queue(struct isp116x *isp116x) +{ + struct isp116x_ep *ep; + struct urb *urb; + struct ptd *ptd; + u16 toggle, dir, len; + + for (ep = isp116x->atl_active; ep; ep = ep->active) { + BUG_ON(list_empty(&ep->hep->urb_list)); + urb = container_of(ep->hep->urb_list.next, + struct urb, urb_list); + ptd = &ep->ptd; + len = ep->length; + spin_lock(&urb->lock); + ep->data = (unsigned char *)urb->transfer_buffer + + urb->actual_length; + + switch (ep->nextpid) { + case USB_PID_IN: + toggle = usb_gettoggle(urb->dev, ep->epnum, 0); + dir = PTD_DIR_IN; + break; + case USB_PID_OUT: + toggle = usb_gettoggle(urb->dev, ep->epnum, 1); + dir = PTD_DIR_OUT; + break; + case USB_PID_SETUP: + toggle = 0; + dir = PTD_DIR_SETUP; + len = sizeof(struct usb_ctrlrequest); + ep->data = urb->setup_packet; + break; + case USB_PID_ACK: + toggle = 1; + len = 0; + dir = (urb->transfer_buffer_length + && usb_pipein(urb->pipe)) + ? PTD_DIR_OUT : PTD_DIR_IN; + break; + default: + /* To please gcc */ + toggle = dir = 0; + ERR("%s %d: ep->nextpid %d\n", __func__, __LINE__, + ep->nextpid); + BUG_ON(1); + } + + ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK | PTD_TOGGLE(toggle); + ptd->mps = PTD_MPS(ep->maxpacket) + | PTD_SPD(urb->dev->speed == USB_SPEED_LOW) + | PTD_EP(ep->epnum); + ptd->len = PTD_LEN(len) | PTD_DIR(dir); + ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe)); + spin_unlock(&urb->lock); + if (!ep->active) { + ptd->mps |= PTD_LAST_MSK; + isp116x->atl_last_dir = dir; + } + isp116x->atl_bufshrt = sizeof(struct ptd) + isp116x->atl_buflen; + isp116x->atl_buflen = isp116x->atl_bufshrt + ALIGN(len, 4); + } +} + +/* + Analyze transfer results, handle partial transfers and errors +*/ +static void postproc_atl_queue(struct isp116x *isp116x) +{ + struct isp116x_ep *ep; + struct urb *urb; + struct usb_device *udev; + struct ptd *ptd; + int short_not_ok; + u8 cc; + + for (ep = isp116x->atl_active; ep; ep = ep->active) { + BUG_ON(list_empty(&ep->hep->urb_list)); + urb = + container_of(ep->hep->urb_list.next, struct urb, urb_list); + udev = urb->dev; + ptd = &ep->ptd; + cc = PTD_GET_CC(ptd); + + spin_lock(&urb->lock); + short_not_ok = 1; + + /* Data underrun is special. For allowed underrun + we clear the error and continue as normal. For + forbidden underrun we finish the DATA stage + immediately while for control transfer, + we do a STATUS stage. */ + if (cc == TD_DATAUNDERRUN) { + if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) { + DBG("Allowed data underrun\n"); + cc = TD_CC_NOERROR; + short_not_ok = 0; + } else { + ep->error_count = 1; + if (usb_pipecontrol(urb->pipe)) + ep->nextpid = USB_PID_ACK; + else + usb_settoggle(udev, ep->epnum, + ep->nextpid == + USB_PID_OUT, + PTD_GET_TOGGLE(ptd) ^ 1); + urb->status = cc_to_error[TD_DATAUNDERRUN]; + spin_unlock(&urb->lock); + continue; + } + } + /* Keep underrun error through the STATUS stage */ + if (urb->status == cc_to_error[TD_DATAUNDERRUN]) + cc = TD_DATAUNDERRUN; + + if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED + && (++ep->error_count >= 3 || cc == TD_CC_STALL + || cc == TD_DATAOVERRUN)) { + if (urb->status == -EINPROGRESS) + urb->status = cc_to_error[cc]; + if (ep->nextpid == USB_PID_ACK) + ep->nextpid = 0; + spin_unlock(&urb->lock); + continue; + } + /* According to usb spec, zero-length Int transfer signals + finishing of the urb. Hey, does this apply only + for IN endpoints? */ + if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) { + if (urb->status == -EINPROGRESS) + urb->status = 0; + spin_unlock(&urb->lock); + continue; + } + + /* Relax after previously failed, but later succeeded + or correctly NAK'ed retransmission attempt */ + if (ep->error_count + && (cc == TD_CC_NOERROR || cc == TD_NOTACCESSED)) + ep->error_count = 0; + + /* Take into account idiosyncracies of the isp116x chip + regarding toggle bit for failed transfers */ + if (ep->nextpid == USB_PID_OUT) + usb_settoggle(udev, ep->epnum, 1, PTD_GET_TOGGLE(ptd) + ^ (ep->error_count > 0)); + else if (ep->nextpid == USB_PID_IN) + usb_settoggle(udev, ep->epnum, 0, PTD_GET_TOGGLE(ptd) + ^ (ep->error_count > 0)); + + switch (ep->nextpid) { + case USB_PID_IN: + case USB_PID_OUT: + urb->actual_length += PTD_GET_COUNT(ptd); + if (PTD_GET_ACTIVE(ptd) + || (cc != TD_CC_NOERROR && cc < 0x0E)) + break; + if (urb->transfer_buffer_length != urb->actual_length) { + if (short_not_ok) + break; + } else { + if (urb->transfer_flags & URB_ZERO_PACKET + && ep->nextpid == USB_PID_OUT + && !(PTD_GET_COUNT(ptd) % ep->maxpacket)) { + DBG("Zero packet requested\n"); + break; + } + } + /* All data for this URB is transferred, let's finish */ + if (usb_pipecontrol(urb->pipe)) + ep->nextpid = USB_PID_ACK; + else if (urb->status == -EINPROGRESS) + urb->status = 0; + break; + case USB_PID_SETUP: + if (PTD_GET_ACTIVE(ptd) + || (cc != TD_CC_NOERROR && cc < 0x0E)) + break; + if (urb->transfer_buffer_length == urb->actual_length) + ep->nextpid = USB_PID_ACK; + else if (usb_pipeout(urb->pipe)) { + usb_settoggle(udev, 0, 1, 1); + ep->nextpid = USB_PID_OUT; + } else { + usb_settoggle(udev, 0, 0, 1); + ep->nextpid = USB_PID_IN; + } + break; + case USB_PID_ACK: + if (PTD_GET_ACTIVE(ptd) + || (cc != TD_CC_NOERROR && cc < 0x0E)) + break; + if (urb->status == -EINPROGRESS) + urb->status = 0; + ep->nextpid = 0; + break; + default: + BUG_ON(1); + } + spin_unlock(&urb->lock); + } +} + +/* + Take done or failed requests out of schedule. Give back + processed urbs. +*/ +static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep, + struct urb *urb, struct pt_regs *regs) +__releases(isp116x->lock) __acquires(isp116x->lock) +{ + unsigned i; + + urb->hcpriv = NULL; + ep->error_count = 0; + + if (usb_pipecontrol(urb->pipe)) + ep->nextpid = USB_PID_SETUP; + + urb_dbg(urb, "Finish"); + + spin_unlock(&isp116x->lock); + usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, regs); + spin_lock(&isp116x->lock); + + /* take idle endpoints out of the schedule */ + if (!list_empty(&ep->hep->urb_list)) + return; + + /* async deschedule */ + if (!list_empty(&ep->schedule)) { + list_del_init(&ep->schedule); + return; + } + + /* periodic deschedule */ + DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); + for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { + struct isp116x_ep *temp; + struct isp116x_ep **prev = &isp116x->periodic[i]; + + while (*prev && ((temp = *prev) != ep)) + prev = &temp->next; + if (*prev) + *prev = ep->next; + isp116x->load[i] -= ep->load; + } + ep->branch = PERIODIC_SIZE; + isp116x_to_hcd(isp116x)->self.bandwidth_allocated -= + ep->load / ep->period; + + /* switch irq type? */ + if (!--isp116x->periodic_count) { + isp116x->irqenb &= ~HCuPINT_SOF; + isp116x->irqenb |= HCuPINT_ATL; + } +} + +/* + Scan transfer lists, schedule transfers, send data off + to chip. + */ +static void start_atl_transfers(struct isp116x *isp116x) +{ + struct isp116x_ep *last_ep = NULL, *ep; + struct urb *urb; + u16 load = 0; + int len, index, speed, byte_time; + + if (atomic_read(&isp116x->atl_finishing)) + return; + + if (!HC_IS_RUNNING(isp116x_to_hcd(isp116x)->state)) + return; + + /* FIFO not empty? */ + if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL) + return; + + isp116x->atl_active = NULL; + isp116x->atl_buflen = isp116x->atl_bufshrt = 0; + + /* Schedule int transfers */ + if (isp116x->periodic_count) { + isp116x->fmindex = index = + (isp116x->fmindex + 1) & (PERIODIC_SIZE - 1); + if ((load = isp116x->load[index])) { + /* Bring all int transfers for this frame + into the active queue */ + isp116x->atl_active = last_ep = + isp116x->periodic[index]; + while (last_ep->next) + last_ep = (last_ep->active = last_ep->next); + last_ep->active = NULL; + } + } + + /* Schedule control/bulk transfers */ + list_for_each_entry(ep, &isp116x->async, schedule) { + urb = container_of(ep->hep->urb_list.next, + struct urb, urb_list); + speed = urb->dev->speed; + byte_time = speed == USB_SPEED_LOW + ? BYTE_TIME_LOWSPEED : BYTE_TIME_FULLSPEED; + + if (ep->nextpid == USB_PID_SETUP) { + len = sizeof(struct usb_ctrlrequest); + } else if (ep->nextpid == USB_PID_ACK) { + len = 0; + } else { + /* Find current free length ... */ + len = (MAX_LOAD_LIMIT - load) / byte_time; + + /* ... then limit it to configured max size ... */ + len = min(len, speed == USB_SPEED_LOW ? + MAX_TRANSFER_SIZE_LOWSPEED : + MAX_TRANSFER_SIZE_FULLSPEED); + + /* ... and finally cut to the multiple of MaxPacketSize, + or to the real length if there's enough room. */ + if (len < + (urb->transfer_buffer_length - + urb->actual_length)) { + len -= len % ep->maxpacket; + if (!len) + continue; + } else + len = urb->transfer_buffer_length - + urb->actual_length; + BUG_ON(len < 0); + } + + load += len * byte_time; + if (load > MAX_LOAD_LIMIT) + break; + + ep->active = NULL; + ep->length = len; + if (last_ep) + last_ep->active = ep; + else + isp116x->atl_active = ep; + last_ep = ep; + } + + /* Avoid starving of endpoints */ + if ((&isp116x->async)->next != (&isp116x->async)->prev) + list_move(&isp116x->async, (&isp116x->async)->next); + + if (isp116x->atl_active) { + preproc_atl_queue(isp116x); + pack_fifo(isp116x); + } +} + +/* + Finish the processed transfers +*/ +static void finish_atl_transfers(struct isp116x *isp116x, struct pt_regs *regs) +{ + struct isp116x_ep *ep; + struct urb *urb; + + if (!isp116x->atl_active) + return; + /* Fifo not ready? */ + if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE)) + return; + + atomic_inc(&isp116x->atl_finishing); + unpack_fifo(isp116x); + postproc_atl_queue(isp116x); + for (ep = isp116x->atl_active; ep; ep = ep->active) { + urb = + container_of(ep->hep->urb_list.next, struct urb, urb_list); + /* USB_PID_ACK check here avoids finishing of + control transfers, for which TD_DATAUNDERRUN + occured, while URB_SHORT_NOT_OK was set */ + if (urb && urb->status != -EINPROGRESS + && ep->nextpid != USB_PID_ACK) + finish_request(isp116x, ep, urb, regs); + } + atomic_dec(&isp116x->atl_finishing); +} + +static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs) +{ + struct isp116x *isp116x = hcd_to_isp116x(hcd); + u16 irqstat; + irqreturn_t ret = IRQ_NONE; + + spin_lock(&isp116x->lock); + isp116x_write_reg16(isp116x, HCuPINTENB, 0); + irqstat = isp116x_read_reg16(isp116x, HCuPINT); + isp116x_write_reg16(isp116x, HCuPINT, irqstat); + + if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) { + ret = IRQ_HANDLED; + finish_atl_transfers(isp116x, regs); + } + + if (irqstat & HCuPINT_OPR) { + u32 intstat = isp116x_read_reg32(isp116x, HCINTSTAT); + isp116x_write_reg32(isp116x, HCINTSTAT, intstat); + if (intstat & HCINT_UE) { + ERR("Unrecoverable error\n"); + /* What should we do here? Reset? */ + } + if (intstat & HCINT_RHSC) { + isp116x->rhstatus = + isp116x_read_reg32(isp116x, HCRHSTATUS); + isp116x->rhport[0] = + isp116x_read_reg32(isp116x, HCRHPORT1); + isp116x->rhport[1] = + isp116x_read_reg32(isp116x, HCRHPORT2); + } + if (intstat & HCINT_RD) { + DBG("---- remote wakeup\n"); + schedule_work(&isp116x->rh_resume); + ret = IRQ_HANDLED; + } + irqstat &= ~HCuPINT_OPR; + ret = IRQ_HANDLED; + } + + if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) { + start_atl_transfers(isp116x); + } + + isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb); + spin_unlock(&isp116x->lock); + return ret; +} + +/*-----------------------------------------------------------------*/ + +/* usb 1.1 says max 90% of a frame is available for periodic transfers. + * this driver doesn't promise that much since it's got to handle an + * IRQ per packet; irq handling latencies also use up that time. + */ + +/* out of 1000 us */ +#define MAX_PERIODIC_LOAD 600 +static int balance(struct isp116x *isp116x, u16 period, u16 load) +{ + int i, branch = -ENOSPC; + + /* search for the least loaded schedule branch of that period + which has enough bandwidth left unreserved. */ + for (i = 0; i < period; i++) { + if (branch < 0 || isp116x->load[branch] > isp116x->load[i]) { + int j; + + for (j = i; j < PERIODIC_SIZE; j += period) { + if ((isp116x->load[j] + load) + > MAX_PERIODIC_LOAD) + break; + } + if (j < PERIODIC_SIZE) + continue; + branch = i; + } + } + return branch; +} + +/* NB! ALL the code above this point runs with isp116x->lock + held, irqs off +*/ + +/*-----------------------------------------------------------------*/ + +static int isp116x_urb_enqueue(struct usb_hcd *hcd, + struct usb_host_endpoint *hep, struct urb *urb, + int mem_flags) +{ + struct isp116x *isp116x = hcd_to_isp116x(hcd); + struct usb_device *udev = urb->dev; + unsigned int pipe = urb->pipe; + int is_out = !usb_pipein(pipe); + int type = usb_pipetype(pipe); + int epnum = usb_pipeendpoint(pipe); + struct isp116x_ep *ep = NULL; + unsigned long flags; + int i; + int ret = 0; + + urb_dbg(urb, "Enqueue"); + + if (type == PIPE_ISOCHRONOUS) { + ERR("Isochronous transfers not supported\n"); + urb_dbg(urb, "Refused to enqueue"); + return -ENXIO; + } + /* avoid all allocations within spinlocks: request or endpoint */ + if (!hep->hcpriv) { + ep = kcalloc(1, sizeof *ep, (__force unsigned)mem_flags); + if (!ep) + return -ENOMEM; + } + + spin_lock_irqsave(&isp116x->lock, flags); + if (!HC_IS_RUNNING(hcd->state)) { + ret = -ENODEV; + goto fail; + } + + if (hep->hcpriv) + ep = hep->hcpriv; + else { + INIT_LIST_HEAD(&ep->schedule); + ep->udev = usb_get_dev(udev); + ep->epnum = epnum; + ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out); + usb_settoggle(udev, epnum, is_out, 0); + + if (type == PIPE_CONTROL) { + ep->nextpid = USB_PID_SETUP; + } else if (is_out) { + ep->nextpid = USB_PID_OUT; + } else { + ep->nextpid = USB_PID_IN; + } + + if (urb->interval) { + /* + With INT URBs submitted, the driver works with SOF + interrupt enabled and ATL interrupt disabled. After + the PTDs are written to fifo ram, the chip starts + fifo processing and usb transfers after the next + SOF and continues until the transfers are finished + (succeeded or failed) or the frame ends. Therefore, + the transfers occur only in every second frame, + while fifo reading/writing and data processing + occur in every other second frame. */ + if (urb->interval < 2) + urb->interval = 2; + if (urb->interval > 2 * PERIODIC_SIZE) + urb->interval = 2 * PERIODIC_SIZE; + ep->period = urb->interval >> 1; + ep->branch = PERIODIC_SIZE; + ep->load = usb_calc_bus_time(udev->speed, + !is_out, + (type == PIPE_ISOCHRONOUS), + usb_maxpacket(udev, pipe, + is_out)) / + 1000; + } + hep->hcpriv = ep; + ep->hep = hep; + } + + /* maybe put endpoint into schedule */ + switch (type) { + case PIPE_CONTROL: + case PIPE_BULK: + if (list_empty(&ep->schedule)) + list_add_tail(&ep->schedule, &isp116x->async); + break; + case PIPE_INTERRUPT: + urb->interval = ep->period; + ep->length = min((int)ep->maxpacket, + urb->transfer_buffer_length); + + /* urb submitted for already existing endpoint */ + if (ep->branch < PERIODIC_SIZE) + break; + + ret = ep->branch = balance(isp116x, ep->period, ep->load); + if (ret < 0) + goto fail; + ret = 0; + + urb->start_frame = (isp116x->fmindex & (PERIODIC_SIZE - 1)) + + ep->branch; + + /* sort each schedule branch by period (slow before fast) + to share the faster parts of the tree without needing + dummy/placeholder nodes */ + DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); + for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { + struct isp116x_ep **prev = &isp116x->periodic[i]; + struct isp116x_ep *here = *prev; + + while (here && ep != here) { + if (ep->period > here->period) + break; + prev = &here->next; + here = *prev; + } + if (ep != here) { + ep->next = here; + *prev = ep; + } + isp116x->load[i] += ep->load; + } + hcd->self.bandwidth_allocated += ep->load / ep->period; + + /* switch over to SOFint */ + if (!isp116x->periodic_count++) { + isp116x->irqenb &= ~HCuPINT_ATL; + isp116x->irqenb |= HCuPINT_SOF; + isp116x_write_reg16(isp116x, HCuPINTENB, + isp116x->irqenb); + } + } + + /* in case of unlink-during-submit */ + spin_lock(&urb->lock); + if (urb->status != -EINPROGRESS) { + spin_unlock(&urb->lock); + finish_request(isp116x, ep, urb, NULL); + ret = 0; + goto fail; + } + urb->hcpriv = hep; + spin_unlock(&urb->lock); + start_atl_transfers(isp116x); + + fail: + spin_unlock_irqrestore(&isp116x->lock, flags); + return ret; +} + +/* + Dequeue URBs. +*/ +static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +{ + struct isp116x *isp116x = hcd_to_isp116x(hcd); + struct usb_host_endpoint *hep; + struct isp116x_ep *ep, *ep_act; + unsigned long flags; + + spin_lock_irqsave(&isp116x->lock, flags); + hep = urb->hcpriv; + /* URB already unlinked (or never linked)? */ + if (!hep) { + spin_unlock_irqrestore(&isp116x->lock, flags); + return 0; + } + ep = hep->hcpriv; + WARN_ON(hep != ep->hep); + + /* In front of queue? */ + if (ep->hep->urb_list.next == &urb->urb_list) + /* active? */ + for (ep_act = isp116x->atl_active; ep_act; + ep_act = ep_act->active) + if (ep_act == ep) { + VDBG("dequeue, urb %p active; wait for irq\n", + urb); + urb = NULL; + break; + } + + if (urb) + finish_request(isp116x, ep, urb, NULL); + + spin_unlock_irqrestore(&isp116x->lock, flags); + return 0; +} + +static void isp116x_endpoint_disable(struct usb_hcd *hcd, + struct usb_host_endpoint *hep) +{ + int i; + struct isp116x_ep *ep = hep->hcpriv;; + + if (!ep) + return; + + /* assume we'd just wait for the irq */ + for (i = 0; i < 100 && !list_empty(&hep->urb_list); i++) + msleep(3); + if (!list_empty(&hep->urb_list)) + WARN("ep %p not empty?\n", ep); + + usb_put_dev(ep->udev); + kfree(ep); + hep->hcpriv = NULL; +} + +static int isp116x_get_frame(struct usb_hcd *hcd) +{ + struct isp116x *isp116x = hcd_to_isp116x(hcd); + u32 fmnum; + unsigned long flags; + + spin_lock_irqsave(&isp116x->lock, flags); + fmnum = isp116x_read_reg32(isp116x, HCFMNUM); + spin_unlock_irqrestore(&isp116x->lock, flags); + return (int)fmnum; +} + +/*----------------------------------------------------------------*/ + +/* + Adapted from ohci-hub.c. Currently we don't support autosuspend. +*/ +static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct isp116x *isp116x = hcd_to_isp116x(hcd); + int ports, i, changed = 0; + + if (!HC_IS_RUNNING(hcd->state)) + return -ESHUTDOWN; + + ports = isp116x->rhdesca & RH_A_NDP; + + /* init status */ + if (isp116x->rhstatus & (RH_HS_LPSC | RH_HS_OCIC)) + buf[0] = changed = 1; + else + buf[0] = 0; + + for (i = 0; i < ports; i++) { + u32 status = isp116x->rhport[i]; + + if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC + | RH_PS_OCIC | RH_PS_PRSC)) { + changed = 1; + buf[0] |= 1 << (i + 1); + continue; + } + } + return changed; +} + +static void isp116x_hub_descriptor(struct isp116x *isp116x, + struct usb_hub_descriptor *desc) +{ + u32 reg = isp116x->rhdesca; + + desc->bDescriptorType = 0x29; + desc->bDescLength = 9; + desc->bHubContrCurrent = 0; + desc->bNbrPorts = (u8) (reg & 0x3); + /* Power switching, device type, overcurrent. */ + desc->wHubCharacteristics = + (__force __u16) cpu_to_le16((u16) ((reg >> 8) & 0x1f)); + desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff); + /* two bitmaps: ports removable, and legacy PortPwrCtrlMask */ + desc->bitmap[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1; + desc->bitmap[1] = ~0; +} + +/* Perform reset of a given port. + It would be great to just start the reset and let the + USB core to clear the reset in due time. However, + root hub ports should be reset for at least 50 ms, while + our chip stays in reset for about 10 ms. I.e., we must + repeatedly reset it ourself here. +*/ +static inline void root_port_reset(struct isp116x *isp116x, unsigned port) +{ + u32 tmp; + unsigned long flags, t; + + /* Root hub reset should be 50 ms, but some devices + want it even longer. */ + t = jiffies + msecs_to_jiffies(100); + + while (time_before(jiffies, t)) { + spin_lock_irqsave(&isp116x->lock, flags); + /* spin until any current reset finishes */ + for (;;) { + tmp = isp116x_read_reg32(isp116x, port ? + HCRHPORT2 : HCRHPORT1); + if (!(tmp & RH_PS_PRS)) + break; + udelay(500); + } + /* Don't reset a disconnected port */ + if (!(tmp & RH_PS_CCS)) { + spin_unlock_irqrestore(&isp116x->lock, flags); + break; + } + /* Reset lasts 10ms (claims datasheet) */ + isp116x_write_reg32(isp116x, port ? HCRHPORT2 : + HCRHPORT1, (RH_PS_PRS)); + spin_unlock_irqrestore(&isp116x->lock, flags); + msleep(10); + } +} + +/* Adapted from ohci-hub.c */ +static int isp116x_hub_control(struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, u16 wIndex, char *buf, u16 wLength) +{ + struct isp116x *isp116x = hcd_to_isp116x(hcd); + int ret = 0; + unsigned long flags; + int ports = isp116x->rhdesca & RH_A_NDP; + u32 tmp = 0; + + switch (typeReq) { + case ClearHubFeature: + DBG("ClearHubFeature: "); + switch (wValue) { + case C_HUB_OVER_CURRENT: + DBG("C_HUB_OVER_CURRENT\n"); + spin_lock_irqsave(&isp116x->lock, flags); + isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC); + spin_unlock_irqrestore(&isp116x->lock, flags); + case C_HUB_LOCAL_POWER: + DBG("C_HUB_LOCAL_POWER\n"); + break; + default: + goto error; + } + break; + case SetHubFeature: + DBG("SetHubFeature: "); + switch (wValue) { + case C_HUB_OVER_CURRENT: + case C_HUB_LOCAL_POWER: + DBG("C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n"); + break; + default: + goto error; + } + break; + case GetHubDescriptor: + DBG("GetHubDescriptor\n"); + isp116x_hub_descriptor(isp116x, + (struct usb_hub_descriptor *)buf); + break; + case GetHubStatus: + DBG("GetHubStatus\n"); + *(__le32 *) buf = cpu_to_le32(0); + break; + case GetPortStatus: + DBG("GetPortStatus\n"); + if (!wIndex || wIndex > ports) + goto error; + tmp = isp116x->rhport[--wIndex]; + *(__le32 *) buf = cpu_to_le32(tmp); + DBG("GetPortStatus: port[%d] %08x\n", wIndex + 1, tmp); + break; + case ClearPortFeature: + DBG("ClearPortFeature: "); + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + DBG("USB_PORT_FEAT_ENABLE\n"); + tmp = RH_PS_CCS; + break; + case USB_PORT_FEAT_C_ENABLE: + DBG("USB_PORT_FEAT_C_ENABLE\n"); + tmp = RH_PS_PESC; + break; + case USB_PORT_FEAT_SUSPEND: + DBG("USB_PORT_FEAT_SUSPEND\n"); + tmp = RH_PS_POCI; + break; + case USB_PORT_FEAT_C_SUSPEND: + DBG("USB_PORT_FEAT_C_SUSPEND\n"); + tmp = RH_PS_PSSC; + break; + case USB_PORT_FEAT_POWER: + DBG("USB_PORT_FEAT_POWER\n"); + tmp = RH_PS_LSDA; + break; + case USB_PORT_FEAT_C_CONNECTION: + DBG("USB_PORT_FEAT_C_CONNECTION\n"); + tmp = RH_PS_CSC; + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + DBG("USB_PORT_FEAT_C_OVER_CURRENT\n"); + tmp = RH_PS_OCIC; + break; + case USB_PORT_FEAT_C_RESET: + DBG("USB_PORT_FEAT_C_RESET\n"); + tmp = RH_PS_PRSC; + break; + default: + goto error; + } + spin_lock_irqsave(&isp116x->lock, flags); + isp116x_write_reg32(isp116x, wIndex + ? HCRHPORT2 : HCRHPORT1, tmp); + isp116x->rhport[wIndex] = + isp116x_read_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1); + spin_unlock_irqrestore(&isp116x->lock, flags); + break; + case SetPortFeature: + DBG("SetPortFeature: "); + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + DBG("USB_PORT_FEAT_SUSPEND\n"); + spin_lock_irqsave(&isp116x->lock, flags); + isp116x_write_reg32(isp116x, wIndex + ? HCRHPORT2 : HCRHPORT1, RH_PS_PSS); + break; + case USB_PORT_FEAT_POWER: + DBG("USB_PORT_FEAT_POWER\n"); + spin_lock_irqsave(&isp116x->lock, flags); + isp116x_write_reg32(isp116x, wIndex + ? HCRHPORT2 : HCRHPORT1, RH_PS_PPS); + break; + case USB_PORT_FEAT_RESET: + DBG("USB_PORT_FEAT_RESET\n"); + root_port_reset(isp116x, wIndex); + spin_lock_irqsave(&isp116x->lock, flags); + break; + default: + goto error; + } + isp116x->rhport[wIndex] = + isp116x_read_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1); + spin_unlock_irqrestore(&isp116x->lock, flags); + break; + + default: + error: + /* "protocol stall" on error */ + DBG("PROTOCOL STALL\n"); + ret = -EPIPE; + } + return ret; +} + +#ifdef CONFIG_PM + +static int isp116x_hub_suspend(struct usb_hcd *hcd) +{ + struct isp116x *isp116x = hcd_to_isp116x(hcd); + unsigned long flags; + u32 val; + int ret = 0; + + spin_lock_irqsave(&isp116x->lock, flags); + + val = isp116x_read_reg32(isp116x, HCCONTROL); + switch (val & HCCONTROL_HCFS) { + case HCCONTROL_USB_OPER: + hcd->state = HC_STATE_QUIESCING; + val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE); + val |= HCCONTROL_USB_SUSPEND; + if (hcd->remote_wakeup) + val |= HCCONTROL_RWE; + /* Wait for usb transfers to finish */ + mdelay(2); + isp116x_write_reg32(isp116x, HCCONTROL, val); + hcd->state = HC_STATE_SUSPENDED; + /* Wait for devices to suspend */ + mdelay(5); + case HCCONTROL_USB_SUSPEND: + break; + case HCCONTROL_USB_RESUME: + isp116x_write_reg32(isp116x, HCCONTROL, + (val & ~HCCONTROL_HCFS) | + HCCONTROL_USB_RESET); + case HCCONTROL_USB_RESET: + ret = -EBUSY; + break; + default: + ret = -EINVAL; + } + + spin_unlock_irqrestore(&isp116x->lock, flags); + return ret; +} + +static int isp116x_hub_resume(struct usb_hcd *hcd) +{ + struct isp116x *isp116x = hcd_to_isp116x(hcd); + u32 val; + int ret = -EINPROGRESS; + + msleep(5); + spin_lock_irq(&isp116x->lock); + + val = isp116x_read_reg32(isp116x, HCCONTROL); + switch (val & HCCONTROL_HCFS) { + case HCCONTROL_USB_SUSPEND: + val &= ~HCCONTROL_HCFS; + val |= HCCONTROL_USB_RESUME; + isp116x_write_reg32(isp116x, HCCONTROL, val); + case HCCONTROL_USB_RESUME: + break; + case HCCONTROL_USB_OPER: + /* Without setting power_state here the + SUSPENDED state won't be removed from + sysfs/usbN/power.state as a response to remote + wakeup. Maybe in the future. */ + hcd->self.root_hub->dev.power.power_state = PMSG_ON; + ret = 0; + break; + default: + ret = -EBUSY; + } + + if (ret != -EINPROGRESS) { + spin_unlock_irq(&isp116x->lock); + return ret; + } + + val = isp116x->rhdesca & RH_A_NDP; + while (val--) { + u32 stat = + isp116x_read_reg32(isp116x, val ? HCRHPORT2 : HCRHPORT1); + /* force global, not selective, resume */ + if (!(stat & RH_PS_PSS)) + continue; + DBG("%s: Resuming port %d\n", __func__, val); + isp116x_write_reg32(isp116x, RH_PS_POCI, val + ? HCRHPORT2 : HCRHPORT1); + } + spin_unlock_irq(&isp116x->lock); + + hcd->state = HC_STATE_RESUMING; + mdelay(20); + + /* Go operational */ + spin_lock_irq(&isp116x->lock); + val = isp116x_read_reg32(isp116x, HCCONTROL); + isp116x_write_reg32(isp116x, HCCONTROL, + (val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER); + spin_unlock_irq(&isp116x->lock); + /* see analogous comment above */ + hcd->self.root_hub->dev.power.power_state = PMSG_ON; + hcd->state = HC_STATE_RUNNING; + + return 0; +} + +static void isp116x_rh_resume(void *_hcd) +{ + struct usb_hcd *hcd = _hcd; + + usb_resume_device(hcd->self.root_hub); +} + +#else + +#define isp116x_hub_suspend NULL +#define isp116x_hub_resume NULL + +static void isp116x_rh_resume(void *_hcd) +{ +} + +#endif + +/*-----------------------------------------------------------------*/ + +#ifdef STUB_DEBUG_FILE + +static inline void create_debug_file(struct isp116x *isp116x) +{ +} + +static inline void remove_debug_file(struct isp116x *isp116x) +{ +} + +#else + +#include +#include + +static void dump_irq(struct seq_file *s, char *label, u16 mask) +{ + seq_printf(s, "%s %04x%s%s%s%s%s%s\n", label, mask, + mask & HCuPINT_CLKRDY ? " clkrdy" : "", + mask & HCuPINT_SUSP ? " susp" : "", + mask & HCuPINT_OPR ? " opr" : "", + mask & HCuPINT_AIIEOT ? " eot" : "", + mask & HCuPINT_ATL ? " atl" : "", + mask & HCuPINT_SOF ? " sof" : ""); +} + +static void dump_int(struct seq_file *s, char *label, u32 mask) +{ + seq_printf(s, "%s %08x%s%s%s%s%s%s%s\n", label, mask, + mask & HCINT_MIE ? " MIE" : "", + mask & HCINT_RHSC ? " rhsc" : "", + mask & HCINT_FNO ? " fno" : "", + mask & HCINT_UE ? " ue" : "", + mask & HCINT_RD ? " rd" : "", + mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : ""); +} + +static int proc_isp116x_show(struct seq_file *s, void *unused) +{ + struct isp116x *isp116x = s->private; + struct isp116x_ep *ep; + struct urb *urb; + unsigned i; + char *str; + + seq_printf(s, "%s\n%s version %s\n", + isp116x_to_hcd(isp116x)->product_desc, hcd_name, + DRIVER_VERSION); + + if (HC_IS_SUSPENDED(isp116x_to_hcd(isp116x)->state)) { + seq_printf(s, "HCD is suspended\n"); + return 0; + } + if (!HC_IS_RUNNING(isp116x_to_hcd(isp116x)->state)) { + seq_printf(s, "HCD not running\n"); + return 0; + } + + spin_lock_irq(&isp116x->lock); + + dump_irq(s, "hc_irq_enable", isp116x_read_reg16(isp116x, HCuPINTENB)); + dump_irq(s, "hc_irq_status", isp116x_read_reg16(isp116x, HCuPINT)); + dump_int(s, "hc_int_enable", isp116x_read_reg32(isp116x, HCINTENB)); + dump_int(s, "hc_int_status", isp116x_read_reg32(isp116x, HCINTSTAT)); + + list_for_each_entry(ep, &isp116x->async, schedule) { + + switch (ep->nextpid) { + case USB_PID_IN: + str = "in"; + break; + case USB_PID_OUT: + str = "out"; + break; + case USB_PID_SETUP: + str = "setup"; + break; + case USB_PID_ACK: + str = "status"; + break; + default: + str = "?"; + break; + }; + seq_printf(s, "%p, ep%d%s, maxpacket %d:\n", ep, + ep->epnum, str, ep->maxpacket); + list_for_each_entry(urb, &ep->hep->urb_list, urb_list) { + seq_printf(s, " urb%p, %d/%d\n", urb, + urb->actual_length, + urb->transfer_buffer_length); + } + } + if (!list_empty(&isp116x->async)) + seq_printf(s, "\n"); + + seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE); + + for (i = 0; i < PERIODIC_SIZE; i++) { + ep = isp116x->periodic[i]; + if (!ep) + continue; + seq_printf(s, "%2d [%3d]:\n", i, isp116x->load[i]); + + /* DUMB: prints shared entries multiple times */ + do { + seq_printf(s, " %d/%p (%sdev%d ep%d%s max %d)\n", + ep->period, ep, + (ep->udev->speed == + USB_SPEED_FULL) ? "" : "ls ", + ep->udev->devnum, ep->epnum, + (ep->epnum == + 0) ? "" : ((ep->nextpid == + USB_PID_IN) ? "in" : "out"), + ep->maxpacket); + ep = ep->next; + } while (ep); + } + spin_unlock_irq(&isp116x->lock); + seq_printf(s, "\n"); + + return 0; +} + +static int proc_isp116x_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_isp116x_show, PDE(inode)->data); +} + +static struct file_operations proc_ops = { + .open = proc_isp116x_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* expect just one isp116x per system */ +static const char proc_filename[] = "driver/isp116x"; + +static void create_debug_file(struct isp116x *isp116x) +{ + struct proc_dir_entry *pde; + + pde = create_proc_entry(proc_filename, 0, NULL); + if (pde == NULL) + return; + + pde->proc_fops = &proc_ops; + pde->data = isp116x; + isp116x->pde = pde; +} + +static void remove_debug_file(struct isp116x *isp116x) +{ + if (isp116x->pde) + remove_proc_entry(proc_filename, NULL); +} + +#endif + +/*-----------------------------------------------------------------*/ + +/* + Software reset - can be called from any contect. +*/ +static int isp116x_sw_reset(struct isp116x *isp116x) +{ + int retries = 15; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&isp116x->lock, flags); + isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC); + isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR); + while (--retries) { + /* It usually resets within 1 ms */ + mdelay(1); + if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR)) + break; + } + if (!retries) { + ERR("Software reset timeout\n"); + ret = -ETIME; + } + spin_unlock_irqrestore(&isp116x->lock, flags); + return ret; +} + +/* + Reset. Tries to perform platform-specific hardware + reset first; falls back to software reset. +*/ +static int isp116x_reset(struct usb_hcd *hcd) +{ + struct isp116x *isp116x = hcd_to_isp116x(hcd); + unsigned long t; + u16 clkrdy = 0; + int ret = 0, timeout = 15 /* ms */ ; + + if (isp116x->board && isp116x->board->reset) { + /* Hardware reset */ + isp116x->board->reset(hcd->self.controller, 1); + msleep(10); + if (isp116x->board->clock) + isp116x->board->clock(hcd->self.controller, 1); + msleep(1); + isp116x->board->reset(hcd->self.controller, 0); + } else + ret = isp116x_sw_reset(isp116x); + + if (ret) + return ret; + + t = jiffies + msecs_to_jiffies(timeout); + while (time_before_eq(jiffies, t)) { + msleep(4); + spin_lock_irq(&isp116x->lock); + clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY; + spin_unlock_irq(&isp116x->lock); + if (clkrdy) + break; + } + if (!clkrdy) { + ERR("Clock not ready after 20ms\n"); + ret = -ENODEV; + } + return ret; +} + +static void isp116x_stop(struct usb_hcd *hcd) +{ + struct isp116x *isp116x = hcd_to_isp116x(hcd); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&isp116x->lock, flags); + isp116x_write_reg16(isp116x, HCuPINTENB, 0); + + /* Switch off ports' power, some devices don't come up + after next 'insmod' without this */ + val = isp116x_read_reg32(isp116x, HCRHDESCA); + val &= ~(RH_A_NPS | RH_A_PSM); + isp116x_write_reg32(isp116x, HCRHDESCA, val); + isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS); + spin_unlock_irqrestore(&isp116x->lock, flags); + + /* Put the chip into reset state */ + if (isp116x->board && isp116x->board->reset) + isp116x->board->reset(hcd->self.controller, 0); + else + isp116x_sw_reset(isp116x); + + /* Stop the clock */ + if (isp116x->board && isp116x->board->clock) + isp116x->board->clock(hcd->self.controller, 0); +} + +/* + Configure the chip. The chip must be successfully reset by now. +*/ +static int isp116x_start(struct usb_hcd *hcd) +{ + struct isp116x *isp116x = hcd_to_isp116x(hcd); + struct isp116x_platform_data *board = isp116x->board; + struct usb_device *udev; + u32 val; + unsigned long flags; + + spin_lock_irqsave(&isp116x->lock, flags); + + /* clear interrupt status and disable all interrupt sources */ + isp116x_write_reg16(isp116x, HCuPINT, 0xff); + isp116x_write_reg16(isp116x, HCuPINTENB, 0); + + val = isp116x_read_reg16(isp116x, HCCHIPID); + if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) { + ERR("Invalid chip ID %04x\n", val); + spin_unlock_irqrestore(&isp116x->lock, flags); + return -ENODEV; + } + + isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE); + isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE); + + /* ----- HW conf */ + val = HCHWCFG_INT_ENABLE | HCHWCFG_DBWIDTH(1); + if (board->sel15Kres) + val |= HCHWCFG_15KRSEL; + /* Remote wakeup won't work without working clock */ + if (board->clknotstop || board->remote_wakeup_enable) + val |= HCHWCFG_CLKNOTSTOP; + if (board->oc_enable) + val |= HCHWCFG_ANALOG_OC; + if (board->int_act_high) + val |= HCHWCFG_INT_POL; + if (board->int_edge_triggered) + val |= HCHWCFG_INT_TRIGGER; + isp116x_write_reg16(isp116x, HCHWCFG, val); + + /* ----- Root hub conf */ + val = 0; + /* AN10003_1.pdf recommends NPS to be always 1 */ + if (board->no_power_switching) + val |= RH_A_NPS; + if (board->power_switching_mode) + val |= RH_A_PSM; + if (board->potpg) + val |= (board->potpg << 24) & RH_A_POTPGT; + else + val |= (25 << 24) & RH_A_POTPGT; + isp116x_write_reg32(isp116x, HCRHDESCA, val); + isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA); + + val = RH_B_PPCM; + isp116x_write_reg32(isp116x, HCRHDESCB, val); + isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB); + + val = 0; + if (board->remote_wakeup_enable) { + hcd->can_wakeup = 1; + val |= RH_HS_DRWE; + } + isp116x_write_reg32(isp116x, HCRHSTATUS, val); + isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS); + + isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf); + spin_unlock_irqrestore(&isp116x->lock, flags); + + udev = usb_alloc_dev(NULL, &hcd->self, 0); + if (!udev) { + isp116x_stop(hcd); + return -ENOMEM; + } + + udev->speed = USB_SPEED_FULL; + hcd->state = HC_STATE_RUNNING; + + if (usb_hcd_register_root_hub(udev, hcd) != 0) { + isp116x_stop(hcd); + usb_put_dev(udev); + return -ENODEV; + } + + spin_lock_irqsave(&isp116x->lock, flags); + /* Set up interrupts */ + isp116x->intenb = HCINT_MIE | HCINT_RHSC | HCINT_UE; + if (board->remote_wakeup_enable) + isp116x->intenb |= HCINT_RD; + isp116x->irqenb = HCuPINT_ATL | HCuPINT_OPR; /* | HCuPINT_SUSP; */ + isp116x_write_reg32(isp116x, HCINTENB, isp116x->intenb); + isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb); + + /* Go operational */ + val = HCCONTROL_USB_OPER; + /* Remote wakeup connected - NOT SUPPORTED */ + /* if (board->remote_wakeup_connected) + val |= HCCONTROL_RWC; */ + if (board->remote_wakeup_enable) + val |= HCCONTROL_RWE; + isp116x_write_reg32(isp116x, HCCONTROL, val); + + /* Disable ports to avoid race in device enumeration */ + isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS); + isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS); + + isp116x_show_regs(isp116x); + spin_unlock_irqrestore(&isp116x->lock, flags); + return 0; +} + +/*-----------------------------------------------------------------*/ + +static struct hc_driver isp116x_hc_driver = { + .description = hcd_name, + .product_desc = "ISP116x Host Controller", + .hcd_priv_size = sizeof(struct isp116x), + + .irq = isp116x_irq, + .flags = HCD_USB11, + + .reset = isp116x_reset, + .start = isp116x_start, + .stop = isp116x_stop, + + .urb_enqueue = isp116x_urb_enqueue, + .urb_dequeue = isp116x_urb_dequeue, + .endpoint_disable = isp116x_endpoint_disable, + + .get_frame_number = isp116x_get_frame, + + .hub_status_data = isp116x_hub_status_data, + .hub_control = isp116x_hub_control, + .hub_suspend = isp116x_hub_suspend, + .hub_resume = isp116x_hub_resume, +}; + +/*----------------------------------------------------------------*/ + +static int __init_or_module isp116x_remove(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct isp116x *isp116x = hcd_to_isp116x(hcd); + struct platform_device *pdev; + struct resource *res; + + pdev = container_of(dev, struct platform_device, dev); + remove_debug_file(isp116x); + usb_remove_hcd(hcd); + + iounmap(isp116x->data_reg); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + release_mem_region(res->start, 2); + iounmap(isp116x->addr_reg); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, 2); + + usb_put_hcd(hcd); + return 0; +} + +#define resource_len(r) (((r)->end - (r)->start) + 1) + +static int __init isp116x_probe(struct device *dev) +{ + struct usb_hcd *hcd; + struct isp116x *isp116x; + struct platform_device *pdev; + struct resource *addr, *data; + void __iomem *addr_reg; + void __iomem *data_reg; + int irq; + int ret = 0; + + pdev = container_of(dev, struct platform_device, dev); + if (pdev->num_resources < 3) { + ret = -ENODEV; + goto err1; + } + + data = platform_get_resource(pdev, IORESOURCE_MEM, 0); + addr = platform_get_resource(pdev, IORESOURCE_MEM, 1); + irq = platform_get_irq(pdev, 0); + if (!addr || !data || irq < 0) { + ret = -ENODEV; + goto err1; + } + + if (dev->dma_mask) { + DBG("DMA not supported\n"); + ret = -EINVAL; + goto err1; + } + + if (!request_mem_region(addr->start, 2, hcd_name)) { + ret = -EBUSY; + goto err1; + } + addr_reg = ioremap(addr->start, resource_len(addr)); + if (addr_reg == NULL) { + ret = -ENOMEM; + goto err2; + } + if (!request_mem_region(data->start, 2, hcd_name)) { + ret = -EBUSY; + goto err3; + } + data_reg = ioremap(data->start, resource_len(data)); + if (data_reg == NULL) { + ret = -ENOMEM; + goto err4; + } + + /* allocate and initialize hcd */ + hcd = usb_create_hcd(&isp116x_hc_driver, dev, dev->bus_id); + if (!hcd) { + ret = -ENOMEM; + goto err5; + } + /* this rsrc_start is bogus */ + hcd->rsrc_start = addr->start; + isp116x = hcd_to_isp116x(hcd); + isp116x->data_reg = data_reg; + isp116x->addr_reg = addr_reg; + spin_lock_init(&isp116x->lock); + INIT_LIST_HEAD(&isp116x->async); + INIT_WORK(&isp116x->rh_resume, isp116x_rh_resume, hcd); + isp116x->board = dev->platform_data; + + if (!isp116x->board) { + ERR("Platform data structure not initialized\n"); + ret = -ENODEV; + goto err6; + } + if (isp116x_check_platform_delay(isp116x)) { + ERR("USE_PLATFORM_DELAY defined, but delay function not " + "implemented.\n"); + ERR("See comments in drivers/usb/host/isp116x-hcd.c\n"); + ret = -ENODEV; + goto err6; + } + + ret = usb_add_hcd(hcd, irq, SA_INTERRUPT); + if (ret != 0) + goto err6; + + create_debug_file(isp116x); + return 0; + + err6: + usb_put_hcd(hcd); + err5: + iounmap(data_reg); + err4: + release_mem_region(data->start, 2); + err3: + iounmap(addr_reg); + err2: + release_mem_region(addr->start, 2); + err1: + ERR("init error, %d\n", ret); + return ret; +} + +#ifdef CONFIG_PM +/* + Suspend of platform device +*/ +static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase) +{ + int ret = 0; + struct usb_hcd *hcd = dev_get_drvdata(dev); + + VDBG("%s: state %x, phase %x\n", __func__, state, phase); + + if (phase != SUSPEND_DISABLE && phase != SUSPEND_POWER_DOWN) + return 0; + + ret = usb_suspend_device(hcd->self.root_hub, state); + if (!ret) { + dev->power.power_state = state; + INFO("%s suspended\n", (char *)hcd_name); + } else + ERR("%s suspend failed\n", (char *)hcd_name); + + return ret; +} + +/* + Resume platform device +*/ +static int isp116x_resume(struct device *dev, u32 phase) +{ + int ret = 0; + struct usb_hcd *hcd = dev_get_drvdata(dev); + + VDBG("%s: state %x, phase %x\n", __func__, dev->power.power_state, + phase); + if (phase != RESUME_POWER_ON) + return 0; + + ret = usb_resume_device(hcd->self.root_hub); + if (!ret) { + dev->power.power_state = PMSG_ON; + VDBG("%s resumed\n", (char *)hcd_name); + } + return ret; +} + +#else + +#define isp116x_suspend NULL +#define isp116x_resume NULL + +#endif + +static struct device_driver isp116x_driver = { + .name = (char *)hcd_name, + .bus = &platform_bus_type, + .probe = isp116x_probe, + .remove = isp116x_remove, + .suspend = isp116x_suspend, + .resume = isp116x_resume, +}; + +/*-----------------------------------------------------------------*/ + +static int __init isp116x_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION); + return driver_register(&isp116x_driver); +} + +module_init(isp116x_init); + +static void __exit isp116x_cleanup(void) +{ + driver_unregister(&isp116x_driver); +} + +module_exit(isp116x_cleanup); diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h new file mode 100644 index 000000000000..58873470dcf5 --- /dev/null +++ b/drivers/usb/host/isp116x.h @@ -0,0 +1,583 @@ +/* + * ISP116x register declarations and HCD data structures + * + * Copyright (C) 2005 Olav Kongas + * Portions: + * Copyright (C) 2004 Lothar Wassmann + * Copyright (C) 2004 Psion Teklogix + * Copyright (C) 2004 David Brownell + */ + +/* us of 1ms frame */ +#define MAX_LOAD_LIMIT 850 + +/* Full speed: max # of bytes to transfer for a single urb + at a time must be < 1024 && must be multiple of 64. + 832 allows transfering 4kiB within 5 frames. */ +#define MAX_TRANSFER_SIZE_FULLSPEED 832 + +/* Low speed: there is no reason to schedule in very big + chunks; often the requested long transfers are for + string descriptors containing short strings. */ +#define MAX_TRANSFER_SIZE_LOWSPEED 64 + +/* Bytetime (us), a rough indication of how much time it + would take to transfer a byte of useful data over USB */ +#define BYTE_TIME_FULLSPEED 1 +#define BYTE_TIME_LOWSPEED 20 + +/* Buffer sizes */ +#define ISP116x_BUF_SIZE 4096 +#define ISP116x_ITL_BUFSIZE 0 +#define ISP116x_ATL_BUFSIZE ((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE)) + +#define ISP116x_WRITE_OFFSET 0x80 + +/*------------ ISP116x registers/bits ------------*/ +#define HCREVISION 0x00 +#define HCCONTROL 0x01 +#define HCCONTROL_HCFS (3 << 6) /* host controller + functional state */ +#define HCCONTROL_USB_RESET (0 << 6) +#define HCCONTROL_USB_RESUME (1 << 6) +#define HCCONTROL_USB_OPER (2 << 6) +#define HCCONTROL_USB_SUSPEND (3 << 6) +#define HCCONTROL_RWC (1 << 9) /* remote wakeup connected */ +#define HCCONTROL_RWE (1 << 10) /* remote wakeup enable */ +#define HCCMDSTAT 0x02 +#define HCCMDSTAT_HCR (1 << 0) /* host controller reset */ +#define HCCMDSTAT_SOC (3 << 16) /* scheduling overrun count */ +#define HCINTSTAT 0x03 +#define HCINT_SO (1 << 0) /* scheduling overrun */ +#define HCINT_WDH (1 << 1) /* writeback of done_head */ +#define HCINT_SF (1 << 2) /* start frame */ +#define HCINT_RD (1 << 3) /* resume detect */ +#define HCINT_UE (1 << 4) /* unrecoverable error */ +#define HCINT_FNO (1 << 5) /* frame number overflow */ +#define HCINT_RHSC (1 << 6) /* root hub status change */ +#define HCINT_OC (1 << 30) /* ownership change */ +#define HCINT_MIE (1 << 31) /* master interrupt enable */ +#define HCINTENB 0x04 +#define HCINTDIS 0x05 +#define HCFMINTVL 0x0d +#define HCFMREM 0x0e +#define HCFMNUM 0x0f +#define HCLSTHRESH 0x11 +#define HCRHDESCA 0x12 +#define RH_A_NDP (0x3 << 0) /* # downstream ports */ +#define RH_A_PSM (1 << 8) /* power switching mode */ +#define RH_A_NPS (1 << 9) /* no power switching */ +#define RH_A_DT (1 << 10) /* device type (mbz) */ +#define RH_A_OCPM (1 << 11) /* overcurrent protection + mode */ +#define RH_A_NOCP (1 << 12) /* no overcurrent protection */ +#define RH_A_POTPGT (0xff << 24) /* power on -> power good + time */ +#define HCRHDESCB 0x13 +#define RH_B_DR (0xffff << 0) /* device removable flags */ +#define RH_B_PPCM (0xffff << 16) /* port power control mask */ +#define HCRHSTATUS 0x14 +#define RH_HS_LPS (1 << 0) /* local power status */ +#define RH_HS_OCI (1 << 1) /* over current indicator */ +#define RH_HS_DRWE (1 << 15) /* device remote wakeup + enable */ +#define RH_HS_LPSC (1 << 16) /* local power status change */ +#define RH_HS_OCIC (1 << 17) /* over current indicator + change */ +#define RH_HS_CRWE (1 << 31) /* clear remote wakeup + enable */ +#define HCRHPORT1 0x15 +#define RH_PS_CCS (1 << 0) /* current connect status */ +#define RH_PS_PES (1 << 1) /* port enable status */ +#define RH_PS_PSS (1 << 2) /* port suspend status */ +#define RH_PS_POCI (1 << 3) /* port over current + indicator */ +#define RH_PS_PRS (1 << 4) /* port reset status */ +#define RH_PS_PPS (1 << 8) /* port power status */ +#define RH_PS_LSDA (1 << 9) /* low speed device attached */ +#define RH_PS_CSC (1 << 16) /* connect status change */ +#define RH_PS_PESC (1 << 17) /* port enable status change */ +#define RH_PS_PSSC (1 << 18) /* port suspend status + change */ +#define RH_PS_OCIC (1 << 19) /* over current indicator + change */ +#define RH_PS_PRSC (1 << 20) /* port reset status change */ +#define HCRHPORT_CLRMASK (0x1f << 16) +#define HCRHPORT2 0x16 +#define HCHWCFG 0x20 +#define HCHWCFG_15KRSEL (1 << 12) +#define HCHWCFG_CLKNOTSTOP (1 << 11) +#define HCHWCFG_ANALOG_OC (1 << 10) +#define HCHWCFG_DACK_MODE (1 << 8) +#define HCHWCFG_EOT_POL (1 << 7) +#define HCHWCFG_DACK_POL (1 << 6) +#define HCHWCFG_DREQ_POL (1 << 5) +#define HCHWCFG_DBWIDTH_MASK (0x03 << 3) +#define HCHWCFG_DBWIDTH(n) (((n) << 3) & HCHWCFG_DBWIDTH_MASK) +#define HCHWCFG_INT_POL (1 << 2) +#define HCHWCFG_INT_TRIGGER (1 << 1) +#define HCHWCFG_INT_ENABLE (1 << 0) +#define HCDMACFG 0x21 +#define HCDMACFG_BURST_LEN_MASK (0x03 << 5) +#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN_MASK) +#define HCDMACFG_BURST_LEN_1 HCDMACFG_BURST_LEN(0) +#define HCDMACFG_BURST_LEN_4 HCDMACFG_BURST_LEN(1) +#define HCDMACFG_BURST_LEN_8 HCDMACFG_BURST_LEN(2) +#define HCDMACFG_DMA_ENABLE (1 << 4) +#define HCDMACFG_BUF_TYPE_MASK (0x07 << 1) +#define HCDMACFG_CTR_SEL (1 << 2) +#define HCDMACFG_ITLATL_SEL (1 << 1) +#define HCDMACFG_DMA_RW_SELECT (1 << 0) +#define HCXFERCTR 0x22 +#define HCuPINT 0x24 +#define HCuPINT_SOF (1 << 0) +#define HCuPINT_ATL (1 << 1) +#define HCuPINT_AIIEOT (1 << 2) +#define HCuPINT_OPR (1 << 4) +#define HCuPINT_SUSP (1 << 5) +#define HCuPINT_CLKRDY (1 << 6) +#define HCuPINTENB 0x25 +#define HCCHIPID 0x27 +#define HCCHIPID_MASK 0xff00 +#define HCCHIPID_MAGIC 0x6100 +#define HCSCRATCH 0x28 +#define HCSWRES 0x29 +#define HCSWRES_MAGIC 0x00f6 +#define HCITLBUFLEN 0x2a +#define HCATLBUFLEN 0x2b +#define HCBUFSTAT 0x2c +#define HCBUFSTAT_ITL0_FULL (1 << 0) +#define HCBUFSTAT_ITL1_FULL (1 << 1) +#define HCBUFSTAT_ATL_FULL (1 << 2) +#define HCBUFSTAT_ITL0_DONE (1 << 3) +#define HCBUFSTAT_ITL1_DONE (1 << 4) +#define HCBUFSTAT_ATL_DONE (1 << 5) +#define HCRDITL0LEN 0x2d +#define HCRDITL1LEN 0x2e +#define HCITLPORT 0x40 +#define HCATLPORT 0x41 + +/* Philips transfer descriptor */ +struct ptd { + u16 count; +#define PTD_COUNT_MSK (0x3ff << 0) +#define PTD_TOGGLE_MSK (1 << 10) +#define PTD_ACTIVE_MSK (1 << 11) +#define PTD_CC_MSK (0xf << 12) + u16 mps; +#define PTD_MPS_MSK (0x3ff << 0) +#define PTD_SPD_MSK (1 << 10) +#define PTD_LAST_MSK (1 << 11) +#define PTD_EP_MSK (0xf << 12) + u16 len; +#define PTD_LEN_MSK (0x3ff << 0) +#define PTD_DIR_MSK (3 << 10) +#define PTD_DIR_SETUP (0) +#define PTD_DIR_OUT (1) +#define PTD_DIR_IN (2) +#define PTD_B5_5_MSK (1 << 13) + u16 faddr; +#define PTD_FA_MSK (0x7f << 0) +#define PTD_FMT_MSK (1 << 7) +} __attribute__ ((packed, aligned(2))); + +/* PTD accessor macros. */ +#define PTD_GET_COUNT(p) (((p)->count & PTD_COUNT_MSK) >> 0) +#define PTD_COUNT(v) (((v) << 0) & PTD_COUNT_MSK) +#define PTD_GET_TOGGLE(p) (((p)->count & PTD_TOGGLE_MSK) >> 10) +#define PTD_TOGGLE(v) (((v) << 10) & PTD_TOGGLE_MSK) +#define PTD_GET_ACTIVE(p) (((p)->count & PTD_ACTIVE_MSK) >> 11) +#define PTD_ACTIVE(v) (((v) << 11) & PTD_ACTIVE_MSK) +#define PTD_GET_CC(p) (((p)->count & PTD_CC_MSK) >> 12) +#define PTD_CC(v) (((v) << 12) & PTD_CC_MSK) +#define PTD_GET_MPS(p) (((p)->mps & PTD_MPS_MSK) >> 0) +#define PTD_MPS(v) (((v) << 0) & PTD_MPS_MSK) +#define PTD_GET_SPD(p) (((p)->mps & PTD_SPD_MSK) >> 10) +#define PTD_SPD(v) (((v) << 10) & PTD_SPD_MSK) +#define PTD_GET_LAST(p) (((p)->mps & PTD_LAST_MSK) >> 11) +#define PTD_LAST(v) (((v) << 11) & PTD_LAST_MSK) +#define PTD_GET_EP(p) (((p)->mps & PTD_EP_MSK) >> 12) +#define PTD_EP(v) (((v) << 12) & PTD_EP_MSK) +#define PTD_GET_LEN(p) (((p)->len & PTD_LEN_MSK) >> 0) +#define PTD_LEN(v) (((v) << 0) & PTD_LEN_MSK) +#define PTD_GET_DIR(p) (((p)->len & PTD_DIR_MSK) >> 10) +#define PTD_DIR(v) (((v) << 10) & PTD_DIR_MSK) +#define PTD_GET_B5_5(p) (((p)->len & PTD_B5_5_MSK) >> 13) +#define PTD_B5_5(v) (((v) << 13) & PTD_B5_5_MSK) +#define PTD_GET_FA(p) (((p)->faddr & PTD_FA_MSK) >> 0) +#define PTD_FA(v) (((v) << 0) & PTD_FA_MSK) +#define PTD_GET_FMT(p) (((p)->faddr & PTD_FMT_MSK) >> 7) +#define PTD_FMT(v) (((v) << 7) & PTD_FMT_MSK) + +/* Hardware transfer status codes -- CC from ptd->count */ +#define TD_CC_NOERROR 0x00 +#define TD_CC_CRC 0x01 +#define TD_CC_BITSTUFFING 0x02 +#define TD_CC_DATATOGGLEM 0x03 +#define TD_CC_STALL 0x04 +#define TD_DEVNOTRESP 0x05 +#define TD_PIDCHECKFAIL 0x06 +#define TD_UNEXPECTEDPID 0x07 +#define TD_DATAOVERRUN 0x08 +#define TD_DATAUNDERRUN 0x09 + /* 0x0A, 0x0B reserved for hardware */ +#define TD_BUFFEROVERRUN 0x0C +#define TD_BUFFERUNDERRUN 0x0D + /* 0x0E, 0x0F reserved for HCD */ +#define TD_NOTACCESSED 0x0F + +/* map PTD status codes (CC) to errno values */ +static const int cc_to_error[16] = { + /* No Error */ 0, + /* CRC Error */ -EILSEQ, + /* Bit Stuff */ -EPROTO, + /* Data Togg */ -EILSEQ, + /* Stall */ -EPIPE, + /* DevNotResp */ -ETIMEDOUT, + /* PIDCheck */ -EPROTO, + /* UnExpPID */ -EPROTO, + /* DataOver */ -EOVERFLOW, + /* DataUnder */ -EREMOTEIO, + /* (for hw) */ -EIO, + /* (for hw) */ -EIO, + /* BufferOver */ -ECOMM, + /* BuffUnder */ -ENOSR, + /* (for HCD) */ -EALREADY, + /* (for HCD) */ -EALREADY +}; + +/*--------------------------------------------------------------*/ + +#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */ +#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE) + +struct isp116x { + spinlock_t lock; + struct work_struct rh_resume; + + void __iomem *addr_reg; + void __iomem *data_reg; + + struct isp116x_platform_data *board; + + struct proc_dir_entry *pde; + unsigned long stat1, stat2, stat4, stat8, stat16; + + /* HC registers */ + u32 intenb; /* "OHCI" interrupts */ + u16 irqenb; /* uP interrupts */ + + /* Root hub registers */ + u32 rhdesca; + u32 rhdescb; + u32 rhstatus; + u32 rhport[2]; + + /* async schedule: control, bulk */ + struct list_head async; + + /* periodic schedule: int */ + u16 load[PERIODIC_SIZE]; + struct isp116x_ep *periodic[PERIODIC_SIZE]; + unsigned periodic_count; + u16 fmindex; + + /* Schedule for the current frame */ + struct isp116x_ep *atl_active; + int atl_buflen; + int atl_bufshrt; + int atl_last_dir; + atomic_t atl_finishing; +}; + +static inline struct isp116x *hcd_to_isp116x(struct usb_hcd *hcd) +{ + return (struct isp116x *)(hcd->hcd_priv); +} + +static inline struct usb_hcd *isp116x_to_hcd(struct isp116x *isp116x) +{ + return container_of((void *)isp116x, struct usb_hcd, hcd_priv); +} + +struct isp116x_ep { + struct usb_host_endpoint *hep; + struct usb_device *udev; + struct ptd ptd; + + u8 maxpacket; + u8 epnum; + u8 nextpid; + u16 error_count; + u16 length; /* of current packet */ + unsigned char *data; /* to databuf */ + /* queue of active EP's (the ones scheduled for the + current frame) */ + struct isp116x_ep *active; + + /* periodic schedule */ + u16 period; + u16 branch; + u16 load; + struct isp116x_ep *next; + + /* async schedule */ + struct list_head schedule; +}; + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG +#define DBG(stuff...) printk(KERN_DEBUG "116x: " stuff) +#else +#define DBG(stuff...) do{}while(0) +#endif + +#ifdef VERBOSE +# define VDBG DBG +#else +# define VDBG(stuff...) do{}while(0) +#endif + +#define ERR(stuff...) printk(KERN_ERR "116x: " stuff) +#define WARN(stuff...) printk(KERN_WARNING "116x: " stuff) +#define INFO(stuff...) printk(KERN_INFO "116x: " stuff) + +/* ------------------------------------------------- */ + +#if defined(USE_PLATFORM_DELAY) +#if defined(USE_NDELAY) +#error USE_PLATFORM_DELAY and USE_NDELAY simultaneously defined. +#endif +#define isp116x_delay(h,d) (h)->board->delay( \ + isp116x_to_hcd(h)->self.controller,d) +#define isp116x_check_platform_delay(h) ((h)->board->delay == NULL) +#elif defined(USE_NDELAY) +#define isp116x_delay(h,d) ndelay(d) +#define isp116x_check_platform_delay(h) 0 +#else +#define isp116x_delay(h,d) do{}while(0) +#define isp116x_check_platform_delay(h) 0 +#endif + +#if defined(DEBUG) +#define IRQ_TEST() BUG_ON(!irqs_disabled()) +#else +#define IRQ_TEST() do{}while(0) +#endif + +static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg) +{ + IRQ_TEST(); + writew(reg & 0xff, isp116x->addr_reg); + isp116x_delay(isp116x, 300); +} + +static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val) +{ + writew(val, isp116x->data_reg); + isp116x_delay(isp116x, 150); +} + +static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val) +{ + __raw_writew(val, isp116x->data_reg); + isp116x_delay(isp116x, 150); +} + +static inline u16 isp116x_read_data16(struct isp116x *isp116x) +{ + u16 val; + + val = readw(isp116x->data_reg); + isp116x_delay(isp116x, 150); + return val; +} + +static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x) +{ + u16 val; + + val = __raw_readw(isp116x->data_reg); + isp116x_delay(isp116x, 150); + return val; +} + +static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val) +{ + writew(val & 0xffff, isp116x->data_reg); + isp116x_delay(isp116x, 150); + writew(val >> 16, isp116x->data_reg); + isp116x_delay(isp116x, 150); +} + +static inline u32 isp116x_read_data32(struct isp116x *isp116x) +{ + u32 val; + + val = (u32) readw(isp116x->data_reg); + isp116x_delay(isp116x, 150); + val |= ((u32) readw(isp116x->data_reg)) << 16; + isp116x_delay(isp116x, 150); + return val; +} + +/* Let's keep register access functions out of line. Hint: + we wait at least 150 ns at every access. +*/ +static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg) +{ + isp116x_write_addr(isp116x, reg); + return isp116x_read_data16(isp116x); +} + +static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg) +{ + isp116x_write_addr(isp116x, reg); + return isp116x_read_data32(isp116x); +} + +static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg, + unsigned val) +{ + isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET); + isp116x_write_data16(isp116x, (u16) (val & 0xffff)); +} + +static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg, + unsigned val) +{ + isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET); + isp116x_write_data32(isp116x, (u32) val); +} + +#define isp116x_show_reg(d,r) { \ + if ((r) < 0x20) { \ + DBG("%-12s[%02x]: %08x\n", #r, \ + r, isp116x_read_reg32(d, r)); \ + } else { \ + DBG("%-12s[%02x]: %04x\n", #r, \ + r, isp116x_read_reg16(d, r)); \ + } \ +} + +static inline void isp116x_show_regs(struct isp116x *isp116x) +{ + isp116x_show_reg(isp116x, HCREVISION); + isp116x_show_reg(isp116x, HCCONTROL); + isp116x_show_reg(isp116x, HCCMDSTAT); + isp116x_show_reg(isp116x, HCINTSTAT); + isp116x_show_reg(isp116x, HCINTENB); + isp116x_show_reg(isp116x, HCFMINTVL); + isp116x_show_reg(isp116x, HCFMREM); + isp116x_show_reg(isp116x, HCFMNUM); + isp116x_show_reg(isp116x, HCLSTHRESH); + isp116x_show_reg(isp116x, HCRHDESCA); + isp116x_show_reg(isp116x, HCRHDESCB); + isp116x_show_reg(isp116x, HCRHSTATUS); + isp116x_show_reg(isp116x, HCRHPORT1); + isp116x_show_reg(isp116x, HCRHPORT2); + isp116x_show_reg(isp116x, HCHWCFG); + isp116x_show_reg(isp116x, HCDMACFG); + isp116x_show_reg(isp116x, HCXFERCTR); + isp116x_show_reg(isp116x, HCuPINT); + isp116x_show_reg(isp116x, HCuPINTENB); + isp116x_show_reg(isp116x, HCCHIPID); + isp116x_show_reg(isp116x, HCSCRATCH); + isp116x_show_reg(isp116x, HCITLBUFLEN); + isp116x_show_reg(isp116x, HCATLBUFLEN); + isp116x_show_reg(isp116x, HCBUFSTAT); + isp116x_show_reg(isp116x, HCRDITL0LEN); + isp116x_show_reg(isp116x, HCRDITL1LEN); +} + +#if defined(URB_TRACE) + +#define PIPETYPE(pipe) ({ char *__s; \ + if (usb_pipecontrol(pipe)) __s = "ctrl"; \ + else if (usb_pipeint(pipe)) __s = "int"; \ + else if (usb_pipebulk(pipe)) __s = "bulk"; \ + else __s = "iso"; \ + __s;}) +#define PIPEDIR(pipe) ({ usb_pipein(pipe) ? "in" : "out"; }) +#define URB_NOTSHORT(urb) ({ (urb)->transfer_flags & URB_SHORT_NOT_OK ? \ + "short_not_ok" : ""; }) + +/* print debug info about the URB */ +static void urb_dbg(struct urb *urb, char *msg) +{ + unsigned int pipe; + + if (!urb) { + DBG("%s: zero urb\n", msg); + return; + } + pipe = urb->pipe; + DBG("%s: FA %d ep%d%s %s: len %d/%d %s\n", msg, + usb_pipedevice(pipe), usb_pipeendpoint(pipe), + PIPEDIR(pipe), PIPETYPE(pipe), + urb->transfer_buffer_length, urb->actual_length, URB_NOTSHORT(urb)); +} + +#else + +#define urb_dbg(urb,msg) do{}while(0) + +#endif /* ! defined(URB_TRACE) */ + +#if defined(PTD_TRACE) + +#define PTD_DIR_STR(ptd) ({char __c; \ + switch(PTD_GET_DIR(ptd)){ \ + case 0: __c = 's'; break; \ + case 1: __c = 'o'; break; \ + default: __c = 'i'; break; \ + }; __c;}) + +/* + Dump PTD info. The code documents the format + perfectly, right :) +*/ +static inline void dump_ptd(struct ptd *ptd) +{ + printk("td: %x %d%c%d %d,%d,%d %x %x%x%x\n", + PTD_GET_CC(ptd), PTD_GET_FA(ptd), + PTD_DIR_STR(ptd), PTD_GET_EP(ptd), + PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd), + PTD_GET_TOGGLE(ptd), PTD_GET_ACTIVE(ptd), + PTD_GET_SPD(ptd), PTD_GET_LAST(ptd)); +} + +static inline void dump_ptd_out_data(struct ptd *ptd, u8 * buf) +{ + int k; + + if (PTD_GET_DIR(ptd) != PTD_DIR_IN && PTD_GET_LEN(ptd)) { + printk("-> "); + for (k = 0; k < PTD_GET_LEN(ptd); ++k) + printk("%02x ", ((u8 *) buf)[k]); + printk("\n"); + } +} + +static inline void dump_ptd_in_data(struct ptd *ptd, u8 * buf) +{ + int k; + + if (PTD_GET_DIR(ptd) == PTD_DIR_IN && PTD_GET_COUNT(ptd)) { + printk("<- "); + for (k = 0; k < PTD_GET_COUNT(ptd); ++k) + printk("%02x ", ((u8 *) buf)[k]); + printk("\n"); + } + if (PTD_GET_LAST(ptd)) + printk("-\n"); +} + +#else + +#define dump_ptd(ptd) do{}while(0) +#define dump_ptd_in_data(ptd,buf) do{}while(0) +#define dump_ptd_out_data(ptd,buf) do{}while(0) + +#endif /* ! defined(PTD_TRACE) */ diff --git a/include/linux/usb_isp116x.h b/include/linux/usb_isp116x.h new file mode 100644 index 000000000000..5f5a9d9bd6c2 --- /dev/null +++ b/include/linux/usb_isp116x.h @@ -0,0 +1,47 @@ + +/* + * Board initialization code should put one of these into dev->platform_data + * and place the isp116x onto platform_bus. + */ + +struct isp116x_platform_data { + /* Enable internal resistors on downstream ports */ + unsigned sel15Kres:1; + /* Chip's internal clock won't be stopped in suspended state. + Setting/unsetting this bit takes effect only if + 'remote_wakeup_enable' below is not set. */ + unsigned clknotstop:1; + /* On-chip overcurrent protection */ + unsigned oc_enable:1; + /* INT output polarity */ + unsigned int_act_high:1; + /* INT edge or level triggered */ + unsigned int_edge_triggered:1; + /* WAKEUP pin connected - NOT SUPPORTED */ + /* unsigned remote_wakeup_connected:1; */ + /* Wakeup by devices on usb bus enabled */ + unsigned remote_wakeup_enable:1; + /* Switch or not to switch (keep always powered) */ + unsigned no_power_switching:1; + /* Ganged port power switching (0) or individual port + power switching (1) */ + unsigned power_switching_mode:1; + /* Given port_power, msec/2 after power on till power good */ + u8 potpg; + /* Hardware reset set/clear. If implemented, this function must: + if set == 0, deassert chip's HW reset pin + otherwise, assert chip's HW reset pin */ + void (*reset) (struct device * dev, int set); + /* Hardware clock start/stop. If implemented, this function must: + if start == 0, stop the external clock + otherwise, start the external clock + */ + void (*clock) (struct device * dev, int start); + /* Inter-io delay (ns). The chip is picky about access timings; it + expects at least: + 150ns delay between consecutive accesses to DATA_REG, + 300ns delay between access to ADDR_REG and DATA_REG + OE, WE MUST NOT be changed during these intervals + */ + void (*delay) (struct device * dev, int delay); +}; -- cgit v1.2.3 From 589a0083a3c9e9610e54984998a46c07a2584b55 Mon Sep 17 00:00:00 2001 From: Olav Kongas Date: Thu, 21 Apr 2005 17:12:59 +0300 Subject: [PATCH] USB: Fix oops at rmmod after failed probe in isp116x-hcd This patch fixes an oops triggered at rmmod of isp116x-hcd after the probe() has failed. Also, it extends the error message printed, if the driver cannot detect "Chip's Clock Ready" after a software reset. As Ian Campbell recently reported, this happens if the chip's H_WAKEUP pin is not pulled low during software reset. Several people have already had this issue, hence the update to the error message. Also, extend the error message about the failed clock detection after the software reset. Signed-off-by: Olav Kongas --- drivers/usb/host/isp116x-hcd.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 69e7433d9ce8..1183988fdf54 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1501,6 +1501,12 @@ static int isp116x_reset(struct usb_hcd *hcd) } if (!clkrdy) { ERR("Clock not ready after 20ms\n"); + /* After sw_reset the clock won't report to be ready, if + H_WAKEUP pin is high. */ + if (!isp116x->board || !isp116x->board->reset) + ERR("The driver does not support hardware wakeup.\n"); + ERR("Please make sure that the H_WAKEUP pin " + "is pulled low!\n"); ret = -ENODEV; } return ret; @@ -1678,10 +1684,13 @@ static struct hc_driver isp116x_hc_driver = { static int __init_or_module isp116x_remove(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct isp116x *isp116x = hcd_to_isp116x(hcd); + struct isp116x *isp116x; struct platform_device *pdev; struct resource *res; + if(!hcd) + return 0; + isp116x = hcd_to_isp116x(hcd); pdev = container_of(dev, struct platform_device, dev); remove_debug_file(isp116x); usb_remove_hcd(hcd); -- cgit v1.2.3 From 72ebddb59a644732ff0240cdf5d216952a2b0c6b Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 11 Apr 2005 18:34:17 -0700 Subject: [PATCH] USB: turn a user mode driver error into a hard error This patch turns a user mode driver error into a hard error, and updates the relevant diagnostic slightly to help troubleshooting. gphoto was known to have this problem, hopefully it is now fixed (they have had plenty of warning...) This had been left as a soft error to give various user mode drivers a change to be properly fixed, with the statement that starting in about 2.6.10 it would be changed. It had been mostly safe as a soft error ... but that can not be guaranteed. Now that a year has passed, it's time to really insist that the user mode drivers finally fix their relevant bugs. Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 6bfab4bcaa9e..787c27a63c51 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -784,16 +784,16 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) { if (usb_interface_claimed(actconfig->interface[i])) { dev_warn (&ps->dev->dev, - "usbfs: interface %d claimed " + "usbfs: interface %d claimed by %s " "while '%s' sets config #%d\n", actconfig->interface[i] ->cur_altsetting ->desc.bInterfaceNumber, + actconfig->interface[i] + ->dev.driver->name, current->comm, u); -#if 0 /* FIXME: enable in 2.6.10 or so */ status = -EBUSY; break; -#endif } } } -- cgit v1.2.3 From 014e73c99aa408f3766afe8d11a1caa3a708b736 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 9 Apr 2005 17:24:42 -0400 Subject: [PATCH] USB UHCI: subroutine reordering This patch moves a few subroutines around in the uhci-hcd source file. Nothing else is changed. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 287 ++++++++++++++++++++++---------------------- 1 file changed, 143 insertions(+), 144 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 49bd83ee0c75..8b6c87ef486b 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -90,7 +90,6 @@ static char *errbuf; static kmem_cache_t *uhci_up_cachep; /* urb_priv */ static void uhci_get_current_frame_number(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) @@ -105,96 +104,43 @@ static void hc_state_transitions(struct uhci_hcd *uhci); #include "uhci-debug.c" #include "uhci-q.c" -static int init_stall_timer(struct usb_hcd *hcd); - -static void stall_callback(unsigned long ptr) -{ - struct usb_hcd *hcd = (struct usb_hcd *)ptr; - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - struct urb_priv *up; - unsigned long flags; - - spin_lock_irqsave(&uhci->lock, flags); - uhci_scan_schedule(uhci, NULL); - - list_for_each_entry(up, &uhci->urb_list, urb_list) { - struct urb *u = up->urb; - - spin_lock(&u->lock); - - /* Check if the FSBR timed out */ - if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) - uhci_fsbr_timeout(uhci, u); - - spin_unlock(&u->lock); - } - - /* Really disable FSBR */ - if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { - uhci->fsbrtimeout = 0; - uhci->skel_term_qh->link = UHCI_PTR_TERM; - } - - /* Poll for and perform state transitions */ - hc_state_transitions(uhci); - if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED)) - uhci_check_ports(uhci); - - init_stall_timer(hcd); - spin_unlock_irqrestore(&uhci->lock, flags); -} - -static int init_stall_timer(struct usb_hcd *hcd) +static int ports_active(struct uhci_hcd *uhci) { - struct uhci_hcd *uhci = hcd_to_uhci(hcd); + unsigned long io_addr = uhci->io_addr; + int connection = 0; + int i; - init_timer(&uhci->stall_timer); - uhci->stall_timer.function = stall_callback; - uhci->stall_timer.data = (unsigned long)hcd; - uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100); - add_timer(&uhci->stall_timer); + for (i = 0; i < uhci->rh_numports; i++) + connection |= (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_CCS); - return 0; + return connection; } -static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) +static int suspend_allowed(struct uhci_hcd *uhci) { - struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long io_addr = uhci->io_addr; - unsigned short status; + int i; - /* - * Read the interrupt status, and write it back to clear the - * interrupt cause. Contrary to the UHCI specification, the - * "HC Halted" status bit is persistent: it is RO, not R/WC. + if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL) + return 1; + + /* Some of Intel's USB controllers have a bug that causes false + * resume indications if any port has an over current condition. + * To prevent problems, we will not allow a global suspend if + * any ports are OC. + * + * Some motherboards using Intel's chipsets (but not using all + * the USB ports) appear to hardwire the over current inputs active + * to disable the USB ports. */ - status = inw(io_addr + USBSTS); - if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */ - return IRQ_NONE; - outw(status, io_addr + USBSTS); /* Clear it */ - if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { - if (status & USBSTS_HSE) - dev_err(uhci_dev(uhci), "host system error, " - "PCI problems?\n"); - if (status & USBSTS_HCPE) - dev_err(uhci_dev(uhci), "host controller process " - "error, something bad happened!\n"); - if ((status & USBSTS_HCH) && uhci->state > 0) { - dev_err(uhci_dev(uhci), "host controller halted, " - "very bad!\n"); - /* FIXME: Reset the controller, fix the offending TD */ - } + /* check for over current condition on any port */ + for (i = 0; i < uhci->rh_numports; i++) { + if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC) + return 0; } - if (status & USBSTS_RD) - uhci->resume_detect = 1; - - spin_lock(&uhci->lock); - uhci_scan_schedule(uhci, regs); - spin_unlock(&uhci->lock); - - return IRQ_HANDLED; + return 1; } static void reset_hc(struct uhci_hcd *uhci) @@ -276,43 +222,46 @@ static void wakeup_hc(struct uhci_hcd *uhci) } } -static int ports_active(struct uhci_hcd *uhci) +static int start_hc(struct uhci_hcd *uhci) { unsigned long io_addr = uhci->io_addr; - int connection = 0; - int i; - - for (i = 0; i < uhci->rh_numports; i++) - connection |= (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_CCS); + int timeout = 10; - return connection; -} + /* + * Reset the HC - this will force us to get a + * new notification of any already connected + * ports due to the virtual disconnect that it + * implies. + */ + outw(USBCMD_HCRESET, io_addr + USBCMD); + while (inw(io_addr + USBCMD) & USBCMD_HCRESET) { + if (--timeout < 0) { + dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n"); + return -ETIMEDOUT; + } + msleep(1); + } -static int suspend_allowed(struct uhci_hcd *uhci) -{ - unsigned long io_addr = uhci->io_addr; - int i; + /* Mark controller as running before we enable interrupts */ + uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; - if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL) - return 1; + /* Turn on PIRQ and all interrupts */ + pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, + USBLEGSUP_DEFAULT); + outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, + io_addr + USBINTR); - /* Some of Intel's USB controllers have a bug that causes false - * resume indications if any port has an over current condition. - * To prevent problems, we will not allow a global suspend if - * any ports are OC. - * - * Some motherboards using Intel's chipsets (but not using all - * the USB ports) appear to hardwire the over current inputs active - * to disable the USB ports. - */ + /* Start at frame 0 */ + outw(0, io_addr + USBFRNUM); + outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD); - /* check for over current condition on any port */ - for (i = 0; i < uhci->rh_numports; i++) { - if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC) - return 0; - } + /* Run and mark it configured with a 64-byte max packet */ + uhci->state = UHCI_RUNNING_GRACE; + uhci->state_end = jiffies + HZ; + outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); + uhci->is_stopped = 0; - return 1; + return 0; } static void hc_state_transitions(struct uhci_hcd *uhci) @@ -353,56 +302,106 @@ static void hc_state_transitions(struct uhci_hcd *uhci) } } -/* - * Store the current frame number in uhci->frame_number if the controller - * is runnning - */ -static void uhci_get_current_frame_number(struct uhci_hcd *uhci) +static int init_stall_timer(struct usb_hcd *hcd); + +static void stall_callback(unsigned long ptr) { - if (!uhci->is_stopped) - uhci->frame_number = inw(uhci->io_addr + USBFRNUM); + struct usb_hcd *hcd = (struct usb_hcd *)ptr; + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + struct urb_priv *up; + unsigned long flags; + + spin_lock_irqsave(&uhci->lock, flags); + uhci_scan_schedule(uhci, NULL); + + list_for_each_entry(up, &uhci->urb_list, urb_list) { + struct urb *u = up->urb; + + spin_lock(&u->lock); + + /* Check if the FSBR timed out */ + if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) + uhci_fsbr_timeout(uhci, u); + + spin_unlock(&u->lock); + } + + /* Really disable FSBR */ + if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { + uhci->fsbrtimeout = 0; + uhci->skel_term_qh->link = UHCI_PTR_TERM; + } + + /* Poll for and perform state transitions */ + hc_state_transitions(uhci); + if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED)) + uhci_check_ports(uhci); + + init_stall_timer(hcd); + spin_unlock_irqrestore(&uhci->lock, flags); } -static int start_hc(struct uhci_hcd *uhci) +static int init_stall_timer(struct usb_hcd *hcd) { + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + + init_timer(&uhci->stall_timer); + uhci->stall_timer.function = stall_callback; + uhci->stall_timer.data = (unsigned long)hcd; + uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100); + add_timer(&uhci->stall_timer); + + return 0; +} + +static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) +{ + struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long io_addr = uhci->io_addr; - int timeout = 10; + unsigned short status; /* - * Reset the HC - this will force us to get a - * new notification of any already connected - * ports due to the virtual disconnect that it - * implies. + * Read the interrupt status, and write it back to clear the + * interrupt cause. Contrary to the UHCI specification, the + * "HC Halted" status bit is persistent: it is RO, not R/WC. */ - outw(USBCMD_HCRESET, io_addr + USBCMD); - while (inw(io_addr + USBCMD) & USBCMD_HCRESET) { - if (--timeout < 0) { - dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n"); - return -ETIMEDOUT; + status = inw(io_addr + USBSTS); + if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */ + return IRQ_NONE; + outw(status, io_addr + USBSTS); /* Clear it */ + + if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { + if (status & USBSTS_HSE) + dev_err(uhci_dev(uhci), "host system error, " + "PCI problems?\n"); + if (status & USBSTS_HCPE) + dev_err(uhci_dev(uhci), "host controller process " + "error, something bad happened!\n"); + if ((status & USBSTS_HCH) && uhci->state > 0) { + dev_err(uhci_dev(uhci), "host controller halted, " + "very bad!\n"); + /* FIXME: Reset the controller, fix the offending TD */ } - msleep(1); } - /* Mark controller as running before we enable interrupts */ - uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; - - /* Turn on PIRQ and all interrupts */ - pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, - USBLEGSUP_DEFAULT); - outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, - io_addr + USBINTR); + if (status & USBSTS_RD) + uhci->resume_detect = 1; - /* Start at frame 0 */ - outw(0, io_addr + USBFRNUM); - outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD); + spin_lock(&uhci->lock); + uhci_scan_schedule(uhci, regs); + spin_unlock(&uhci->lock); - /* Run and mark it configured with a 64-byte max packet */ - uhci->state = UHCI_RUNNING_GRACE; - uhci->state_end = jiffies + HZ; - outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); - uhci->is_stopped = 0; + return IRQ_HANDLED; +} - return 0; +/* + * Store the current frame number in uhci->frame_number if the controller + * is runnning + */ +static void uhci_get_current_frame_number(struct uhci_hcd *uhci) +{ + if (!uhci->is_stopped) + uhci->frame_number = inw(uhci->io_addr + USBFRNUM); } /* -- cgit v1.2.3 From f5946f8220a866dcdb8edc6abe23c1443e252425 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 9 Apr 2005 17:26:00 -0400 Subject: [PATCH] USB UHCI: Minor improvements This patch makes a few small improvements in the UHCI driver. Some code is moved between different source files and a more useful pointer is passed to a callback routine. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 69 +++++++++++---------------------------------- drivers/usb/host/uhci-hub.c | 16 +++++++++++ drivers/usb/host/uhci-q.c | 23 +++++++++++++++ 3 files changed, 55 insertions(+), 53 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 8b6c87ef486b..c17bd7ebc021 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -100,22 +100,15 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci); /* to make sure it doesn't hog all of the bandwidth */ #define DEPTH_INTERVAL 5 +static inline void restart_timer(struct uhci_hcd *uhci) +{ + mod_timer(&uhci->stall_timer, jiffies + msecs_to_jiffies(100)); +} + #include "uhci-hub.c" #include "uhci-debug.c" #include "uhci-q.c" -static int ports_active(struct uhci_hcd *uhci) -{ - unsigned long io_addr = uhci->io_addr; - int connection = 0; - int i; - - for (i = 0; i < uhci->rh_numports; i++) - connection |= (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_CCS); - - return connection; -} - static int suspend_allowed(struct uhci_hcd *uhci) { unsigned long io_addr = uhci->io_addr; @@ -270,14 +263,14 @@ static void hc_state_transitions(struct uhci_hcd *uhci) case UHCI_RUNNING: /* global suspend if nothing connected for 1 second */ - if (!ports_active(uhci) && suspend_allowed(uhci)) { + if (!any_ports_active(uhci) && suspend_allowed(uhci)) { uhci->state = UHCI_SUSPENDING_GRACE; uhci->state_end = jiffies + HZ; } break; case UHCI_SUSPENDING_GRACE: - if (ports_active(uhci)) + if (any_ports_active(uhci)) uhci->state = UHCI_RUNNING; else if (time_after_eq(jiffies, uhci->state_end)) suspend_hc(uhci); @@ -302,58 +295,24 @@ static void hc_state_transitions(struct uhci_hcd *uhci) } } -static int init_stall_timer(struct usb_hcd *hcd); - -static void stall_callback(unsigned long ptr) +static void stall_callback(unsigned long _uhci) { - struct usb_hcd *hcd = (struct usb_hcd *)ptr; - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - struct urb_priv *up; + struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci; unsigned long flags; spin_lock_irqsave(&uhci->lock, flags); uhci_scan_schedule(uhci, NULL); - - list_for_each_entry(up, &uhci->urb_list, urb_list) { - struct urb *u = up->urb; - - spin_lock(&u->lock); - - /* Check if the FSBR timed out */ - if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) - uhci_fsbr_timeout(uhci, u); - - spin_unlock(&u->lock); - } - - /* Really disable FSBR */ - if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { - uhci->fsbrtimeout = 0; - uhci->skel_term_qh->link = UHCI_PTR_TERM; - } + check_fsbr(uhci); /* Poll for and perform state transitions */ hc_state_transitions(uhci); if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED)) uhci_check_ports(uhci); - init_stall_timer(hcd); + restart_timer(uhci); spin_unlock_irqrestore(&uhci->lock, flags); } -static int init_stall_timer(struct usb_hcd *hcd) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - - init_timer(&uhci->stall_timer); - uhci->stall_timer.function = stall_callback; - uhci->stall_timer.data = (unsigned long)hcd; - uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100); - add_timer(&uhci->stall_timer); - - return 0; -} - static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); @@ -509,6 +468,10 @@ static int uhci_start(struct usb_hcd *hcd) init_waitqueue_head(&uhci->waitqh); + init_timer(&uhci->stall_timer); + uhci->stall_timer.function = stall_callback; + uhci->stall_timer.data = (unsigned long) uhci; + uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl), &dma_handle, 0); if (!uhci->fl) { @@ -646,7 +609,7 @@ static int uhci_start(struct usb_hcd *hcd) if ((retval = start_hc(uhci)) != 0) goto err_alloc_skelqh; - init_stall_timer(hcd); + restart_timer(uhci); udev->speed = USB_SPEED_FULL; diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 4c45ba8390f8..ddb19cbf4b75 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -33,6 +33,22 @@ static __u8 root_hub_hub_des[] = /* status change bits: nonzero writes will clear */ #define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC) +/* A port that either is connected or has a changed-bit set will prevent + * us from AUTO_STOPPING. + */ +static int any_ports_active(struct uhci_hcd *uhci) +{ + int port; + + for (port = 0; port < uhci->rh_numports; ++port) { + if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & + (USBPORTSC_CCS | RWC_BITS)) || + test_bit(port, &uhci->port_c_suspend)) + return 1; + } + return 0; +} + static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 2a7c19501f24..f5c75885f7be 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1537,3 +1537,26 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) /* Wake up anyone waiting for an URB to complete */ wake_up_all(&uhci->waitqh); } + +static void check_fsbr(struct uhci_hcd *uhci) +{ + struct urb_priv *up; + + list_for_each_entry(up, &uhci->urb_list, urb_list) { + struct urb *u = up->urb; + + spin_lock(&u->lock); + + /* Check if the FSBR timed out */ + if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) + uhci_fsbr_timeout(uhci, u); + + spin_unlock(&u->lock); + } + + /* Really disable FSBR */ + if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { + uhci->fsbrtimeout = 0; + uhci->skel_term_qh->link = UHCI_PTR_TERM; + } +} -- cgit v1.2.3 From c8f4fe4358c5e0a79b4bd47b814d19f1d1d06f21 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 9 Apr 2005 17:27:32 -0400 Subject: [PATCH] USB UHCI: Add root hub states This patch starts making some serious changes to the UHCI driver. There's a set of private states for the root hub, and the internal routines for suspending and resuming work completely differently, with transitions based on the new states. Now the driver distinguishes between a privately auto-stopped state and a publicly suspended state, and it will properly suspend controllers with broken resume-detect interrupts instead of resetting them. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-debug.c | 32 +++++ drivers/usb/host/uhci-hcd.c | 285 ++++++++++++++++++++++-------------------- drivers/usb/host/uhci-hcd.h | 49 +++++--- drivers/usb/host/uhci-hub.c | 2 +- 4 files changed, 212 insertions(+), 156 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 24c73c5a3435..4538a98b6f9d 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -237,6 +237,37 @@ static int uhci_show_sc(int port, unsigned short status, char *buf, int len) return out - buf; } +static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len) +{ + char *out = buf; + char *rh_state; + + /* Try to make sure there's enough memory */ + if (len < 60) + return 0; + + switch (uhci->rh_state) { + case UHCI_RH_RESET: + rh_state = "reset"; break; + case UHCI_RH_SUSPENDED: + rh_state = "suspended"; break; + case UHCI_RH_AUTO_STOPPED: + rh_state = "auto-stopped"; break; + case UHCI_RH_RESUMING: + rh_state = "resuming"; break; + case UHCI_RH_SUSPENDING: + rh_state = "suspending"; break; + case UHCI_RH_RUNNING: + rh_state = "running"; break; + case UHCI_RH_RUNNING_NODEVS: + rh_state = "running, no devs"; break; + default: + rh_state = "?"; break; + } + out += sprintf(out, "Root-hub state: %s\n", rh_state); + return out - buf; +} + static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) { char *out = buf; @@ -408,6 +439,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) spin_lock_irqsave(&uhci->lock, flags); + out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); out += sprintf(out, "HC status\n"); out += uhci_show_status(uhci, out, len - (out - buf)); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index c17bd7ebc021..57b36dcea5d0 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -64,7 +64,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v2.2" +#define DRIVER_VERSION "v2.3" #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \ Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \ Alan Stern" @@ -109,33 +109,6 @@ static inline void restart_timer(struct uhci_hcd *uhci) #include "uhci-debug.c" #include "uhci-q.c" -static int suspend_allowed(struct uhci_hcd *uhci) -{ - unsigned long io_addr = uhci->io_addr; - int i; - - if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL) - return 1; - - /* Some of Intel's USB controllers have a bug that causes false - * resume indications if any port has an over current condition. - * To prevent problems, we will not allow a global suspend if - * any ports are OC. - * - * Some motherboards using Intel's chipsets (but not using all - * the USB ports) appear to hardwire the over current inputs active - * to disable the USB ports. - */ - - /* check for over current condition on any port */ - for (i = 0; i < uhci->rh_numports; i++) { - if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC) - return 0; - } - - return 1; -} - static void reset_hc(struct uhci_hcd *uhci) { unsigned long io_addr = uhci->io_addr; @@ -147,7 +120,6 @@ static void reset_hc(struct uhci_hcd *uhci) outw(0, uhci->io_addr + USBINTR); /* Global reset for 50ms */ - uhci->state = UHCI_RESET; outw(USBCMD_GRESET, io_addr + USBCMD); msleep(50); outw(0, io_addr + USBCMD); @@ -156,63 +128,130 @@ static void reset_hc(struct uhci_hcd *uhci) msleep(10); uhci->resume_detect = 0; uhci->is_stopped = UHCI_IS_STOPPED; + uhci->rh_state = UHCI_RH_RESET; } -static void suspend_hc(struct uhci_hcd *uhci) +static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) { - unsigned long io_addr = uhci->io_addr; + int port; - dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); - uhci->state = UHCI_SUSPENDED; - uhci->resume_detect = 0; - outw(USBCMD_EGSM, io_addr + USBCMD); + switch (to_pci_dev(uhci_dev(uhci))->vendor) { + default: + break; + + case PCI_VENDOR_ID_GENESYS: + /* Genesys Logic's GL880S controllers don't generate + * resume-detect interrupts. + */ + return 1; + + case PCI_VENDOR_ID_INTEL: + /* Some of Intel's USB controllers have a bug that causes + * resume-detect interrupts if any port has an over-current + * condition. To make matters worse, some motherboards + * hardwire unused USB ports' over-current inputs active! + * To prevent problems, we will not enable resume-detect + * interrupts if any ports are OC. + */ + for (port = 0; port < uhci->rh_numports; ++port) { + if (inw(uhci->io_addr + USBPORTSC1 + port * 2) & + USBPORTSC_OC) + return 1; + } + break; + } + return 0; +} + +static void suspend_hc(struct uhci_hcd *uhci, enum uhci_rh_state new_state) +__releases(uhci->lock) +__acquires(uhci->lock) +{ + int auto_stop; + int int_enable; + + auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); + dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__, + (auto_stop ? " (auto-stop)" : "")); + + /* If we get a suspend request when we're already auto-stopped + * then there's nothing to do. + */ + if (uhci->rh_state == UHCI_RH_AUTO_STOPPED) { + uhci->rh_state = new_state; + return; + } + + /* Enable resume-detect interrupts if they work. + * Then enter Global Suspend mode, still configured. + */ + int_enable = (resume_detect_interrupts_are_broken(uhci) ? + 0 : USBINTR_RESUME); + outw(int_enable, uhci->io_addr + USBINTR); + outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD); + udelay(5); + + /* If we're auto-stopping then no devices have been attached + * for a while, so there shouldn't be any active URBs and the + * controller should stop after a few microseconds. Otherwise + * we will give the controller one frame to stop. + */ + if (!auto_stop && !(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) { + uhci->rh_state = UHCI_RH_SUSPENDING; + spin_unlock_irq(&uhci->lock); + msleep(1); + spin_lock_irq(&uhci->lock); + } + if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) + dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n"); - /* FIXME: Wait for the controller to actually stop */ uhci_get_current_frame_number(uhci); + smp_wmb(); + + uhci->rh_state = new_state; uhci->is_stopped = UHCI_IS_STOPPED; + uhci->resume_detect = 0; uhci_scan_schedule(uhci, NULL); } static void wakeup_hc(struct uhci_hcd *uhci) +__releases(uhci->lock) +__acquires(uhci->lock) { - unsigned long io_addr = uhci->io_addr; + dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__, + uhci->rh_state == UHCI_RH_AUTO_STOPPED ? + " (auto-start)" : ""); - switch (uhci->state) { - case UHCI_SUSPENDED: /* Start the resume */ - dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); - - /* Global resume for >= 20ms */ - outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD); - uhci->state = UHCI_RESUMING_1; - uhci->state_end = jiffies + msecs_to_jiffies(20); - uhci->is_stopped = 0; - break; + /* If we are auto-stopped then no devices are attached so there's + * no need for wakeup signals. Otherwise we send Global Resume + * for 20 ms. + */ + if (uhci->rh_state == UHCI_RH_SUSPENDED) { + uhci->rh_state = UHCI_RH_RESUMING; + outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF, + uhci->io_addr + USBCMD); + spin_unlock_irq(&uhci->lock); + msleep(20); + spin_lock_irq(&uhci->lock); - case UHCI_RESUMING_1: /* End global resume */ - uhci->state = UHCI_RESUMING_2; - outw(0, io_addr + USBCMD); - /* Falls through */ - - case UHCI_RESUMING_2: /* Wait for EOP to be sent */ - if (inw(io_addr + USBCMD) & USBCMD_FGR) - break; - - /* Run for at least 1 second, and - * mark it configured with a 64-byte max packet */ - uhci->state = UHCI_RUNNING_GRACE; - uhci->state_end = jiffies + HZ; - outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, - io_addr + USBCMD); - break; + /* End Global Resume and wait for EOP to be sent */ + outw(USBCMD_CF, uhci->io_addr + USBCMD); + udelay(4); + if (inw(uhci->io_addr + USBCMD) & USBCMD_FGR) + dev_warn(uhci_dev(uhci), "FGR not stopped yet!\n"); + } - case UHCI_RUNNING_GRACE: /* Now allowed to suspend */ - uhci->state = UHCI_RUNNING; - break; + uhci->rh_state = UHCI_RH_RUNNING; + uhci->is_stopped = 0; + smp_wmb(); - default: - break; - } + /* Mark it configured and running with a 64-byte max packet. + * All interrupts are enabled, even though RD won't do anything. + */ + outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, uhci->io_addr + USBCMD); + outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, + uhci->io_addr + USBINTR); } static int start_hc(struct uhci_hcd *uhci) @@ -249,49 +288,40 @@ static int start_hc(struct uhci_hcd *uhci) outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD); /* Run and mark it configured with a 64-byte max packet */ - uhci->state = UHCI_RUNNING_GRACE; - uhci->state_end = jiffies + HZ; + uhci->rh_state = UHCI_RH_RUNNING; outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); uhci->is_stopped = 0; return 0; } -static void hc_state_transitions(struct uhci_hcd *uhci) +static void rh_state_transitions(struct uhci_hcd *uhci) { - switch (uhci->state) { - case UHCI_RUNNING: - - /* global suspend if nothing connected for 1 second */ - if (!any_ports_active(uhci) && suspend_allowed(uhci)) { - uhci->state = UHCI_SUSPENDING_GRACE; - uhci->state_end = jiffies + HZ; - } - break; - - case UHCI_SUSPENDING_GRACE: - if (any_ports_active(uhci)) - uhci->state = UHCI_RUNNING; - else if (time_after_eq(jiffies, uhci->state_end)) - suspend_hc(uhci); - break; - - case UHCI_SUSPENDED: - - /* wakeup if requested by a device */ - if (uhci->resume_detect) - wakeup_hc(uhci); - break; - - case UHCI_RESUMING_1: - case UHCI_RESUMING_2: - case UHCI_RUNNING_GRACE: - if (time_after_eq(jiffies, uhci->state_end)) - wakeup_hc(uhci); - break; - - default: - break; + switch (uhci->rh_state) { + case UHCI_RH_RUNNING: + /* are any devices attached? */ + if (!any_ports_active(uhci)) { + uhci->rh_state = UHCI_RH_RUNNING_NODEVS; + uhci->auto_stop_time = jiffies + HZ; + } + break; + + case UHCI_RH_RUNNING_NODEVS: + /* auto-stop if nothing connected for 1 second */ + if (any_ports_active(uhci)) + uhci->rh_state = UHCI_RH_RUNNING; + else if (time_after_eq(jiffies, uhci->auto_stop_time)) + suspend_hc(uhci, UHCI_RH_AUTO_STOPPED); + break; + + case UHCI_RH_AUTO_STOPPED: + /* wakeup if requested by a device */ + if (uhci->resume_detect) + wakeup_hc(uhci); + break; + + default: + break; } } @@ -305,8 +335,8 @@ static void stall_callback(unsigned long _uhci) check_fsbr(uhci); /* Poll for and perform state transitions */ - hc_state_transitions(uhci); - if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED)) + rh_state_transitions(uhci); + if (unlikely(uhci->suspended_ports)) uhci_check_ports(uhci); restart_timer(uhci); @@ -336,7 +366,8 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) if (status & USBSTS_HCPE) dev_err(uhci_dev(uhci), "host controller process " "error, something bad happened!\n"); - if ((status & USBSTS_HCH) && uhci->state > 0) { + if ((status & USBSTS_HCH) && + uhci->rh_state >= UHCI_RH_RUNNING) { dev_err(uhci_dev(uhci), "host controller halted, " "very bad!\n"); /* FIXME: Reset the controller, fix the offending TD */ @@ -683,17 +714,7 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) struct uhci_hcd *uhci = hcd_to_uhci(hcd); spin_lock_irq(&uhci->lock); - - /* Don't try to suspend broken motherboards, reset instead */ - if (suspend_allowed(uhci)) - suspend_hc(uhci); - else { - spin_unlock_irq(&uhci->lock); - reset_hc(uhci); - spin_lock_irq(&uhci->lock); - uhci_scan_schedule(uhci, NULL); - } - + suspend_hc(uhci, UHCI_RH_SUSPENDED); spin_unlock_irq(&uhci->lock); return 0; } @@ -701,13 +722,9 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) static int uhci_resume(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - int rc; - - pci_set_master(to_pci_dev(uhci_dev(uhci))); spin_lock_irq(&uhci->lock); - - if (uhci->state == UHCI_SUSPENDED) { + if (uhci->rh_state == UHCI_RH_SUSPENDED) { /* * Some systems don't maintain the UHCI register values @@ -721,19 +738,13 @@ static int uhci_resume(struct usb_hcd *hcd) outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, uhci->io_addr + USBINTR); - uhci->resume_detect = 1; pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, USBLEGSUP_DEFAULT); - } else { - spin_unlock_irq(&uhci->lock); - reset_hc(uhci); - if ((rc = start_hc(uhci)) != 0) - return rc; - spin_lock_irq(&uhci->lock); + wakeup_hc(uhci); } - hcd->state = HC_STATE_RUNNING; - spin_unlock_irq(&uhci->lock); + + hcd->state = HC_STATE_RUNNING; return 0; } #endif @@ -750,13 +761,15 @@ static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd, static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - int frame_number; unsigned long flags; + int is_stopped; + int frame_number; /* Minimize latency by avoiding the spinlock */ local_irq_save(flags); - rmb(); - frame_number = (uhci->is_stopped ? uhci->frame_number : + is_stopped = uhci->is_stopped; + smp_rmb(); + frame_number = (is_stopped ? uhci->frame_number : inw(uhci->io_addr + USBFRNUM)); local_irq_restore(flags); return frame_number; diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 02255d69e1fe..4bac57c74ec2 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -314,26 +314,29 @@ static inline int __interval_to_skel(int interval) } /* - * Device states for the host controller. + * States for the root hub. * * To prevent "bouncing" in the presence of electrical noise, - * we insist on a 1-second "grace" period, before switching to - * the RUNNING or SUSPENDED states, during which the state is - * not allowed to change. - * - * The resume process is divided into substates in order to avoid - * potentially length delays during the timer handler. - * - * States in which the host controller is halted must have values <= 0. + * when there are no devices attached we delay for 1 second in the + * RUNNING_NODEVS state before switching to the AUTO_STOPPED state. + * + * (Note that the AUTO_STOPPED state won't be necessary once the hub + * driver learns to autosuspend.) */ -enum uhci_state { - UHCI_RESET, - UHCI_RUNNING_GRACE, /* Before RUNNING */ - UHCI_RUNNING, /* The normal state */ - UHCI_SUSPENDING_GRACE, /* Before SUSPENDED */ - UHCI_SUSPENDED = -10, /* When no devices are attached */ - UHCI_RESUMING_1, - UHCI_RESUMING_2 +enum uhci_rh_state { + /* In the next 4 states the HC must be halted */ + UHCI_RH_RESET, + UHCI_RH_SUSPENDED, + UHCI_RH_AUTO_STOPPED, + UHCI_RH_RESUMING, + + /* In the next state the HC changes from running to halted, so it + * can legally appear either way */ + UHCI_RH_SUSPENDING, + + /* In the next two states it's an error if the HC is halted */ + UHCI_RH_RUNNING, /* The normal state */ + UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */ }; /* @@ -363,8 +366,9 @@ struct uhci_hcd { int fsbr; /* Full-speed bandwidth reclamation */ unsigned long fsbrtimeout; /* FSBR delay */ - enum uhci_state state; /* FIXME: needs a spinlock */ - unsigned long state_end; /* Time of next transition */ + enum uhci_rh_state rh_state; + unsigned long auto_stop_time; /* When to AUTO_STOP */ + unsigned int frame_number; /* As of last check */ unsigned int is_stopped; #define UHCI_IS_STOPPED 9999 /* Larger than a frame # */ @@ -451,4 +455,11 @@ struct urb_priv { * #2 urb->lock */ + +/* Some special IDs */ + +#define PCI_VENDOR_ID_GENESYS 0x17a0 +#define PCI_DEVICE_ID_GL880S_UHCI 0x8083 +#define PCI_DEVICE_ID_GL880S_EHCI 0x8084 + #endif diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index ddb19cbf4b75..fc34fee2ab07 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -60,7 +60,7 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) test_bit(port, &uhci->port_c_suspend)) *buf |= (1 << (port + 1)); } - if (*buf && uhci->state == UHCI_SUSPENDED) + if (*buf && uhci->is_stopped) uhci->resume_detect = 1; return !!*buf; } -- cgit v1.2.3 From a8bed8b6be75bc5a46aa599ab360d5f1db291c8f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 9 Apr 2005 17:29:00 -0400 Subject: [PATCH] USB UHCI: Add root-hub suspend/resume support This patch implements (finally!) separate suspend and resume routines for the root hub and the controller in the UHCI driver. It also changes the sequence used to reset the controller during initial probing, so as to preserve the existing state during a Resume-From-Disk. (This new sequence is what should be used in the PCI Quirks code for early USB handoffs, incidentally.) Lastly it adds a notion of the controller being "inaccessible" while in a PCI low-power state, when normal I/O operations shouldn't be allowed. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 288 +++++++++++++++++++++++++++++--------------- drivers/usb/host/uhci-hcd.h | 10 +- drivers/usb/host/uhci-hub.c | 6 + 3 files changed, 202 insertions(+), 102 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 57b36dcea5d0..730ba3a621ae 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -109,28 +109,113 @@ static inline void restart_timer(struct uhci_hcd *uhci) #include "uhci-debug.c" #include "uhci-q.c" +/* + * Make sure the controller is completely inactive, unable to + * generate interrupts or do DMA. + */ static void reset_hc(struct uhci_hcd *uhci) { - unsigned long io_addr = uhci->io_addr; + /* Turn off PIRQ enable and SMI enable. (This also turns off the + * BIOS's USB Legacy Support.) Turn off all the R/WC bits too. + */ + pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, + USBLEGSUP_RWC); - /* Turn off PIRQ, SMI, and all interrupts. This also turns off - * the BIOS's USB Legacy Support. + /* Reset the HC - this will force us to get a + * new notification of any already connected + * ports due to the virtual disconnect that it + * implies. */ - pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); - outw(0, uhci->io_addr + USBINTR); + outw(USBCMD_HCRESET, uhci->io_addr + USBCMD); + mb(); + udelay(5); + if (inw(uhci->io_addr + USBCMD) & USBCMD_HCRESET) + dev_warn(uhci_dev(uhci), "HCRESET not completed yet!\n"); - /* Global reset for 50ms */ - outw(USBCMD_GRESET, io_addr + USBCMD); - msleep(50); - outw(0, io_addr + USBCMD); + /* Just to be safe, disable interrupt requests and + * make sure the controller is stopped. + */ + outw(0, uhci->io_addr + USBINTR); + outw(0, uhci->io_addr + USBCMD); - /* Another 10ms delay */ - msleep(10); uhci->resume_detect = 0; - uhci->is_stopped = UHCI_IS_STOPPED; + uhci->port_c_suspend = uhci->suspended_ports = + uhci->resuming_ports = 0; uhci->rh_state = UHCI_RH_RESET; + uhci->is_stopped = UHCI_IS_STOPPED; + uhci_to_hcd(uhci)->state = HC_STATE_HALT; } +/* + * Initialize a controller that was newly discovered or has just been + * resumed. In either case we can't be sure of its previous state. + */ +static void check_and_reset_hc(struct uhci_hcd *uhci) +{ + u16 legsup; + unsigned int cmd, intr; + + /* + * When restarting a suspended controller, we expect all the + * settings to be the same as we left them: + * + * PIRQ and SMI disabled, no R/WC bits set in USBLEGSUP; + * Controller is stopped and configured with EGSM set; + * No interrupts enabled except possibly Resume Detect. + * + * If any of these conditions are violated we do a complete reset. + */ + pci_read_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, &legsup); + if (legsup & ~USBLEGSUP_RO) { + dev_dbg(uhci_dev(uhci), "%s: legsup = 0x%04x\n", + __FUNCTION__, legsup); + goto reset_needed; + } + + cmd = inw(uhci->io_addr + USBCMD); + if ((cmd & USBCMD_RS) || !(cmd & USBCMD_CF) || !(cmd & USBCMD_EGSM)) { + dev_dbg(uhci_dev(uhci), "%s: cmd = 0x%04x\n", + __FUNCTION__, cmd); + goto reset_needed; + } + + intr = inw(uhci->io_addr + USBINTR); + if (intr & (~USBINTR_RESUME)) { + dev_dbg(uhci_dev(uhci), "%s: intr = 0x%04x\n", + __FUNCTION__, intr); + goto reset_needed; + } + return; + +reset_needed: + dev_dbg(uhci_dev(uhci), "Performing full reset\n"); + reset_hc(uhci); +} + +/* + * Store the basic register settings needed by the controller. + */ +static void configure_hc(struct uhci_hcd *uhci) +{ + /* Set the frame length to the default: 1 ms exactly */ + outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF); + + /* Store the frame list base address */ + outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); + + /* Set the current frame number */ + outw(uhci->frame_number, uhci->io_addr + USBFRNUM); + + /* Mark controller as running before we enable interrupts */ + uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; + mb(); + + /* Enable PIRQ */ + pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, + USBLEGSUP_DEFAULT); +} + + static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) { int port; @@ -163,7 +248,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) return 0; } -static void suspend_hc(struct uhci_hcd *uhci, enum uhci_rh_state new_state) +static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state) __releases(uhci->lock) __acquires(uhci->lock) { @@ -189,6 +274,7 @@ __acquires(uhci->lock) 0 : USBINTR_RESUME); outw(int_enable, uhci->io_addr + USBINTR); outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD); + mb(); udelay(5); /* If we're auto-stopping then no devices have been attached @@ -215,7 +301,22 @@ __acquires(uhci->lock) uhci_scan_schedule(uhci, NULL); } -static void wakeup_hc(struct uhci_hcd *uhci) +static void start_rh(struct uhci_hcd *uhci) +{ + uhci->rh_state = UHCI_RH_RUNNING; + uhci->is_stopped = 0; + smp_wmb(); + + /* Mark it configured and running with a 64-byte max packet. + * All interrupts are enabled, even though RESUME won't do anything. + */ + outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, uhci->io_addr + USBCMD); + outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, + uhci->io_addr + USBINTR); + mb(); +} + +static void wakeup_rh(struct uhci_hcd *uhci) __releases(uhci->lock) __acquires(uhci->lock) { @@ -237,62 +338,13 @@ __acquires(uhci->lock) /* End Global Resume and wait for EOP to be sent */ outw(USBCMD_CF, uhci->io_addr + USBCMD); + mb(); udelay(4); if (inw(uhci->io_addr + USBCMD) & USBCMD_FGR) dev_warn(uhci_dev(uhci), "FGR not stopped yet!\n"); } - uhci->rh_state = UHCI_RH_RUNNING; - uhci->is_stopped = 0; - smp_wmb(); - - /* Mark it configured and running with a 64-byte max packet. - * All interrupts are enabled, even though RD won't do anything. - */ - outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, uhci->io_addr + USBCMD); - outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, - uhci->io_addr + USBINTR); -} - -static int start_hc(struct uhci_hcd *uhci) -{ - unsigned long io_addr = uhci->io_addr; - int timeout = 10; - - /* - * Reset the HC - this will force us to get a - * new notification of any already connected - * ports due to the virtual disconnect that it - * implies. - */ - outw(USBCMD_HCRESET, io_addr + USBCMD); - while (inw(io_addr + USBCMD) & USBCMD_HCRESET) { - if (--timeout < 0) { - dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n"); - return -ETIMEDOUT; - } - msleep(1); - } - - /* Mark controller as running before we enable interrupts */ - uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; - - /* Turn on PIRQ and all interrupts */ - pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, - USBLEGSUP_DEFAULT); - outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, - io_addr + USBINTR); - - /* Start at frame 0 */ - outw(0, io_addr + USBFRNUM); - outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD); - - /* Run and mark it configured with a 64-byte max packet */ - uhci->rh_state = UHCI_RH_RUNNING; - outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); - uhci->is_stopped = 0; - - return 0; + start_rh(uhci); } static void rh_state_transitions(struct uhci_hcd *uhci) @@ -311,13 +363,13 @@ static void rh_state_transitions(struct uhci_hcd *uhci) if (any_ports_active(uhci)) uhci->rh_state = UHCI_RH_RUNNING; else if (time_after_eq(jiffies, uhci->auto_stop_time)) - suspend_hc(uhci, UHCI_RH_AUTO_STOPPED); + suspend_rh(uhci, UHCI_RH_AUTO_STOPPED); break; case UHCI_RH_AUTO_STOPPED: /* wakeup if requested by a device */ if (uhci->resume_detect) - wakeup_hc(uhci); + wakeup_rh(uhci); break; default: @@ -336,7 +388,7 @@ static void stall_callback(unsigned long _uhci) /* Poll for and perform state transitions */ rh_state_transitions(uhci); - if (unlikely(uhci->suspended_ports)) + if (uhci->suspended_ports && !uhci->hc_inaccessible) uhci_check_ports(uhci); restart_timer(uhci); @@ -346,7 +398,6 @@ static void stall_callback(unsigned long _uhci) static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned long io_addr = uhci->io_addr; unsigned short status; /* @@ -354,10 +405,10 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) * interrupt cause. Contrary to the UHCI specification, the * "HC Halted" status bit is persistent: it is RO, not R/WC. */ - status = inw(io_addr + USBSTS); + status = inw(uhci->io_addr + USBSTS); if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */ return IRQ_NONE; - outw(status, io_addr + USBSTS); /* Clear it */ + outw(status, uhci->io_addr + USBSTS); /* Clear it */ if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { if (status & USBSTS_HSE) @@ -440,10 +491,10 @@ static int uhci_reset(struct usb_hcd *hcd) 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. + /* Kick BIOS off this hardware and reset if the controller + * isn't already safely quiescent. */ - reset_hc(uhci); + check_and_reset_hc(uhci); return 0; } @@ -634,11 +685,12 @@ static int uhci_start(struct usb_hcd *hcd) /* * Some architectures require a full mb() to enforce completion of - * the memory writes above before the I/O transfers in start_hc(). + * the memory writes above before the I/O transfers in configure_hc(). */ mb(); - if ((retval = start_hc(uhci)) != 0) - goto err_alloc_skelqh; + + configure_hc(uhci); + start_rh(uhci); restart_timer(uhci); @@ -656,9 +708,8 @@ static int uhci_start(struct usb_hcd *hcd) * error exits: */ err_start_root_hub: - reset_hc(uhci); - del_timer_sync(&uhci->stall_timer); + reset_hc(uhci); err_alloc_skelqh: for (i = 0; i < UHCI_NUM_SKELQH; i++) @@ -699,9 +750,9 @@ static void uhci_stop(struct usb_hcd *hcd) struct uhci_hcd *uhci = hcd_to_uhci(hcd); del_timer_sync(&uhci->stall_timer); - reset_hc(uhci); spin_lock_irq(&uhci->lock); + reset_hc(uhci); uhci_scan_schedule(uhci, NULL); spin_unlock_irq(&uhci->lock); @@ -709,12 +760,47 @@ static void uhci_stop(struct usb_hcd *hcd) } #ifdef CONFIG_PM +static int uhci_rh_suspend(struct usb_hcd *hcd) +{ + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + + spin_lock_irq(&uhci->lock); + suspend_rh(uhci, UHCI_RH_SUSPENDED); + spin_unlock_irq(&uhci->lock); + return 0; +} + +static int uhci_rh_resume(struct usb_hcd *hcd) +{ + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + + spin_lock_irq(&uhci->lock); + wakeup_rh(uhci); + spin_unlock_irq(&uhci->lock); + return 0; +} + static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); + dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); + spin_lock_irq(&uhci->lock); - suspend_hc(uhci, UHCI_RH_SUSPENDED); + +#ifndef CONFIG_USB_SUSPEND + /* Otherwise this would never happen */ + suspend_rh(uhci, UHCI_RH_SUSPENDED); +#endif + + /* All PCI host controllers are required to disable IRQ generation + * at the source, so we must turn off PIRQ. + */ + pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); + uhci->hc_inaccessible = 1; + + /* FIXME: Enable non-PME# remote wakeup? */ + spin_unlock_irq(&uhci->lock); return 0; } @@ -723,28 +809,28 @@ static int uhci_resume(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); + dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); + spin_lock_irq(&uhci->lock); - if (uhci->rh_state == UHCI_RH_SUSPENDED) { - /* - * Some systems don't maintain the UHCI register values - * during a PM suspend/resume cycle, so reinitialize - * the Frame Number, Framelist Base Address, Interrupt - * Enable, and Legacy Support registers. - */ - pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, - 0); - outw(uhci->frame_number, uhci->io_addr + USBFRNUM); - outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); - outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | - USBINTR_SP, uhci->io_addr + USBINTR); - pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, - USBLEGSUP_DEFAULT); - wakeup_hc(uhci); - } - spin_unlock_irq(&uhci->lock); + /* FIXME: Disable non-PME# remote wakeup? */ + + uhci->hc_inaccessible = 0; + + /* The BIOS may have changed the controller settings during a + * system wakeup. Check it and reconfigure to avoid problems. + */ + check_and_reset_hc(uhci); + configure_hc(uhci); + +#ifndef CONFIG_USB_SUSPEND + /* Otherwise this would never happen */ + wakeup_rh(uhci); +#endif + if (uhci->rh_state == UHCI_RH_RESET) + suspend_rh(uhci, UHCI_RH_SUSPENDED); - hcd->state = HC_STATE_RUNNING; + spin_unlock_irq(&uhci->lock); return 0; } #endif @@ -792,6 +878,8 @@ static const struct hc_driver uhci_driver = { #ifdef CONFIG_PM .suspend = uhci_suspend, .resume = uhci_resume, + .hub_suspend = uhci_rh_suspend, + .hub_resume = uhci_rh_resume, #endif .stop = uhci_stop, diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 4bac57c74ec2..827df5e06800 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -41,6 +41,7 @@ #define USBFRNUM 6 #define USBFLBASEADD 8 #define USBSOF 12 +#define USBSOF_DEFAULT 64 /* Frame length is exactly 1 ms */ /* USB port status and control registers */ #define USBPORTSC1 16 @@ -66,6 +67,8 @@ /* Legacy support register */ #define USBLEGSUP 0xc0 #define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ +#define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ +#define USBLEGSUP_RO 0x5040 /* R/O and reserved bits */ #define UHCI_NULL_DATA_SIZE 0x7FF /* for UHCI controller TD */ @@ -325,8 +328,9 @@ static inline int __interval_to_skel(int interval) */ enum uhci_rh_state { /* In the next 4 states the HC must be halted */ - UHCI_RH_RESET, + UHCI_RH_RESET, /* These two must come first */ UHCI_RH_SUSPENDED, + UHCI_RH_AUTO_STOPPED, UHCI_RH_RESUMING, @@ -334,7 +338,8 @@ enum uhci_rh_state { * can legally appear either way */ UHCI_RH_SUSPENDING, - /* In the next two states it's an error if the HC is halted */ + /* In the next two states it's an error if the HC is halted. + * These two must come last */ UHCI_RH_RUNNING, /* The normal state */ UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */ }; @@ -376,6 +381,7 @@ struct uhci_hcd { unsigned int scan_in_progress:1; /* Schedule scan is running */ unsigned int need_rescan:1; /* Redo the schedule scan */ unsigned int resume_detect:1; /* Need a Global Resume */ + unsigned int hc_inaccessible:1; /* HC is suspended or dead */ /* Support for port suspend/resume/reset */ unsigned long port_c_suspend; /* Bit-arrays of ports */ diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index fc34fee2ab07..13652de52203 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -54,6 +54,9 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) struct uhci_hcd *uhci = hcd_to_uhci(hcd); int port; + if (uhci->hc_inaccessible) + return 0; + *buf = 0; for (port = 0; port < uhci->rh_numports; ++port) { if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) || @@ -150,6 +153,9 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wPortChange, wPortStatus; unsigned long flags; + if (uhci->hc_inaccessible) + return -ETIMEDOUT; + spin_lock_irqsave(&uhci->lock, flags); switch (typeReq) { -- cgit v1.2.3 From 4daaa87c8f19c5f1978470e9e91b74d9e0fb0f8e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 9 Apr 2005 17:30:08 -0400 Subject: [PATCH] USB UHCI: Fix up loose ends This patch tidies up a few loose ends left by the preceding patches. It indicates the controller supports remote wakeup whenever the PM capability is present -- which shouldn't cause any harm if the assumption turns out to be wrong. It refuses to suspend the controller if the root hub is still active, and it refuses to resume the root hub if the controller is suspended. It adds checks for a dead controller in several spots, and it adds memory barriers as needed to insure that I/O operations are completed before moving on. Actually I'm not certain the last part is being done correctly. With code like this: outw(..., ...); mb(); udelay(5); do we know for certain that the outw() will complete _before_ the delay begins? If not, how should this be written? Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 86 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 21 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 730ba3a621ae..82e608a4bbd0 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -13,18 +13,13 @@ * (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 + * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu * * Intel documents this fairly well, and as far as I know there * are no royalties or anything like that, but even so there are * people who decided that they want to do the same thing in a * completely different way. * - * WARNING! The USB documentation is downright evil. Most of it - * is just crap, written by a committee. You're better off ignoring - * most of it, the important stuff is: - * - the low-level protocol (fairly simple but lots of small details) - * - working around the horridness of the rest */ #include @@ -146,6 +141,15 @@ static void reset_hc(struct uhci_hcd *uhci) uhci_to_hcd(uhci)->state = HC_STATE_HALT; } +/* + * Last rites for a defunct/nonfunctional controller + */ +static void hc_died(struct uhci_hcd *uhci) +{ + reset_hc(uhci); + uhci->hc_inaccessible = 1; +} + /* * Initialize a controller that was newly discovered or has just been * resumed. In either case we can't be sure of its previous state. @@ -287,6 +291,8 @@ __acquires(uhci->lock) spin_unlock_irq(&uhci->lock); msleep(1); spin_lock_irq(&uhci->lock); + if (uhci->hc_inaccessible) /* Died */ + return; } if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n"); @@ -335,6 +341,8 @@ __acquires(uhci->lock) spin_unlock_irq(&uhci->lock); msleep(20); spin_lock_irq(&uhci->lock); + if (uhci->hc_inaccessible) /* Died */ + return; /* End Global Resume and wait for EOP to be sent */ outw(USBCMD_CF, uhci->io_addr + USBCMD); @@ -387,9 +395,11 @@ static void stall_callback(unsigned long _uhci) check_fsbr(uhci); /* Poll for and perform state transitions */ - rh_state_transitions(uhci); - if (uhci->suspended_ports && !uhci->hc_inaccessible) - uhci_check_ports(uhci); + if (!uhci->hc_inaccessible) { + rh_state_transitions(uhci); + if (uhci->suspended_ports) + uhci_check_ports(uhci); + } restart_timer(uhci); spin_unlock_irqrestore(&uhci->lock, flags); @@ -399,6 +409,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned short status; + unsigned long flags; /* * Read the interrupt status, and write it back to clear the @@ -417,20 +428,26 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) if (status & USBSTS_HCPE) dev_err(uhci_dev(uhci), "host controller process " "error, something bad happened!\n"); - if ((status & USBSTS_HCH) && - uhci->rh_state >= UHCI_RH_RUNNING) { - dev_err(uhci_dev(uhci), "host controller halted, " + if (status & USBSTS_HCH) { + spin_lock_irqsave(&uhci->lock, flags); + if (uhci->rh_state >= UHCI_RH_RUNNING) { + dev_err(uhci_dev(uhci), + "host controller halted, " "very bad!\n"); - /* FIXME: Reset the controller, fix the offending TD */ + hc_died(uhci); + spin_unlock_irqrestore(&uhci->lock, flags); + return IRQ_HANDLED; + } + spin_unlock_irqrestore(&uhci->lock, flags); } } if (status & USBSTS_RD) uhci->resume_detect = 1; - spin_lock(&uhci->lock); + spin_lock_irqsave(&uhci->lock, flags); uhci_scan_schedule(uhci, regs); - spin_unlock(&uhci->lock); + spin_unlock_irqrestore(&uhci->lock, flags); return IRQ_HANDLED; } @@ -525,10 +542,15 @@ static int uhci_start(struct usb_hcd *hcd) struct dentry *dentry; io_size = (unsigned) hcd->rsrc_len; + if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM)) + hcd->can_wakeup = 1; /* Assume it supports PME# */ - dentry = debugfs_create_file(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, &uhci_debug_operations); + dentry = debugfs_create_file(hcd->self.bus_name, + S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, + &uhci_debug_operations); if (!dentry) { - dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n"); + dev_err(uhci_dev(uhci), + "couldn't create uhci debugfs entry\n"); retval = -ENOMEM; goto err_create_debug_entry; } @@ -765,7 +787,8 @@ static int uhci_rh_suspend(struct usb_hcd *hcd) struct uhci_hcd *uhci = hcd_to_uhci(hcd); spin_lock_irq(&uhci->lock); - suspend_rh(uhci, UHCI_RH_SUSPENDED); + if (!uhci->hc_inaccessible) /* Not dead */ + suspend_rh(uhci, UHCI_RH_SUSPENDED); spin_unlock_irq(&uhci->lock); return 0; } @@ -773,26 +796,44 @@ static int uhci_rh_suspend(struct usb_hcd *hcd) static int uhci_rh_resume(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); + int rc = 0; spin_lock_irq(&uhci->lock); - wakeup_rh(uhci); + if (uhci->hc_inaccessible) { + if (uhci->rh_state == UHCI_RH_SUSPENDED) { + dev_warn(uhci_dev(uhci), "HC isn't running!\n"); + rc = -ENODEV; + } + /* Otherwise the HC is dead */ + } else + wakeup_rh(uhci); spin_unlock_irq(&uhci->lock); - return 0; + return rc; } static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); + int rc = 0; dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); spin_lock_irq(&uhci->lock); + if (uhci->hc_inaccessible) /* Dead or already suspended */ + goto done; #ifndef CONFIG_USB_SUSPEND /* Otherwise this would never happen */ suspend_rh(uhci, UHCI_RH_SUSPENDED); #endif + if (uhci->rh_state > UHCI_RH_SUSPENDED) { + dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); + hcd->state = HC_STATE_RUNNING; + rc = -EBUSY; + goto done; + }; + /* All PCI host controllers are required to disable IRQ generation * at the source, so we must turn off PIRQ. */ @@ -801,8 +842,9 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) /* FIXME: Enable non-PME# remote wakeup? */ +done: spin_unlock_irq(&uhci->lock); - return 0; + return rc; } static int uhci_resume(struct usb_hcd *hcd) @@ -811,6 +853,8 @@ static int uhci_resume(struct usb_hcd *hcd) dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); + if (uhci->rh_state == UHCI_RH_RESET) /* Dead */ + return 0; spin_lock_irq(&uhci->lock); /* FIXME: Disable non-PME# remote wakeup? */ -- cgit v1.2.3 From 6c1b445c226dd82d0961725dec8051b95003723a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 21 Apr 2005 16:04:58 -0400 Subject: [PATCH] USB UHCI: Use root-hub IRQs while suspended This patch, which has as478b as a prerequisite, enables the uhci-hcd driver to take advantage of root-hub IRQs rather than polling during the time it is suspended. (Unfortunately the hardware doesn't support port-change interrupts while the controller is running.) It also turns off the driver's private timer while the controller is suspended, as it isn't needed then. The combined elimination of polling interrupts and timer interrupts ought to be enough to allow some systems to save a noticeable amount of power while they are otherwise idle. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 70 +++++++++++++++------------------------------ drivers/usb/host/uhci-hcd.h | 12 ++++---- drivers/usb/host/uhci-hub.c | 67 ++++++++++++++++++++++++++++++++++++++----- drivers/usb/host/uhci-q.c | 3 ++ 4 files changed, 92 insertions(+), 60 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 82e608a4bbd0..25a718eb1d0f 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -84,6 +84,8 @@ static char *errbuf; static kmem_cache_t *uhci_up_cachep; /* urb_priv */ +static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state); +static void wakeup_rh(struct uhci_hcd *uhci); static void uhci_get_current_frame_number(struct uhci_hcd *uhci); /* If a transfer is still active after this much time, turn off FSBR */ @@ -133,12 +135,12 @@ static void reset_hc(struct uhci_hcd *uhci) outw(0, uhci->io_addr + USBINTR); outw(0, uhci->io_addr + USBCMD); - uhci->resume_detect = 0; uhci->port_c_suspend = uhci->suspended_ports = uhci->resuming_ports = 0; uhci->rh_state = UHCI_RH_RESET; uhci->is_stopped = UHCI_IS_STOPPED; uhci_to_hcd(uhci)->state = HC_STATE_HALT; + uhci_to_hcd(uhci)->poll_rh = 0; } /* @@ -148,6 +150,7 @@ static void hc_died(struct uhci_hcd *uhci) { reset_hc(uhci); uhci->hc_inaccessible = 1; + del_timer(&uhci->stall_timer); } /* @@ -302,14 +305,14 @@ __acquires(uhci->lock) uhci->rh_state = new_state; uhci->is_stopped = UHCI_IS_STOPPED; - uhci->resume_detect = 0; + del_timer(&uhci->stall_timer); + uhci_to_hcd(uhci)->poll_rh = !int_enable; uhci_scan_schedule(uhci, NULL); } static void start_rh(struct uhci_hcd *uhci) { - uhci->rh_state = UHCI_RH_RUNNING; uhci->is_stopped = 0; smp_wmb(); @@ -320,6 +323,9 @@ static void start_rh(struct uhci_hcd *uhci) outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, uhci->io_addr + USBINTR); mb(); + uhci->rh_state = UHCI_RH_RUNNING; + uhci_to_hcd(uhci)->poll_rh = 1; + restart_timer(uhci); } static void wakeup_rh(struct uhci_hcd *uhci) @@ -353,36 +359,9 @@ __acquires(uhci->lock) } start_rh(uhci); -} - -static void rh_state_transitions(struct uhci_hcd *uhci) -{ - switch (uhci->rh_state) { - case UHCI_RH_RUNNING: - /* are any devices attached? */ - if (!any_ports_active(uhci)) { - uhci->rh_state = UHCI_RH_RUNNING_NODEVS; - uhci->auto_stop_time = jiffies + HZ; - } - break; - case UHCI_RH_RUNNING_NODEVS: - /* auto-stop if nothing connected for 1 second */ - if (any_ports_active(uhci)) - uhci->rh_state = UHCI_RH_RUNNING; - else if (time_after_eq(jiffies, uhci->auto_stop_time)) - suspend_rh(uhci, UHCI_RH_AUTO_STOPPED); - break; - - case UHCI_RH_AUTO_STOPPED: - /* wakeup if requested by a device */ - if (uhci->resume_detect) - wakeup_rh(uhci); - break; - - default: - break; - } + /* Restart root hub polling */ + mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies); } static void stall_callback(unsigned long _uhci) @@ -394,14 +373,8 @@ static void stall_callback(unsigned long _uhci) uhci_scan_schedule(uhci, NULL); check_fsbr(uhci); - /* Poll for and perform state transitions */ - if (!uhci->hc_inaccessible) { - rh_state_transitions(uhci); - if (uhci->suspended_ports) - uhci_check_ports(uhci); - } - - restart_timer(uhci); + if (!uhci->is_stopped) + restart_timer(uhci); spin_unlock_irqrestore(&uhci->lock, flags); } @@ -443,7 +416,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) } if (status & USBSTS_RD) - uhci->resume_detect = 1; + usb_hcd_poll_rh_status(hcd); spin_lock_irqsave(&uhci->lock, flags); uhci_scan_schedule(uhci, regs); @@ -542,6 +515,7 @@ static int uhci_start(struct usb_hcd *hcd) struct dentry *dentry; io_size = (unsigned) hcd->rsrc_len; + hcd->uses_new_polling = 1; if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM)) hcd->can_wakeup = 1; /* Assume it supports PME# */ @@ -714,8 +688,6 @@ static int uhci_start(struct usb_hcd *hcd) configure_hc(uhci); start_rh(uhci); - restart_timer(uhci); - udev->speed = USB_SPEED_FULL; if (usb_hcd_register_root_hub(udev, hcd) != 0) { @@ -730,8 +702,8 @@ static int uhci_start(struct usb_hcd *hcd) * error exits: */ err_start_root_hub: - del_timer_sync(&uhci->stall_timer); reset_hc(uhci); + del_timer_sync(&uhci->stall_timer); err_alloc_skelqh: for (i = 0; i < UHCI_NUM_SKELQH; i++) @@ -771,13 +743,12 @@ static void uhci_stop(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - del_timer_sync(&uhci->stall_timer); - spin_lock_irq(&uhci->lock); reset_hc(uhci); uhci_scan_schedule(uhci, NULL); spin_unlock_irq(&uhci->lock); - + + del_timer_sync(&uhci->stall_timer); release_uhci(uhci); } @@ -844,6 +815,8 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) done: spin_unlock_irq(&uhci->lock); + if (rc == 0) + del_timer_sync(&hcd->rh_timer); return rc; } @@ -875,6 +848,9 @@ static int uhci_resume(struct usb_hcd *hcd) suspend_rh(uhci, UHCI_RH_SUSPENDED); spin_unlock_irq(&uhci->lock); + + if (hcd->poll_rh) + usb_hcd_poll_rh_status(hcd); return 0; } #endif diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 827df5e06800..d7c67b73eb7a 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -327,18 +327,19 @@ static inline int __interval_to_skel(int interval) * driver learns to autosuspend.) */ enum uhci_rh_state { - /* In the next 4 states the HC must be halted */ - UHCI_RH_RESET, /* These two must come first */ + /* In the following states the HC must be halted. + * These two must come first */ + UHCI_RH_RESET, UHCI_RH_SUSPENDED, UHCI_RH_AUTO_STOPPED, UHCI_RH_RESUMING, - /* In the next state the HC changes from running to halted, so it - * can legally appear either way */ + /* In this state the HC changes from running to halted, + * so it can legally appear either way. */ UHCI_RH_SUSPENDING, - /* In the next two states it's an error if the HC is halted. + /* In the following states it's an error if the HC is halted. * These two must come last */ UHCI_RH_RUNNING, /* The normal state */ UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */ @@ -380,7 +381,6 @@ struct uhci_hcd { unsigned int scan_in_progress:1; /* Schedule scan is running */ unsigned int need_rescan:1; /* Redo the schedule scan */ - unsigned int resume_detect:1; /* Need a Global Resume */ unsigned int hc_inaccessible:1; /* HC is suspended or dead */ /* Support for port suspend/resume/reset */ diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 13652de52203..4eace2b19ddb 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -49,22 +49,16 @@ static int any_ports_active(struct uhci_hcd *uhci) return 0; } -static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) +static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf) { - struct uhci_hcd *uhci = hcd_to_uhci(hcd); int port; - if (uhci->hc_inaccessible) - return 0; - *buf = 0; for (port = 0; port < uhci->rh_numports; ++port) { if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) || test_bit(port, &uhci->port_c_suspend)) *buf |= (1 << (port + 1)); } - if (*buf && uhci->is_stopped) - uhci->resume_detect = 1; return !!*buf; } @@ -134,6 +128,11 @@ static void uhci_check_ports(struct uhci_hcd *uhci) set_bit(port, &uhci->resuming_ports); uhci->ports_timeout = jiffies + msecs_to_jiffies(20); + + /* Make sure we see the port again + * after the resuming period is over. */ + mod_timer(&uhci_to_hcd(uhci)->rh_timer, + uhci->ports_timeout); } else if (time_after_eq(jiffies, uhci->ports_timeout)) { uhci_finish_suspend(uhci, port, port_addr); @@ -142,6 +141,60 @@ static void uhci_check_ports(struct uhci_hcd *uhci) } } +static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + unsigned long flags; + int status; + + spin_lock_irqsave(&uhci->lock, flags); + if (uhci->hc_inaccessible) { + status = 0; + goto done; + } + + uhci_check_ports(uhci); + status = get_hub_status_data(uhci, buf); + + switch (uhci->rh_state) { + case UHCI_RH_SUSPENDING: + case UHCI_RH_SUSPENDED: + /* if port change, ask to be resumed */ + if (status) + usb_hcd_resume_root_hub(hcd); + break; + + case UHCI_RH_AUTO_STOPPED: + /* if port change, auto start */ + if (status) + wakeup_rh(uhci); + break; + + case UHCI_RH_RUNNING: + /* are any devices attached? */ + if (!any_ports_active(uhci)) { + uhci->rh_state = UHCI_RH_RUNNING_NODEVS; + uhci->auto_stop_time = jiffies + HZ; + } + break; + + case UHCI_RH_RUNNING_NODEVS: + /* auto-stop if nothing connected for 1 second */ + if (any_ports_active(uhci)) + uhci->rh_state = UHCI_RH_RUNNING; + else if (time_after_eq(jiffies, uhci->auto_stop_time)) + suspend_rh(uhci, UHCI_RH_AUTO_STOPPED); + break; + + default: + break; + } + +done: + spin_unlock_irqrestore(&uhci->lock, flags); + return status; +} + /* size of returned buffer is part of USB spec */ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index f5c75885f7be..77f264851e98 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -32,6 +32,8 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci); */ static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) { + if (uhci->is_stopped) + mod_timer(&uhci->stall_timer, jiffies); uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); } @@ -1497,6 +1499,7 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) rescan: uhci->need_rescan = 0; + uhci_clear_next_interrupt(uhci); uhci_get_current_frame_number(uhci); if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) -- cgit v1.2.3 From c074b416b94c0aa4a371f24bf6cc13d8cf1fab59 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 22 Apr 2005 14:39:12 -0400 Subject: [PATCH] USB UHCI: improved reset handling This patch improves the strategy uhci-hcd uses for performing controller resets and checking whether they are needed. The HCRESET command doesn't affect the Suspend, Resume, or Reset bits in the port status & control registers, so the driver must clear them by itself. This means the code to figure out how many ports there are has to be moved to an earlier spot in the driver. The R/WC bits in the USBLEGSUP register can be set by the hardware even in the absence of BIOS meddling with legacy support features. Hence it's not a good idea to check them while trying to determine whether the BIOS has altered the controller's state. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 69 ++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 29 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 25a718eb1d0f..cec070fa8c83 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -112,6 +112,8 @@ static inline void restart_timer(struct uhci_hcd *uhci) */ static void reset_hc(struct uhci_hcd *uhci) { + int port; + /* Turn off PIRQ enable and SMI enable. (This also turns off the * BIOS's USB Legacy Support.) Turn off all the R/WC bits too. */ @@ -135,6 +137,13 @@ static void reset_hc(struct uhci_hcd *uhci) outw(0, uhci->io_addr + USBINTR); outw(0, uhci->io_addr + USBCMD); + /* HCRESET doesn't affect the Suspend, Reset, and Resume Detect + * bits in the port status and control registers. + * We have to clear them by hand. + */ + for (port = 0; port < uhci->rh_numports; ++port) + outw(0, uhci->io_addr + USBPORTSC1 + (port * 2)); + uhci->port_c_suspend = uhci->suspended_ports = uhci->resuming_ports = 0; uhci->rh_state = UHCI_RH_RESET; @@ -166,14 +175,14 @@ static void check_and_reset_hc(struct uhci_hcd *uhci) * When restarting a suspended controller, we expect all the * settings to be the same as we left them: * - * PIRQ and SMI disabled, no R/WC bits set in USBLEGSUP; + * PIRQ and SMI disabled, no R/W bits set in USBLEGSUP; * Controller is stopped and configured with EGSM set; * No interrupts enabled except possibly Resume Detect. * * If any of these conditions are violated we do a complete reset. */ pci_read_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, &legsup); - if (legsup & ~USBLEGSUP_RO) { + if (legsup & ~(USBLEGSUP_RO | USBLEGSUP_RWC)) { dev_dbg(uhci_dev(uhci), "%s: legsup = 0x%04x\n", __FUNCTION__, legsup); goto reset_needed; @@ -478,9 +487,37 @@ static void release_uhci(struct uhci_hcd *uhci) static int uhci_reset(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); + unsigned io_size = (unsigned) hcd->rsrc_len; + int port; uhci->io_addr = (unsigned long) hcd->rsrc_start; + /* The UHCI spec says devices must have 2 ports, and goes on to say + * they may have more but gives no way to determine how many there + * are. However, according to the UHCI spec, Bit 7 of the port + * status and control register is always set to 1. So we try to + * use this to our advantage. + */ + for (port = 0; port < (io_size - USBPORTSC1) / 2; port++) { + unsigned int portstatus; + + portstatus = inw(uhci->io_addr + USBPORTSC1 + (port * 2)); + if (!(portstatus & 0x0080)) + break; + } + if (debug) + dev_info(uhci_dev(uhci), "detected %d ports\n", port); + + /* Anything less than 2 or greater than 7 is weird, + * so we'll ignore it. + */ + if (port < 2 || port > UHCI_RH_MAXCHILD) { + dev_info(uhci_dev(uhci), "port count misdetected? " + "forcing to 2 ports\n"); + port = 2; + } + uhci->rh_numports = port; + /* Kick BIOS off this hardware and reset if the controller * isn't already safely quiescent. */ @@ -508,13 +545,11 @@ static int uhci_start(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); int retval = -EBUSY; - int i, port; - unsigned io_size; + int i; dma_addr_t dma_handle; struct usb_device *udev; struct dentry *dentry; - io_size = (unsigned) hcd->rsrc_len; hcd->uses_new_polling = 1; if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM)) hcd->can_wakeup = 1; /* Assume it supports PME# */ @@ -578,30 +613,6 @@ static int uhci_start(struct usb_hcd *hcd) /* Initialize the root hub */ - /* UHCI specs says devices must have 2 ports, but goes on to say */ - /* they may have more but give no way to determine how many they */ - /* have. However, according to the UHCI spec, Bit 7 is always set */ - /* to 1. So we try to use this to our advantage */ - for (port = 0; port < (io_size - 0x10) / 2; port++) { - unsigned int portstatus; - - portstatus = inw(uhci->io_addr + 0x10 + (port * 2)); - if (!(portstatus & 0x0080)) - break; - } - if (debug) - dev_info(uhci_dev(uhci), "detected %d ports\n", port); - - /* This is experimental so anything less than 2 or greater than 8 is */ - /* something weird and we'll ignore it */ - if (port < 2 || port > UHCI_RH_MAXCHILD) { - dev_info(uhci_dev(uhci), "port count misdetected? " - "forcing to 2 ports\n"); - port = 2; - } - - uhci->rh_numports = port; - udev = usb_alloc_dev(NULL, &hcd->self, 0); if (!udev) { dev_err(uhci_dev(uhci), "unable to allocate root hub\n"); -- cgit v1.2.3 From 02597d2deec2a3de0e2b52c1f83904b65626a0d5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 28 Apr 2005 14:51:27 -0400 Subject: [PATCH] USB UHCI: Add shutdown method After all the discussion you might not be interested in this still, but nevertheless here it is. This patch adds a shutdown method to the uhci-hcd driver. Its prerequisite is the patch you wrote adding shutdown support for PCI. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index cec070fa8c83..53ba8a56592e 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -154,6 +154,7 @@ static void reset_hc(struct uhci_hcd *uhci) /* * Last rites for a defunct/nonfunctional controller + * or one we don't want to use any more. */ static void hc_died(struct uhci_hcd *uhci) { @@ -525,6 +526,20 @@ static int uhci_reset(struct usb_hcd *hcd) return 0; } +/* Make sure the controller is quiescent and that we're not using it + * any more. This is mainly for the benefit of programs which, like kexec, + * expect the hardware to be idle: not doing DMA or generating IRQs. + * + * This routine may be called in a damaged or failing kernel. Hence we + * do not acquire the spinlock before shutting down the controller. + */ +static void uhci_shutdown(struct pci_dev *pdev) +{ + struct usb_hcd *hcd = (struct usb_hcd *) pci_get_drvdata(pdev); + + hc_died(hcd_to_uhci(hcd)); +} + /* * Allocate a frame list, and then setup the skeleton * @@ -939,6 +954,7 @@ static struct pci_driver uhci_pci_driver = { .probe = usb_hcd_pci_probe, .remove = usb_hcd_pci_remove, + .shutdown = uhci_shutdown, #ifdef CONFIG_PM .suspend = usb_hcd_pci_suspend, -- cgit v1.2.3 From d5926ae7a827bdd06b588ffbc56fd4525cd9214a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 21 Apr 2005 15:56:37 -0400 Subject: [PATCH] usbcore support for root-hub IRQ instead of polling This is a revised version of an earlier patch to add support to usbcore for driving root hubs by interrupts rather than polling. There's a temporary flag added to struct usb_hcd, marking devices whose drivers are aware of the new mechanism. By default that flag doesn't get set so drivers will continue to see the same polling behavior as before. This way we can convert the HCDs one by one to use interrupt-based event reporting, and the temporary flag can be removed when they're all done. Also included is a small change to the hcd_disable_endpoint routine. Although endpoints normally shouldn't be disabled while a controller is suspended, it's legal to do so when the controller's driver is being rmmod'ed. Lastly the patch adds a new callback, .hub_irq_enable, for use by HCDs where the root hub's port-change interrupts are level-triggered rather than edge-triggered. The callback is invoked each time khubd has finished processing a root hub, to let the HCD know that the interrupt can safely be re-enabled. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 207 +++++++++++++++++++++++++++++-------------------- drivers/usb/core/hcd.h | 15 +++- drivers/usb/core/hub.c | 5 ++ 3 files changed, 140 insertions(+), 87 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 0da23732e807..1180c157b717 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -519,119 +519,120 @@ error: /*-------------------------------------------------------------------------*/ /* - * Root Hub interrupt transfers are synthesized with a timer. - * Completions are called in_interrupt() but not in_irq(). + * Root Hub interrupt transfers are polled using a timer if the + * driver requests it; otherwise the driver is responsible for + * calling usb_hcd_poll_rh_status() when an event occurs. * - * Note: some root hubs (including common UHCI based designs) can't - * correctly issue port change IRQs. They're the ones that _need_ a - * timer; most other root hubs don't. Some systems could save a - * lot of battery power by eliminating these root hub timer IRQs. + * Completions are called in_interrupt(), but they may or may not + * be in_irq(). */ +void usb_hcd_poll_rh_status(struct usb_hcd *hcd) +{ + struct urb *urb; + int length; + unsigned long flags; + char buffer[4]; /* Any root hubs with > 31 ports? */ -static void rh_report_status (unsigned long ptr); + if (!hcd->uses_new_polling && !hcd->status_urb) + return; -static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) -{ - int len = 1 + (urb->dev->maxchild / 8); + length = hcd->driver->hub_status_data(hcd, buffer); + if (length > 0) { - /* rh_timer protected by hcd_data_lock */ - if (hcd->rh_timer.data || urb->transfer_buffer_length < len) { - dev_dbg (hcd->self.controller, - "not queuing rh status urb, stat %d\n", - urb->status); - return -EINVAL; + /* try to complete the status urb */ + local_irq_save (flags); + spin_lock(&hcd_root_hub_lock); + urb = hcd->status_urb; + if (urb) { + spin_lock(&urb->lock); + if (urb->status == -EINPROGRESS) { + hcd->poll_pending = 0; + hcd->status_urb = NULL; + urb->status = 0; + urb->hcpriv = NULL; + urb->actual_length = length; + memcpy(urb->transfer_buffer, buffer, length); + } else /* urb has been unlinked */ + length = 0; + spin_unlock(&urb->lock); + } else + length = 0; + spin_unlock(&hcd_root_hub_lock); + + /* local irqs are always blocked in completions */ + if (length > 0) + usb_hcd_giveback_urb (hcd, urb, NULL); + else + hcd->poll_pending = 1; + local_irq_restore (flags); } - init_timer (&hcd->rh_timer); - hcd->rh_timer.function = rh_report_status; - hcd->rh_timer.data = (unsigned long) urb; - /* USB 2.0 spec says 256msec; this is close enough */ - hcd->rh_timer.expires = jiffies + HZ/4; - add_timer (&hcd->rh_timer); - urb->hcpriv = hcd; /* nonzero to indicate it's queued */ - return 0; + /* The USB 2.0 spec says 256 ms. This is close enough and won't + * exceed that limit if HZ is 100. */ + if (hcd->uses_new_polling ? hcd->poll_rh : + (length == 0 && hcd->status_urb != NULL)) + mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250)); } +EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status); /* timer callback */ +static void rh_timer_func (unsigned long _hcd) +{ + usb_hcd_poll_rh_status((struct usb_hcd *) _hcd); +} + +/*-------------------------------------------------------------------------*/ -static void rh_report_status (unsigned long ptr) +static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) { - struct urb *urb; - struct usb_hcd *hcd; - int length = 0; + int retval; unsigned long flags; + int len = 1 + (urb->dev->maxchild / 8); - urb = (struct urb *) ptr; - local_irq_save (flags); - spin_lock (&urb->lock); + spin_lock_irqsave (&hcd_root_hub_lock, flags); + if (urb->status != -EINPROGRESS) /* already unlinked */ + retval = urb->status; + else if (hcd->status_urb || urb->transfer_buffer_length < len) { + dev_dbg (hcd->self.controller, "not queuing rh status urb\n"); + retval = -EINVAL; + } else { + hcd->status_urb = urb; + urb->hcpriv = hcd; /* indicate it's queued */ - /* do nothing if the urb's been unlinked */ - if (!urb->dev - || urb->status != -EINPROGRESS - || (hcd = urb->dev->bus->hcpriv) == NULL) { - spin_unlock (&urb->lock); - local_irq_restore (flags); - return; - } + if (!hcd->uses_new_polling) + mod_timer (&hcd->rh_timer, jiffies + + msecs_to_jiffies(250)); - /* complete the status urb, or retrigger the timer */ - spin_lock (&hcd_data_lock); - if (urb->dev->state == USB_STATE_CONFIGURED) { - length = hcd->driver->hub_status_data ( - hcd, urb->transfer_buffer); - if (length > 0) { - hcd->rh_timer.data = 0; - urb->actual_length = length; - urb->status = 0; - urb->hcpriv = NULL; - } else - mod_timer (&hcd->rh_timer, jiffies + HZ/4); + /* If a status change has already occurred, report it ASAP */ + else if (hcd->poll_pending) + mod_timer (&hcd->rh_timer, jiffies); + retval = 0; } - spin_unlock (&hcd_data_lock); - spin_unlock (&urb->lock); - - /* local irqs are always blocked in completions */ - if (length > 0) - usb_hcd_giveback_urb (hcd, urb, NULL); - local_irq_restore (flags); + spin_unlock_irqrestore (&hcd_root_hub_lock, flags); + return retval; } -/*-------------------------------------------------------------------------*/ - static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) { - if (usb_pipeint (urb->pipe)) { - int retval; - unsigned long flags; - - spin_lock_irqsave (&hcd_data_lock, flags); - retval = rh_status_urb (hcd, urb); - spin_unlock_irqrestore (&hcd_data_lock, flags); - return retval; - } + if (usb_pipeint (urb->pipe)) + return rh_queue_status (hcd, urb); if (usb_pipecontrol (urb->pipe)) return rh_call_control (hcd, urb); - else - return -EINVAL; + return -EINVAL; } /*-------------------------------------------------------------------------*/ +/* Asynchronous unlinks of root-hub control URBs are legal, but they + * don't do anything. Status URB unlinks must be made in process context + * with interrupts enabled. + */ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; - - /* note: always a synchronous unlink */ - if ((unsigned long) urb == hcd->rh_timer.data) { - del_timer_sync (&hcd->rh_timer); - hcd->rh_timer.data = 0; - - local_irq_save (flags); - urb->hcpriv = NULL; - usb_hcd_giveback_urb (hcd, urb, NULL); - local_irq_restore (flags); + if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */ + if (in_interrupt()) + return 0; /* nothing to do */ - } else if (usb_pipeendpoint(urb->pipe) == 0) { spin_lock_irq(&urb->lock); /* from usb_kill_urb */ ++urb->reject; spin_unlock_irq(&urb->lock); @@ -642,8 +643,22 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) spin_lock_irq(&urb->lock); --urb->reject; spin_unlock_irq(&urb->lock); - } else - return -EINVAL; + + } else { /* Status URB */ + if (!hcd->uses_new_polling) + del_timer_sync (&hcd->rh_timer); + local_irq_disable (); + spin_lock (&hcd_root_hub_lock); + if (urb == hcd->status_urb) { + hcd->status_urb = NULL; + urb->hcpriv = NULL; + } else + urb = NULL; /* wasn't fully queued */ + spin_unlock (&hcd_root_hub_lock); + if (urb) + usb_hcd_giveback_urb (hcd, urb, NULL); + local_irq_enable (); + } return 0; } @@ -885,6 +900,16 @@ int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd) } EXPORT_SYMBOL_GPL(usb_hcd_register_root_hub); +void usb_enable_root_hub_irq (struct usb_bus *bus) +{ + struct usb_hcd *hcd; + + hcd = container_of (bus, struct usb_hcd, self); + if (hcd->driver->hub_irq_enable && !hcd->poll_rh && + hcd->state != HC_STATE_HALT) + hcd->driver->hub_irq_enable (hcd); +} + /*-------------------------------------------------------------------------*/ @@ -1348,7 +1373,8 @@ hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep) hcd = udev->bus->hcpriv; - WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT); + WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT && + udev->state != USB_STATE_NOTATTACHED); local_irq_disable (); @@ -1612,6 +1638,8 @@ void usb_hc_died (struct usb_hcd *hcd) spin_lock_irqsave (&hcd_root_hub_lock, flags); if (hcd->rh_registered) { + hcd->poll_rh = 0; + del_timer(&hcd->rh_timer); /* make khubd clean up old urbs and devices */ usb_set_device_state (hcd->self.root_hub, @@ -1665,6 +1693,8 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, hcd->self.bus_name = bus_name; init_timer(&hcd->rh_timer); + hcd->rh_timer.function = rh_timer_func; + hcd->rh_timer.data = (unsigned long) hcd; hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc : @@ -1748,6 +1778,8 @@ int usb_add_hcd(struct usb_hcd *hcd, goto err3; } + if (hcd->uses_new_polling && hcd->poll_rh) + usb_hcd_poll_rh_status(hcd); return retval; err3: @@ -1782,6 +1814,9 @@ void usb_remove_hcd(struct usb_hcd *hcd) spin_unlock_irq (&hcd_root_hub_lock); usb_disconnect(&hcd->self.root_hub); + hcd->poll_rh = 0; + del_timer_sync(&hcd->rh_timer); + hcd->driver->stop(hcd); hcd->state = HC_STATE_HALT; diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 325a51656c3f..ac5752778e39 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -65,7 +65,8 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ const char *product_desc; /* product/vendor string */ char irq_descr[24]; /* driver + bus # */ - struct timer_list rh_timer; /* drives root hub */ + struct timer_list rh_timer; /* drives root-hub polling */ + struct urb *status_urb; /* the current status urb */ /* * hardware info/state @@ -76,6 +77,12 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ unsigned remote_wakeup:1;/* sw should use wakeup? */ unsigned rh_registered:1;/* is root hub registered? */ + /* The next flag is a stopgap, to be removed when all the HCDs + * support the new root-hub polling mechanism. */ + unsigned uses_new_polling:1; + unsigned poll_rh:1; /* poll for rh status? */ + unsigned poll_pending:1; /* status has changed? */ + int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ u64 rsrc_start; /* memory/io resource start */ @@ -207,6 +214,8 @@ struct hc_driver { int (*hub_suspend)(struct usb_hcd *); int (*hub_resume)(struct usb_hcd *); int (*start_port_reset)(struct usb_hcd *, unsigned port_num); + void (*hub_irq_enable)(struct usb_hcd *); + /* Needed only if port-change IRQs are level-triggered */ }; extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs); @@ -243,7 +252,9 @@ void hcd_buffer_free (struct usb_bus *bus, size_t size, /* generic bus glue, needed for host controllers that don't use PCI */ extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r); + extern void usb_hc_died (struct usb_hcd *hcd); +extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); /* -------------------------------------------------------------------------- */ @@ -360,6 +371,8 @@ extern wait_queue_head_t usb_kill_urb_queue; extern struct usb_bus *usb_bus_get (struct usb_bus *bus); extern void usb_bus_put (struct usb_bus *bus); +extern void usb_enable_root_hub_irq (struct usb_bus *bus); + extern int usb_find_interface_driver (struct usb_device *dev, struct usb_interface *interface); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a8d879a85d04..6d1a330d577b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2787,6 +2787,11 @@ static void hub_events(void) hub->activating = 0; + /* If this is a root hub, tell the HCD it's okay to + * re-enable port-change interrupts now. */ + if (!hdev->parent) + usb_enable_root_hub_irq(hdev->bus); + loop: usb_unlock_device(hdev); usb_put_intf(intf); -- cgit v1.2.3 From 884b600f63dc7c646f415a5d8f356df1f66ff6f2 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 21 Apr 2005 21:28:02 +0200 Subject: [PATCH] USB: fix acm trouble with terminals This patch fixes lost LF when ACM device is used with getty/login/bash, in case of a modem which takes calls. Signed-off-by: Pete Zaitcev Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 209 +++++++++++++++++++++++++++++++++++++------- drivers/usb/class/cdc-acm.h | 25 +++++- 2 files changed, 197 insertions(+), 37 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 6d1f9b6aecff..69e859e0f51d 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -105,6 +105,111 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int #define acm_send_break(acm, ms) \ acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0) +/* + * Write buffer management. + * All of these assume proper locks taken by the caller. + */ + +static int acm_wb_alloc(struct acm *acm) +{ + int i, wbn; + struct acm_wb *wb; + + wbn = acm->write_current; + i = 0; + for (;;) { + wb = &acm->wb[wbn]; + if (!wb->use) { + wb->use = 1; + return wbn; + } + wbn = (wbn + 1) % ACM_NWB; + if (++i >= ACM_NWB) + return -1; + } +} + +static void acm_wb_free(struct acm *acm, int wbn) +{ + acm->wb[wbn].use = 0; +} + +static int acm_wb_is_avail(struct acm *acm) +{ + int i, n; + + n = 0; + for (i = 0; i < ACM_NWB; i++) { + if (!acm->wb[i].use) + n++; + } + return n; +} + +static inline int acm_wb_is_used(struct acm *acm, int wbn) +{ + return acm->wb[wbn].use; +} + +/* + * Finish write. + */ +static void acm_write_done(struct acm *acm) +{ + unsigned long flags; + int wbn; + + spin_lock_irqsave(&acm->write_lock, flags); + acm->write_ready = 1; + wbn = acm->write_current; + acm_wb_free(acm, wbn); + acm->write_current = (wbn + 1) % ACM_NWB; + spin_unlock_irqrestore(&acm->write_lock, flags); +} + +/* + * Poke write. + */ +static int acm_write_start(struct acm *acm) +{ + unsigned long flags; + int wbn; + struct acm_wb *wb; + int rc; + + spin_lock_irqsave(&acm->write_lock, flags); + if (!acm->dev) { + spin_unlock_irqrestore(&acm->write_lock, flags); + return -ENODEV; + } + + if (!acm->write_ready) { + spin_unlock_irqrestore(&acm->write_lock, flags); + return 0; /* A white lie */ + } + + wbn = acm->write_current; + if (!acm_wb_is_used(acm, wbn)) { + spin_unlock_irqrestore(&acm->write_lock, flags); + return 0; + } + wb = &acm->wb[wbn]; + + acm->write_ready = 0; + spin_unlock_irqrestore(&acm->write_lock, flags); + + acm->writeurb->transfer_buffer = wb->buf; + acm->writeurb->transfer_dma = wb->dmah; + acm->writeurb->transfer_buffer_length = wb->len; + acm->writeurb->dev = acm->dev; + + if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) { + dbg("usb_submit_urb(write bulk) failed: %d", rc); + acm_write_done(acm); + } + return rc; +} + /* * Interrupt handlers for various ACM device responses */ @@ -237,17 +342,13 @@ static void acm_rx_tasklet(unsigned long _acm) static void acm_write_bulk(struct urb *urb, struct pt_regs *regs) { struct acm *acm = (struct acm *)urb->context; - dbg("Entering acm_write_bulk with status %d\n", urb->status); - - if (!ACM_READY(acm)) - goto out; - if (urb->status) - dbg("nonzero write bulk status received: %d", urb->status); + dbg("Entering acm_write_bulk with status %d\n", urb->status); - schedule_work(&acm->work); -out: - acm->ready_for_write = 1; + acm_write_done(acm); + acm_write_start(acm); + if (ACM_READY(acm)) + schedule_work(&acm->work); } static void acm_softint(void *private) @@ -351,32 +452,33 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c { struct acm *acm = tty->driver_data; int stat; + unsigned long flags; + int wbn; + struct acm_wb *wb; + dbg("Entering acm_tty_write to write %d bytes,\n", count); if (!ACM_READY(acm)) return -EINVAL; - if (!acm->ready_for_write) - return 0; if (!count) return 0; - count = (count > acm->writesize) ? acm->writesize : count; + spin_lock_irqsave(&acm->write_lock, flags); + if ((wbn = acm_wb_alloc(acm)) < 0) { + spin_unlock_irqrestore(&acm->write_lock, flags); + acm_write_start(acm); + return 0; + } + wb = &acm->wb[wbn]; + count = (count > acm->writesize) ? acm->writesize : count; dbg("Get %d bytes...", count); - memcpy(acm->write_buffer, buf, count); - dbg(" Successfully copied.\n"); + memcpy(wb->buf, buf, count); + wb->len = count; + spin_unlock_irqrestore(&acm->write_lock, flags); - acm->writeurb->transfer_buffer_length = count; - acm->writeurb->dev = acm->dev; - - acm->ready_for_write = 0; - stat = usb_submit_urb(acm->writeurb, GFP_ATOMIC); - if (stat < 0) { - dbg("usb_submit_urb(write bulk) failed"); - acm->ready_for_write = 1; + if ((stat = acm_write_start(acm)) < 0) return stat; - } - return count; } @@ -385,7 +487,11 @@ static int acm_tty_write_room(struct tty_struct *tty) struct acm *acm = tty->driver_data; if (!ACM_READY(acm)) return -EINVAL; - return !acm->ready_for_write ? 0 : acm->writesize; + /* + * Do not let the line discipline to know that we have a reserve, + * or it might get too enthusiastic. + */ + return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0; } static int acm_tty_chars_in_buffer(struct tty_struct *tty) @@ -393,7 +499,10 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty) struct acm *acm = tty->driver_data; if (!ACM_READY(acm)) return -EINVAL; - return !acm->ready_for_write ? acm->writeurb->transfer_buffer_length : 0; + /* + * This is inaccurate (overcounts), but it works. + */ + return (ACM_NWB - acm_wb_is_avail(acm)) * acm->writesize; } static void acm_tty_throttle(struct tty_struct *tty) @@ -526,6 +635,39 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_ * USB probe and disconnect routines. */ +/* Little helper: write buffers free */ +static void acm_write_buffers_free(struct acm *acm) +{ + int i; + struct acm_wb *wb; + + for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) { + usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah); + } +} + +/* Little helper: write buffers allocate */ +static int acm_write_buffers_alloc(struct acm *acm) +{ + int i; + struct acm_wb *wb; + + for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) { + wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL, + &wb->dmah); + if (!wb->buf) { + while (i != 0) { + --i; + --wb; + usb_buffer_free(acm->dev, acm->writesize, + wb->buf, wb->dmah); + } + return -ENOMEM; + } + } + return 0; +} + static int acm_probe (struct usb_interface *intf, const struct usb_device_id *id) { @@ -700,7 +842,8 @@ skip_normal_probe: acm->bh.data = (unsigned long) acm; INIT_WORK(&acm->work, acm_softint, acm); spin_lock_init(&acm->throttle_lock); - acm->ready_for_write = 1; + spin_lock_init(&acm->write_lock); + acm->write_ready = 1; buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); if (!buf) { @@ -716,12 +859,10 @@ skip_normal_probe: } acm->read_buffer = buf; - buf = usb_buffer_alloc(usb_dev, acm->writesize, GFP_KERNEL, &acm->write_dma); - if (!buf) { + if (acm_write_buffers_alloc(acm) < 0) { dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n"); goto alloc_fail4; } - acm->write_buffer = buf; acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); if (!acm->ctrlurb) { @@ -750,9 +891,9 @@ skip_normal_probe: acm->readurb->transfer_dma = acm->read_dma; usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), - acm->write_buffer, acm->writesize, acm_write_bulk, acm); + NULL, acm->writesize, acm_write_bulk, acm); acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; - acm->writeurb->transfer_dma = acm->write_dma; + /* acm->writeurb->transfer_dma = 0; */ dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); @@ -775,7 +916,7 @@ alloc_fail7: alloc_fail6: usb_free_urb(acm->ctrlurb); alloc_fail5: - usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma); + acm_write_buffers_free(acm); alloc_fail4: usb_buffer_free(usb_dev, readsize, acm->read_buffer, acm->read_dma); alloc_fail3: @@ -806,7 +947,7 @@ static void acm_disconnect(struct usb_interface *intf) flush_scheduled_work(); /* wait for acm_softint */ - usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma); + acm_write_buffers_free(acm); usb_buffer_free(usb_dev, acm->readsize, acm->read_buffer, acm->read_dma); usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 9009114e311b..963a5dfd2096 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -51,14 +51,34 @@ * Internal driver structures. */ +/* + * The only reason to have several buffers is to accomodate assumptions + * in line disciplines. They ask for empty space amount, receive our URB size, + * and proceed to issue several 1-character writes, assuming they will fit. + * The very first write takes a complete URB. Fortunately, this only happens + * when processing onlcr, so we only need 2 buffers. + */ +#define ACM_NWB 2 +struct acm_wb { + unsigned char *buf; + dma_addr_t dmah; + int len; + int use; +}; + struct acm { struct usb_device *dev; /* the corresponding usb device */ struct usb_interface *control; /* control interface */ struct usb_interface *data; /* data interface */ struct tty_struct *tty; /* the corresponding tty */ 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 */ + u8 *ctrl_buffer, *read_buffer; /* buffers of urbs */ + dma_addr_t ctrl_dma, read_dma; /* dma handles of buffers */ + struct acm_wb wb[ACM_NWB]; + int write_current; /* current write buffer */ + int write_used; /* number of non-empty write buffers */ + int write_ready; /* write urb is not running */ + spinlock_t write_lock; 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 */ @@ -71,7 +91,6 @@ struct acm { unsigned int minor; /* acm minor number */ unsigned char throttle; /* throttled by tty layer */ unsigned char clocal; /* termios CLOCAL */ - unsigned char ready_for_write; /* write urb can be used */ unsigned char resubmit_to_unthrottle; /* throtteling has disabled the read urb */ unsigned int ctrl_caps; /* control capabilities from the class specific header */ }; -- cgit v1.2.3 From ff7c79e4f37821235b51fb8e19088c08938cc8fc Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 22 Apr 2005 13:17:00 -0700 Subject: [PATCH] USB: usbtest updates Updates to "usbtest" driver: * Improve some diagnostics. One path that never generated diagnostics before should now generate two ... unless you hit a GCC bug that all my compilers seem to have, go figure. * Add suspend/resume support, so this behaves when the Linux host being used for testing suspends. * Don't test the "zero byte ep0 read" case unless real-world relevance for the testing is is irrelevant. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usbtest.c | 60 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 3104f28f6aa8..cda7249a90b2 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -461,7 +461,7 @@ static int perform_sglist ( static unsigned realworld = 1; module_param (realworld, uint, 0); -MODULE_PARM_DESC (realworld, "clear to demand stricter ch9 compliance"); +MODULE_PARM_DESC (realworld, "clear to demand stricter spec compliance"); static int get_altsetting (struct usbtest_dev *dev) { @@ -604,9 +604,8 @@ static int ch9_postconfig (struct usbtest_dev *dev) USB_DIR_IN | USB_RECIP_DEVICE, 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, - expected); + dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n", + retval, dev->buf[0], expected); return (retval < 0) ? retval : -EDOM; } } @@ -1243,7 +1242,7 @@ static int ctrl_out (struct usbtest_dev *dev, char *what = "?"; struct usb_device *udev; - if (length > 0xffff || vary >= length) + if (length < 1 || length > 0xffff || vary >= length) return -EINVAL; buf = kmalloc(length, SLAB_KERNEL); @@ -1266,6 +1265,11 @@ static int ctrl_out (struct usbtest_dev *dev, 0, 0, buf, len, USB_CTRL_SET_TIMEOUT); if (retval != len) { what = "write"; + if (retval >= 0) { + INFO(dev, "ctrl_out, wlen %d (expected %d)\n", + retval, len); + retval = -EBADMSG; + } break; } @@ -1275,6 +1279,11 @@ static int ctrl_out (struct usbtest_dev *dev, 0, 0, buf, len, USB_CTRL_GET_TIMEOUT); if (retval != len) { what = "read"; + if (retval >= 0) { + INFO(dev, "ctrl_out, rlen %d (expected %d)\n", + retval, len); + retval = -EBADMSG; + } break; } @@ -1293,8 +1302,13 @@ static int ctrl_out (struct usbtest_dev *dev, } len += vary; + + /* [real world] the "zero bytes IN" case isn't really used. + * hardware can easily trip up in this wierd case, since its + * status stage is IN, not OUT like other ep0in transfers. + */ if (len > length) - len = 0; + len = realworld ? 1 : 0; } if (retval < 0) @@ -1519,6 +1533,11 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) if (down_interruptible (&dev->sem)) return -ERESTARTSYS; + if (intf->dev.power.power_state != PMSG_ON) { + up (&dev->sem); + return -EHOSTUNREACH; + } + /* some devices, like ez-usb default devices, need a non-default * altsetting to have any active endpoints. some tests change * altsettings; force a default so most tests don't need to check. @@ -1762,8 +1781,10 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) case 14: if (!dev->info->ctrl_out) break; - dev_dbg (&intf->dev, "TEST 14: %d ep0out, 0..%d vary %d\n", - param->iterations, param->length, param->vary); + dev_dbg (&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n", + param->iterations, + realworld ? 1 : 0, param->length, + param->vary); retval = ctrl_out (dev, param->iterations, param->length, param->vary); break; @@ -1927,6 +1948,27 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) return 0; } +static int usbtest_suspend (struct usb_interface *intf, pm_message_t message) +{ + struct usbtest_dev *dev = usb_get_intfdata (intf); + + down (&dev->sem); + intf->dev.power.power_state = PMSG_SUSPEND; + up (&dev->sem); + return 0; +} + +static int usbtest_resume (struct usb_interface *intf) +{ + struct usbtest_dev *dev = usb_get_intfdata (intf); + + down (&dev->sem); + intf->dev.power.power_state = PMSG_ON; + up (&dev->sem); + return 0; +} + + static void usbtest_disconnect (struct usb_interface *intf) { struct usbtest_dev *dev = usb_get_intfdata (intf); @@ -2115,6 +2157,8 @@ static struct usb_driver usbtest_driver = { .probe = usbtest_probe, .ioctl = usbtest_ioctl, .disconnect = usbtest_disconnect, + .suspend = usbtest_suspend, + .resume = usbtest_resume, }; /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From f4df0e334a9fc731689e8ba4f42a0d72a7491348 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 23 Apr 2005 12:49:16 -0700 Subject: [PATCH] USB: add reboot notifier to ohci Adds a reboot notifier to OHCI, mostly to benefit kexec; plus minor #include tweaks. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 28 ++++++++++++++++++++++++---- drivers/usb/host/ohci-mem.c | 1 + drivers/usb/host/ohci.h | 1 + 3 files changed, 26 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 1e27f10c1592..32120042ab65 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -95,12 +95,11 @@ #include #include #include -#include /* for in_interrupt () */ #include #include -#include "../core/hcd.h" #include -#include /* needed by ohci-mem.c when no PCI */ +#include +#include #include #include @@ -108,8 +107,9 @@ #include #include +#include "../core/hcd.h" -#define DRIVER_VERSION "2004 Nov 08" +#define DRIVER_VERSION "2005 April 22" #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" @@ -141,6 +141,7 @@ static const char hcd_name [] = "ohci_hcd"; static void ohci_dump (struct ohci_hcd *ohci, int verbose); static int ohci_init (struct ohci_hcd *ohci); static void ohci_stop (struct usb_hcd *hcd); +static int ohci_reboot (struct notifier_block *, unsigned long , void *); #include "ohci-hub.c" #include "ohci-dbg.c" @@ -420,6 +421,23 @@ static void ohci_usb_reset (struct ohci_hcd *ohci) ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); } +/* reboot notifier forcibly disables IRQs and DMA, helping kexec and + * other cases where the next software may expect clean state from the + * "firmware". this is bus-neutral, unlike shutdown() methods. + */ +static int +ohci_reboot (struct notifier_block *block, unsigned long code, void *null) +{ + struct ohci_hcd *ohci; + + ohci = container_of (block, struct ohci_hcd, reboot_notifier); + ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + ohci_usb_reset (ohci); + /* flush the writes */ + (void) ohci_readl (ohci, &ohci->regs->control); + return 0; +} + /*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*/ @@ -684,6 +702,7 @@ retry: if (ohci->power_budget) hub_set_power_budget(udev, ohci->power_budget); + register_reboot_notifier (&ohci->reboot_notifier); create_debug_files (ohci); return 0; } @@ -781,6 +800,7 @@ static void ohci_stop (struct usb_hcd *hcd) ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); remove_debug_files (ohci); + unregister_reboot_notifier (&ohci->reboot_notifier); ohci_mem_cleanup (ohci); if (ohci->hcca) { dma_free_coherent (hcd->self.controller, diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index e55682b4919d..23735a36af00 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -29,6 +29,7 @@ static void ohci_hcd_init (struct ohci_hcd *ohci) spin_lock_init (&ohci->lock); INIT_LIST_HEAD (&ohci->pending); INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci)); + ohci->reboot_notifier.notifier_call = ohci_reboot; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 22e1ac138ac0..3dbc7c0eed43 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -390,6 +390,7 @@ struct ohci_hcd { u32 fminterval; /* saved register */ struct work_struct rh_resume; + struct notifier_block reboot_notifier; unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ -- cgit v1.2.3 From 507ca9bc0476662f3463888d583864834eab1e11 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 23 Apr 2005 12:49:16 -0700 Subject: [PATCH] USB: add ability for usb-serial drivers to determine if their write urb is currently being used. This removes a lot of racy and buggy code by trying to check the status of the urb. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cyberjack.c | 19 ++++++++++--------- drivers/usb/serial/generic.c | 24 ++++++++++++++++-------- drivers/usb/serial/ipaq.c | 5 ----- drivers/usb/serial/ipw.c | 14 ++++++++++---- drivers/usb/serial/ir-usb.c | 16 +++++++++++----- drivers/usb/serial/keyspan_pda.c | 19 +++++++++++++------ drivers/usb/serial/omninet.c | 17 ++++++++++++----- drivers/usb/serial/safe_serial.c | 13 +++++++++---- drivers/usb/serial/usb-serial.c | 1 + drivers/usb/serial/usb-serial.h | 3 +++ 10 files changed, 85 insertions(+), 46 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 46a204cd40e1..b5b431067b08 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -213,10 +213,14 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b return (0); } - if (port->write_urb->status == -EINPROGRESS) { + spin_lock(&port->lock); + if (port->write_urb_busy) { + spin_unlock(&port->lock); dbg("%s - already writing", __FUNCTION__); - return (0); + return 0; } + port->write_urb_busy = 1; + spin_unlock(&port->lock); spin_lock_irqsave(&priv->lock, flags); @@ -224,6 +228,7 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b /* To much data for buffer. Reset buffer. */ priv->wrfilled=0; spin_unlock_irqrestore(&priv->lock, flags); + port->write_urb_busy = 0; return (0); } @@ -268,6 +273,7 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b priv->wrfilled=0; priv->wrsent=0; spin_unlock_irqrestore(&priv->lock, flags); + port->write_urb_busy = 0; return 0; } @@ -412,7 +418,8 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs struct cyberjack_private *priv = usb_get_serial_port_data(port); dbg("%s - port %d", __FUNCTION__, port->number); - + + port->write_urb_busy = 0; if (urb->status) { dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; @@ -424,12 +431,6 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs if( priv->wrfilled ) { int length, blksize, result; - if (port->write_urb->status == -EINPROGRESS) { - dbg("%s - already writing", __FUNCTION__); - spin_unlock(&priv->lock); - return; - } - dbg("%s - transmitting data (frame n)", __FUNCTION__); length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ? diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 99214aa3cd19..ddde5fb13f6b 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -174,10 +174,14 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char * /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { - if (port->write_urb->status == -EINPROGRESS) { + spin_lock(&port->lock); + if (port->write_urb_busy) { + spin_unlock(&port->lock); dbg("%s - already writing", __FUNCTION__); - return (0); + return 0; } + port->write_urb_busy = 1; + spin_unlock(&port->lock); count = (count > port->bulk_out_size) ? port->bulk_out_size : count; @@ -195,17 +199,20 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char * usb_serial_generic_write_bulk_callback), port); /* send the data out the bulk port */ + port->write_urb_busy = 1; result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) + if (result) { dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); - else + /* don't have to grab the lock here, as we will retry if != 0 */ + port->write_urb_busy = 0; + } else result = count; return result; } /* no bulk out, so return 0 bytes written */ - return (0); + return 0; } int usb_serial_generic_write_room (struct usb_serial_port *port) @@ -214,9 +221,9 @@ int usb_serial_generic_write_room (struct usb_serial_port *port) int room = 0; dbg("%s - port %d", __FUNCTION__, port->number); - + if (serial->num_bulk_out) { - if (port->write_urb->status != -EINPROGRESS) + if (port->write_urb_busy) room = port->bulk_out_size; } @@ -232,7 +239,7 @@ int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port) dbg("%s - port %d", __FUNCTION__, port->number); if (serial->num_bulk_out) { - if (port->write_urb->status == -EINPROGRESS) + if (port->write_urb_busy) chars = port->write_urb->transfer_buffer_length; } @@ -291,6 +298,7 @@ void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *re dbg("%s - port %d", __FUNCTION__, port->number); + port->write_urb_busy = 0; if (urb->status) { dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 3bd69c4ef24b..c05c2a2a0f31 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -818,11 +818,6 @@ static void ipaq_write_gather(struct usb_serial_port *port) struct ipaq_packet *pkt, *tmp; struct urb *urb = port->write_urb; - if (urb->status == -EINPROGRESS) { - /* Should never happen */ - err("%s - flushing while urb is active !", __FUNCTION__); - return; - } room = URBDATA_SIZE; list_for_each_entry_safe(pkt, tmp, &priv->queue, list) { count = min(room, (int)(pkt->len - pkt->written)); diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 11105d74f461..85e242459c27 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -399,16 +399,21 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int dbg("%s - write request of 0 bytes", __FUNCTION__); return 0; } - - /* Racy and broken, FIXME properly! */ - if (port->write_urb->status == -EINPROGRESS) + + spin_lock(&port->lock); + if (port->write_urb_busy) { + spin_unlock(&port->lock); + dbg("%s - already writing", __FUNCTION__); return 0; + } + port->write_urb_busy = 1; + spin_unlock(&port->lock); count = min(count, port->bulk_out_size); memcpy(port->bulk_out_buffer, buf, count); dbg("%s count now:%d", __FUNCTION__, count); - + usb_fill_bulk_urb(port->write_urb, dev, usb_sndbulkpipe(dev, port->bulk_out_endpointAddress), port->write_urb->transfer_buffer, @@ -418,6 +423,7 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int ret = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (ret != 0) { + port->write_urb_busy = 0; dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, ret); return ret; } diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 59f234df5f89..937b2fdd7171 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -341,10 +341,14 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int if (count == 0) return 0; - if (port->write_urb->status == -EINPROGRESS) { - dbg ("%s - already writing", __FUNCTION__); + spin_lock(&port->lock); + if (port->write_urb_busy) { + spin_unlock(&port->lock); + dbg("%s - already writing", __FUNCTION__); return 0; } + port->write_urb_busy = 1; + spin_unlock(&port->lock); transfer_buffer = port->write_urb->transfer_buffer; transfer_size = min(count, port->bulk_out_size - 1); @@ -374,9 +378,10 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int port->write_urb->transfer_flags = URB_ZERO_PACKET; result = usb_submit_urb (port->write_urb, GFP_ATOMIC); - if (result) + if (result) { + port->write_urb_busy = 0; dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); - else + } else result = transfer_size; return result; @@ -387,7 +392,8 @@ static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs) struct usb_serial_port *port = (struct usb_serial_port *)urb->context; dbg("%s - port %d", __FUNCTION__, port->number); - + + port->write_urb_busy = 0; if (urb->status) { dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 7fd0aa9eccf6..635c384cb15a 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -520,9 +520,13 @@ static int keyspan_pda_write(struct usb_serial_port *port, the TX urb is in-flight (wait until it completes) the device is full (wait until it says there is room) */ - if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) { - return( 0 ); + spin_lock(&port->lock); + if (port->write_urb_busy || priv->tx_throttled) { + spin_unlock(&port->lock); + return 0; } + port->write_urb_busy = 1; + spin_unlock(&port->lock); /* At this point the URB is in our control, nobody else can submit it again (the only sudden transition was the one from EINPROGRESS to @@ -570,7 +574,7 @@ static int keyspan_pda_write(struct usb_serial_port *port, memcpy (port->write_urb->transfer_buffer, buf, count); /* send the data out the bulk port */ port->write_urb->transfer_buffer_length = count; - + priv->tx_room -= count; port->write_urb->dev = port->serial->dev; @@ -593,6 +597,8 @@ static int keyspan_pda_write(struct usb_serial_port *port, rc = count; exit: + if (rc < 0) + port->write_urb_busy = 0; return rc; } @@ -602,6 +608,7 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb, struct pt_regs *re struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct keyspan_pda_private *priv; + port->write_urb_busy = 0; priv = usb_get_serial_port_data(port); /* queue up a wakeup at scheduler time */ @@ -626,12 +633,12 @@ static int keyspan_pda_write_room (struct usb_serial_port *port) static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port) { struct keyspan_pda_private *priv; - + priv = usb_get_serial_port_data(port); - + /* when throttled, return at least WAKEUP_CHARS to tell select() (via n_tty.c:normal_poll() ) that we're not writeable. */ - if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) + if (port->write_urb_busy || priv->tx_throttled) return 256; return 0; } diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index b5f2c06d4f3e..6a99ae192df1 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -254,10 +254,15 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf dbg("%s - write request of 0 bytes", __FUNCTION__); return (0); } - if (wport->write_urb->status == -EINPROGRESS) { + + spin_lock(&port->lock); + if (port->write_urb_busy) { + spin_unlock(&port->lock); dbg("%s - already writing", __FUNCTION__); - return (0); + return 0; } + port->write_urb_busy = 1; + spin_unlock(&port->lock); count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; @@ -275,9 +280,10 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf wport->write_urb->dev = serial->dev; result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); - if (result) + if (result) { + port->write_urb_busy = 0; err("%s - failed submitting write urb, error %d", __FUNCTION__, result); - else + } else result = count; return result; @@ -291,7 +297,7 @@ static int omninet_write_room (struct usb_serial_port *port) int room = 0; // Default: no room - if (wport->write_urb->status != -EINPROGRESS) + if (wport->write_urb_busy) room = wport->bulk_out_size - OMNINET_HEADERLEN; // dbg("omninet_write_room returns %d", room); @@ -306,6 +312,7 @@ static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs) // dbg("omninet_write_bulk_callback, port %0x\n", port); + port->write_urb_busy = 0; if (urb->status) { dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 0e85ed6c6c19..96a17568cbf1 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -299,10 +299,14 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i dbg ("%s - write request of 0 bytes", __FUNCTION__); return (0); } - if (port->write_urb->status == -EINPROGRESS) { - dbg ("%s - already writing", __FUNCTION__); - return (0); + spin_lock(&port->lock); + if (port->write_urb_busy) { + spin_unlock(&port->lock); + dbg("%s - already writing", __FUNCTION__); + return 0; } + port->write_urb_busy = 1; + spin_unlock(&port->lock); packet_length = port->bulk_out_size; // get max packetsize @@ -354,6 +358,7 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i #endif port->write_urb->dev = port->serial->dev; if ((result = usb_submit_urb (port->write_urb, GFP_KERNEL))) { + port->write_urb_busy = 0; err ("%s - failed submitting write urb, error %d", __FUNCTION__, result); return 0; } @@ -368,7 +373,7 @@ static int safe_write_room (struct usb_serial_port *port) dbg ("%s", __FUNCTION__); - if (port->write_urb->status != -EINPROGRESS) + if (port->write_urb_busy) room = port->bulk_out_size - (safe ? 2 : 0); if (room) { diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 5da76dd8fb28..0267b26dde18 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1047,6 +1047,7 @@ int usb_serial_probe(struct usb_interface *interface, memset(port, 0x00, sizeof(struct usb_serial_port)); port->number = i + serial->minor; port->serial = serial; + spin_lock_init(&port->lock); INIT_WORK(&port->work, usb_serial_port_softint, port); serial->port[i] = port; } diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index d1f0c4057fa6..57f92f054c75 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -69,6 +69,7 @@ * usb_serial_port: structure for the specific ports of a device. * @serial: pointer back to the struct usb_serial owner of this port. * @tty: pointer to the corresponding tty for this port. + * @lock: spinlock to grab when updating portions of this structure. * @number: the number of the port (the minor number). * @interrupt_in_buffer: pointer to the interrupt in buffer for this port. * @interrupt_in_urb: pointer to the interrupt in struct urb for this port. @@ -98,6 +99,7 @@ struct usb_serial_port { struct usb_serial * serial; struct tty_struct * tty; + spinlock_t lock; unsigned char number; unsigned char * interrupt_in_buffer; @@ -117,6 +119,7 @@ struct usb_serial_port { unsigned char * bulk_out_buffer; int bulk_out_size; struct urb * write_urb; + int write_urb_busy; __u8 bulk_out_endpointAddress; wait_queue_head_t write_wait; -- cgit v1.2.3 From a3c900bb8cbacfecf0be51313e43f330663266a1 Mon Sep 17 00:00:00 2001 From: Colin Leroy Date: Sun, 24 Apr 2005 16:37:15 -0700 Subject: [PATCH] USB: PM support for zd1201 This patch enables power management (suspend, resume) support for zd1201. It fixes problems after wakeup for me, but these problems did not appear everytime without this patch. it's a bit empirical, based on what the usbnet does, so maybe not correct... Maybe someone can give it a look before it's applied. Signed-off-by: Colin Leroy Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/zd1201.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/usb/net/zd1201.h | 1 + 2 files changed, 39 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index 341ae5f732dd..eb0bff535b3c 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -1884,12 +1884,50 @@ static void zd1201_disconnect(struct usb_interface *interface) kfree(zd); } +#ifdef CONFIG_PM + +static int zd1201_suspend(struct usb_interface *interface, + pm_message_t message) +{ + struct zd1201 *zd = usb_get_intfdata(interface); + + netif_device_detach(zd->dev); + + zd->was_enabled = zd->mac_enabled; + + if (zd->was_enabled) + return zd1201_disable(zd); + else + return 0; +} + +static int zd1201_resume(struct usb_interface *interface) +{ + struct zd1201 *zd = usb_get_intfdata(interface); + + netif_device_attach(zd->dev); + + if (zd->was_enabled) + return zd1201_enable(zd); + else + return 0; +} + +#else + +#define zd1201_suspend NULL +#define zd1201_resume NULL + +#endif + static struct usb_driver zd1201_usb = { .owner = THIS_MODULE, .name = "zd1201", .probe = zd1201_probe, .disconnect = zd1201_disconnect, .id_table = zd1201_table, + .suspend = zd1201_suspend, + .resume = zd1201_resume, }; static int __init zd1201_init(void) diff --git a/drivers/usb/net/zd1201.h b/drivers/usb/net/zd1201.h index 1627c71e8052..235f0ee34b24 100644 --- a/drivers/usb/net/zd1201.h +++ b/drivers/usb/net/zd1201.h @@ -46,6 +46,7 @@ struct zd1201 { char essid[IW_ESSID_MAX_SIZE+1]; int essidlen; int mac_enabled; + int was_enabled; int monitor; int encode_enabled; int encode_restricted; -- cgit v1.2.3 From f58f97fa9d258e4110ee1257a63cd1af51787f69 Mon Sep 17 00:00:00 2001 From: Colin Leroy Date: Sun, 1 May 2005 11:29:10 +0200 Subject: [PATCH] USB: check for device in zd1201_resume My patch adding PM support for zd1201 didn't check for the device on resume, which can oops if the device has been removed. This patch fixes it. Signed-off-by: Colin Leroy Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/zd1201.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index eb0bff535b3c..3b387b005739 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -1905,6 +1905,9 @@ static int zd1201_resume(struct usb_interface *interface) { struct zd1201 *zd = usb_get_intfdata(interface); + if (!zd || !zd->dev) + return -ENODEV; + netif_device_attach(zd->dev); if (zd->was_enabled) -- cgit v1.2.3 From 7d35b9298539d2818c51fe9070b08cf9876016f4 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 25 Apr 2005 11:18:32 -0400 Subject: [PATCH] usbcore: Remove hub_set_power_budget This patch removes the hub_set_power_budget routine, which was used by a couple of HCDs to indicate that the root hub was running on battery power. In its place is a new field added to struct usb_hcd, which HCDs can set before the root hub is registered. Special-case code in the hub driver knows to look at this field when configuring a root hub. Signed-off-by: Alan Stern Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.h | 1 + drivers/usb/core/hub.c | 12 +++++++++--- drivers/usb/core/hub.h | 11 ----------- 3 files changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index ac5752778e39..3837f68bb7b3 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -87,6 +87,7 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ void __iomem *regs; /* device memory/io */ u64 rsrc_start; /* memory/io resource start */ u64 rsrc_len; /* memory/io resource length */ + unsigned power_budget; /* in mA, 0 = no limit */ #define HCD_BUFFER_POOLS 4 struct dma_pool *pool [HCD_BUFFER_POOLS]; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 6d1a330d577b..63ee3d97b6a9 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -643,15 +643,21 @@ static int hub_configure(struct usb_hub *hub, message = "can't get hub status"; goto fail; } - cpu_to_le16s(&hubstatus); - if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) { + le16_to_cpus(&hubstatus); + if (hdev == hdev->bus->root_hub) { + struct usb_hcd *hcd = + container_of(hdev->bus, struct usb_hcd, self); + + hub->power_budget = min(500u, hcd->power_budget) / 2; + } else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) { dev_dbg(hub_dev, "hub controller current requirement: %dmA\n", hub->descriptor->bHubContrCurrent); hub->power_budget = (501 - hub->descriptor->bHubContrCurrent) / 2; + } + if (hub->power_budget) dev_dbg(hub_dev, "%dmA bus power budget for children\n", hub->power_budget * 2); - } ret = hub_hub_status(hub, &hubstatus, &hubchange); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index d114b847d56f..53bf5649621e 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -224,15 +224,4 @@ struct usb_hub { struct work_struct leds; }; -/* use this for low-powered root hubs */ -static inline void -hub_set_power_budget (struct usb_device *hubdev, unsigned mA) -{ - struct usb_hub *hub; - - hub = (struct usb_hub *) - usb_get_intfdata (hubdev->actconfig->interface[0]); - hub->power_budget = min(mA,(unsigned)500)/2; -} - #endif /* __LINUX_HUB_H */ -- cgit v1.2.3 From 2532178a68b5ce4e421d50ea1b1dcc0a1359f19d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 25 Apr 2005 11:14:31 -0400 Subject: [PATCH] UHCI: Don't store device pointer in QH or TD This patch simplifies the uhci-hcd driver by removing the device pointer currently stored in the QH and TD structures. Those pointers weren't being used for anything other than to increment the device's reference count, which is unnecessary since the device is used only when an URB completes, and outstanding URBs take their own reference to the device. As a useful side effect, this change means that uhci-hcd no longer needs to have the root-hub device available in the start routine. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 4 ++-- drivers/usb/host/uhci-hcd.h | 2 -- drivers/usb/host/uhci-q.c | 32 ++++++++++---------------------- 3 files changed, 12 insertions(+), 26 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 53ba8a56592e..6b87bd74b046 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -634,14 +634,14 @@ static int uhci_start(struct usb_hcd *hcd) goto err_alloc_root_hub; } - uhci->term_td = uhci_alloc_td(uhci, udev); + uhci->term_td = uhci_alloc_td(uhci); if (!uhci->term_td) { dev_err(uhci_dev(uhci), "unable to allocate terminating TD\n"); goto err_alloc_term_td; } for (i = 0; i < UHCI_NUM_SKELQH; i++) { - uhci->skelqh[i] = uhci_alloc_qh(uhci, udev); + uhci->skelqh[i] = uhci_alloc_qh(uhci); if (!uhci->skelqh[i]) { dev_err(uhci_dev(uhci), "unable to allocate QH\n"); goto err_alloc_skelqh; diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index d7c67b73eb7a..bf9c5f9b508b 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -114,7 +114,6 @@ struct uhci_qh { /* Software fields */ dma_addr_t dma_handle; - struct usb_device *dev; struct urb_priv *urbp; struct list_head list; /* P: uhci->frame_list_lock */ @@ -206,7 +205,6 @@ struct uhci_td { /* Software fields */ dma_addr_t dma_handle; - struct usb_device *dev; struct urb *urb; struct list_head list; /* P: urb->lock */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 77f264851e98..5f18084a116d 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -48,7 +48,7 @@ static inline void uhci_moveto_complete(struct uhci_hcd *uhci, list_move_tail(&urbp->urb_list, &uhci->complete_list); } -static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev) +static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) { dma_addr_t dma_handle; struct uhci_td *td; @@ -63,14 +63,11 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *d 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; } @@ -170,13 +167,10 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *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) +static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci) { dma_addr_t dma_handle; struct uhci_qh *qh; @@ -190,14 +184,11 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *d 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; } @@ -208,9 +199,6 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *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); } @@ -599,7 +587,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur /* * Build the TD for the control request setup packet */ - td = uhci_alloc_td(uhci, urb->dev); + td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; @@ -628,7 +616,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur if (pktsze > maxsze) pktsze = maxsze; - td = uhci_alloc_td(uhci, urb->dev); + td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; @@ -646,7 +634,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur /* * Build the final TD for control status */ - td = uhci_alloc_td(uhci, urb->dev); + td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; @@ -668,7 +656,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur uhci_fill_td(td, status | TD_CTRL_IOC, destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0); - qh = uhci_alloc_qh(uhci, urb->dev); + qh = uhci_alloc_qh(uhci); if (!qh) return -ENOMEM; @@ -867,7 +855,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb status &= ~TD_CTRL_SPD; } - td = uhci_alloc_td(uhci, urb->dev); + td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; @@ -893,7 +881,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb */ if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) && !len && urb->transfer_buffer_length) { - td = uhci_alloc_td(uhci, urb->dev); + td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; @@ -915,7 +903,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb * flag setting. */ td->status |= cpu_to_le32(TD_CTRL_IOC); - qh = uhci_alloc_qh(uhci, urb->dev); + qh = uhci_alloc_qh(uhci); if (!qh) return -ENOMEM; @@ -1098,7 +1086,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) if (!urb->iso_frame_desc[i].length) continue; - td = uhci_alloc_td(uhci, urb->dev); + td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; -- cgit v1.2.3 From bc96c0ad1ed0c938fefc0423aa99f086c5a2a1ea Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 25 Apr 2005 11:21:31 -0400 Subject: [PATCH] ohci-omap, sl811, dummy: remove hub_set_power_budget This patch changes the HCDs that used the old hub_set_power_budget call, making them use the new hcd->power_budget field instead. Signed-off-by: Alan Stern Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 6 +++--- drivers/usb/host/ohci-hcd.c | 2 -- drivers/usb/host/ohci-omap.c | 4 ++-- drivers/usb/host/ohci.h | 1 - drivers/usb/host/sl811-hcd.c | 7 +++---- 5 files changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c039d2fbe7ab..9d37fc771b27 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1646,6 +1646,9 @@ static int dummy_start (struct usb_hcd *hcd) if (!root) return -ENOMEM; + /* only show a low-power port: just 8mA */ + hcd->power_budget = 8; + /* root hub enters addressed state... */ hcd->state = HC_STATE_RUNNING; root->speed = USB_SPEED_HIGH; @@ -1655,9 +1658,6 @@ static int dummy_start (struct usb_hcd *hcd) goto err1; } - /* only show a low-power port: just 8mA */ - hub_set_power_budget (root, 8); - if ((retval = dummy_register_udc (dum)) != 0) goto err2; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 32120042ab65..0da996191251 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -699,8 +699,6 @@ retry: ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); return -ENODEV; } - if (ohci->power_budget) - hub_set_power_budget(udev, ohci->power_budget); register_reboot_notifier (&ohci->reboot_notifier); create_debug_files (ohci); diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 8aab5907afe9..b62d69937694 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -181,7 +181,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) if (config->otg) { ohci_to_hcd(ohci)->self.otg_port = config->otg; /* default/minimum OTG power budget: 8 mA */ - ohci->power_budget = 8; + ohci_to_hcd(ohci)->power_budget = 8; } /* boards can use OTG transceivers in non-OTG modes */ @@ -230,7 +230,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev) /* TPS2045 switch for internal transceiver (port 1) */ if (machine_is_omap_osk()) { - ohci->power_budget = 250; + ohci_to_hcd(ohci)->power_budget = 250; rh &= ~RH_A_NOCP; diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 3dbc7c0eed43..71cdd2262860 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -371,7 +371,6 @@ struct ohci_hcd { * other external transceivers should be software-transparent */ struct otg_transceiver *transceiver; - unsigned power_budget; /* * memory management for queue data structures diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 99d43f758ad0..1f2d00fe983a 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1574,8 +1574,10 @@ sl811h_start(struct usb_hcd *hcd) udev->speed = USB_SPEED_FULL; hcd->state = HC_STATE_RUNNING; - if (sl811->board) + if (sl811->board) { hcd->can_wakeup = sl811->board->can_wakeup; + hcd->power_budget = sl811->board->power * 2; + } if (usb_hcd_register_root_hub(udev, hcd) != 0) { usb_put_dev(udev); @@ -1583,9 +1585,6 @@ sl811h_start(struct usb_hcd *hcd) return -ENODEV; } - if (sl811->board && sl811->board->power) - hub_set_power_budget(udev, sl811->board->power * 2); - /* enable power and interupts */ port_power(sl811, 1); -- cgit v1.2.3 From 8ec8d20b21f00a36343ca0ebd6c6be9421724a1e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 25 Apr 2005 11:25:17 -0400 Subject: [PATCH] usbcore: register root hub in usb_add_hcd This patch makes usbcore automatically allocate and register the root hub device for a new host controller when the controller is registered. This way the HCDs don't all have to include the same boilerplate code. As a pleasant side benefit, the register_root_hub routine can now be made static and not EXPORTed. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 72 ++++++++++++++++++++++++++++++++++---------------- drivers/usb/core/hcd.h | 3 --- 2 files changed, 49 insertions(+), 26 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1180c157b717..83e732a0d64a 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -832,30 +832,22 @@ static void usb_deregister_bus (struct usb_bus *bus) } /** - * usb_hcd_register_root_hub - called by HCD to register its root hub + * register_root_hub - called by usb_add_hcd() to register a root hub * @usb_dev: the usb root hub device to be registered. * @hcd: host controller for this root hub * - * The USB host controller calls this function to register the root hub - * properly with the USB subsystem. It sets up the device properly in - * the device tree and stores the root_hub pointer in the bus structure, - * then calls usb_new_device() to register the usb device. It also - * assigns the root hub's USB address (always 1). + * This function registers the root hub with the USB subsystem. It sets up + * the device properly in the device tree and stores the root_hub pointer + * in the bus structure, then calls usb_new_device() to register the usb + * device. It also assigns the root hub's USB address (always 1). */ -int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd) +static int register_root_hub (struct usb_device *usb_dev, + struct usb_hcd *hcd) { struct device *parent_dev = hcd->self.controller; const int devnum = 1; int retval; - /* hcd->driver->start() reported can_wakeup, probably with - * assistance from board's boot firmware. - * NOTE: normal devices won't enable wakeup by default. - */ - if (hcd->can_wakeup) - dev_dbg (parent_dev, "supports USB remote wakeup\n"); - hcd->remote_wakeup = hcd->can_wakeup; - usb_dev->devnum = devnum; usb_dev->bus->devnum_next = devnum + 1; memset (&usb_dev->bus->devmap.devicemap, 0, @@ -898,7 +890,6 @@ int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd) return retval; } -EXPORT_SYMBOL_GPL(usb_hcd_register_root_hub); void usb_enable_root_hub_irq (struct usb_bus *bus) { @@ -1724,7 +1715,8 @@ EXPORT_SYMBOL (usb_put_hcd); int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags) { - int retval; + int retval; + struct usb_device *rhdev; dev_info(hcd->self.controller, "%s\n", hcd->product_desc); @@ -1740,7 +1732,7 @@ int usb_add_hcd(struct usb_hcd *hcd, } if ((retval = usb_register_bus(&hcd->self)) < 0) - goto err1; + goto err_register_bus; if (hcd->driver->irq) { char buf[8], *bufp = buf; @@ -1757,7 +1749,7 @@ int usb_add_hcd(struct usb_hcd *hcd, hcd->irq_descr, hcd)) != 0) { dev_err(hcd->self.controller, "request interrupt %s failed\n", bufp); - goto err2; + goto err_request_irq; } hcd->irq = irqnum; dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp, @@ -1773,21 +1765,55 @@ int usb_add_hcd(struct usb_hcd *hcd, (unsigned long long)hcd->rsrc_start); } + /* Allocate the root hub before calling hcd->driver->start(), + * but don't register it until afterward so that the hardware + * is running. + */ + if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { + dev_err(hcd->self.controller, "unable to allocate root hub\n"); + retval = -ENOMEM; + goto err_allocate_root_hub; + } + rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH : + USB_SPEED_FULL; + + /* Although in principle hcd->driver->start() might need to use rhdev, + * none of the current drivers do. + */ if ((retval = hcd->driver->start(hcd)) < 0) { dev_err(hcd->self.controller, "startup error %d\n", retval); - goto err3; + goto err_hcd_driver_start; } + /* hcd->driver->start() reported can_wakeup, probably with + * assistance from board's boot firmware. + * NOTE: normal devices won't enable wakeup by default. + */ + if (hcd->can_wakeup) + dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); + hcd->remote_wakeup = hcd->can_wakeup; + + if ((retval = register_root_hub(rhdev, hcd)) != 0) + goto err_register_root_hub; + if (hcd->uses_new_polling && hcd->poll_rh) usb_hcd_poll_rh_status(hcd); return retval; - err3: + err_register_root_hub: + hcd->driver->stop(hcd); + + err_hcd_driver_start: + usb_put_dev(rhdev); + + err_allocate_root_hub: if (hcd->irq >= 0) free_irq(irqnum, hcd); - err2: + + err_request_irq: usb_deregister_bus(&hcd->self); - err1: + + err_register_bus: hcd_buffer_destroy(hcd); return retval; } diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 3837f68bb7b3..8dc13cde2f73 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -353,9 +353,6 @@ extern long usb_calc_bus_time (int speed, int is_input, extern struct usb_bus *usb_alloc_bus (struct usb_operations *); -extern int usb_hcd_register_root_hub (struct usb_device *usb_dev, - struct usb_hcd *hcd); - extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); extern void usb_set_device_state(struct usb_device *udev, -- cgit v1.2.3 From 247f3105636caa9d1d8a4c3dfb755de42633bc80 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 25 Apr 2005 11:28:04 -0400 Subject: [PATCH] USB HCDs: no longer need to register root hub This patch changes the host controller drivers; they no longer need to register their root hubs because usbcore will take care of it for them. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 24 ++---------------------- drivers/usb/host/ehci-hcd.c | 31 ------------------------------- drivers/usb/host/isp116x-hcd.c | 16 ---------------- drivers/usb/host/ohci-hcd.c | 30 ++---------------------------- drivers/usb/host/sl811-hcd.c | 13 ------------- drivers/usb/host/uhci-hcd.c | 25 ------------------------- 6 files changed, 4 insertions(+), 135 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 9d37fc771b27..1918d10f7569 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1625,7 +1625,6 @@ static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); static int dummy_start (struct usb_hcd *hcd) { struct dummy *dum; - struct usb_device *root; int retval; dum = hcd_to_dummy (hcd); @@ -1642,35 +1641,16 @@ static int dummy_start (struct usb_hcd *hcd) INIT_LIST_HEAD (&dum->urbp_list); - root = usb_alloc_dev (NULL, &hcd->self, 0); - if (!root) - return -ENOMEM; + if ((retval = dummy_register_udc (dum)) != 0) + return retval; /* only show a low-power port: just 8mA */ hcd->power_budget = 8; - - /* root hub enters addressed state... */ hcd->state = HC_STATE_RUNNING; - root->speed = USB_SPEED_HIGH; - - /* ...then configured, so khubd sees us. */ - if ((retval = usb_hcd_register_root_hub (root, hcd)) != 0) { - goto err1; - } - - 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); return 0; - - err2: - usb_disconnect (&hcd->self.root_hub); - err1: - usb_put_dev (root); - hcd->state = HC_STATE_QUIESCING; - return retval; } static void dummy_stop (struct usb_hcd *hcd) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index bc69bd7acebe..527abc693b17 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -492,8 +492,6 @@ static int ehci_start (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 temp; - struct usb_device *udev; - struct usb_bus *bus; int retval; u32 hcc_params; u8 sbrn = 0; @@ -631,17 +629,6 @@ static int ehci_start (struct usb_hcd *hcd) /* set async sleep time = 10 us ... ? */ - /* wire up the root hub */ - bus = hcd_to_bus (hcd); - udev = first ? usb_alloc_dev (NULL, bus, 0) : bus->root_hub; - if (!udev) { -done2: - ehci_mem_cleanup (ehci); - return -ENOMEM; - } - udev->speed = USB_SPEED_HIGH; - udev->state = first ? USB_STATE_ATTACHED : USB_STATE_CONFIGURED; - /* * Start, enabling full USB 2.0 functionality ... usb 1.1 devices * are explicitly handed to companion controller(s), so no TT is @@ -664,24 +651,6 @@ done2: first ? "initialized" : "restarted", temp >> 8, temp & 0xff, DRIVER_VERSION); - /* - * From here on, khubd concurrently accesses the root - * hub; drivers will be talking to enumerated devices. - * (On restart paths, khubd already knows about the root - * hub and could find work as soon as we wrote FLAG_CF.) - * - * Before this point the HC was idle/ready. After, khubd - * and device drivers may start it running. - */ - if (first && usb_hcd_register_root_hub (udev, hcd) != 0) { - if (hcd->state == HC_STATE_RUNNING) - ehci_quiesce (ehci); - ehci_reset (ehci); - usb_put_dev (udev); - retval = -ENODEV; - goto done2; - } - writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ if (first) diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 1183988fdf54..ff0a168e8eed 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1547,7 +1547,6 @@ static int isp116x_start(struct usb_hcd *hcd) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct isp116x_platform_data *board = isp116x->board; - struct usb_device *udev; u32 val; unsigned long flags; @@ -1609,24 +1608,9 @@ static int isp116x_start(struct usb_hcd *hcd) isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS); isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf); - spin_unlock_irqrestore(&isp116x->lock, flags); - - udev = usb_alloc_dev(NULL, &hcd->self, 0); - if (!udev) { - isp116x_stop(hcd); - return -ENOMEM; - } - udev->speed = USB_SPEED_FULL; hcd->state = HC_STATE_RUNNING; - if (usb_hcd_register_root_hub(udev, hcd) != 0) { - isp116x_stop(hcd); - usb_put_dev(udev); - return -ENODEV; - } - - spin_lock_irqsave(&isp116x->lock, flags); /* Set up interrupts */ isp116x->intenb = HCINT_MIE | HCINT_RHSC | HCINT_UE; if (board->remote_wakeup_enable) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 0da996191251..13cd2177b557 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -505,13 +505,10 @@ static int ohci_init (struct ohci_hcd *ohci) /* Start an OHCI controller, set the BUS operational * resets USB and controller * enable interrupts - * connect the virtual root hub */ static int ohci_run (struct ohci_hcd *ohci) { u32 mask, temp; - struct usb_device *udev; - struct usb_bus *bus; int first = ohci->fminterval == 0; disable (ohci); @@ -672,36 +669,13 @@ retry: // POTPGT delay is bits 24-31, in 2 ms units. mdelay ((temp >> 23) & 0x1fe); - bus = &ohci_to_hcd(ohci)->self; ohci_to_hcd(ohci)->state = HC_STATE_RUNNING; ohci_dump (ohci, 1); - udev = bus->root_hub; - if (udev) { - return 0; - } - - /* connect the virtual root hub */ - udev = usb_alloc_dev (NULL, bus, 0); - if (!udev) { - disable (ohci); - ohci->hc_control &= ~OHCI_CTRL_HCFS; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - return -ENOMEM; - } - - udev->speed = USB_SPEED_FULL; - if (usb_hcd_register_root_hub (udev, ohci_to_hcd(ohci)) != 0) { - usb_put_dev (udev); - disable (ohci); - ohci->hc_control &= ~OHCI_CTRL_HCFS; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - return -ENODEV; - } + if (ohci_to_hcd(ohci)->self.root_hub == NULL) + create_debug_files (ohci); - register_reboot_notifier (&ohci->reboot_notifier); - create_debug_files (ohci); return 0; } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 1f2d00fe983a..6c3f910bc307 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1563,15 +1563,8 @@ static int sl811h_start(struct usb_hcd *hcd) { struct sl811 *sl811 = hcd_to_sl811(hcd); - struct usb_device *udev; /* chip has been reset, VBUS power is off */ - - udev = usb_alloc_dev(NULL, &hcd->self, 0); - if (!udev) - return -ENOMEM; - - udev->speed = USB_SPEED_FULL; hcd->state = HC_STATE_RUNNING; if (sl811->board) { @@ -1579,12 +1572,6 @@ sl811h_start(struct usb_hcd *hcd) hcd->power_budget = sl811->board->power * 2; } - if (usb_hcd_register_root_hub(udev, hcd) != 0) { - usb_put_dev(udev); - sl811h_stop(hcd); - return -ENODEV; - } - /* enable power and interupts */ port_power(sl811, 1); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 6b87bd74b046..fdf54295da73 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -562,7 +562,6 @@ static int uhci_start(struct usb_hcd *hcd) int retval = -EBUSY; int i; dma_addr_t dma_handle; - struct usb_device *udev; struct dentry *dentry; hcd->uses_new_polling = 1; @@ -626,14 +625,6 @@ static int uhci_start(struct usb_hcd *hcd) goto err_create_qh_pool; } - /* Initialize the root hub */ - - udev = usb_alloc_dev(NULL, &hcd->self, 0); - if (!udev) { - dev_err(uhci_dev(uhci), "unable to allocate root hub\n"); - goto err_alloc_root_hub; - } - uhci->term_td = uhci_alloc_td(uhci); if (!uhci->term_td) { dev_err(uhci_dev(uhci), "unable to allocate terminating TD\n"); @@ -713,24 +704,11 @@ static int uhci_start(struct usb_hcd *hcd) configure_hc(uhci); start_rh(uhci); - - udev->speed = USB_SPEED_FULL; - - if (usb_hcd_register_root_hub(udev, hcd) != 0) { - dev_err(uhci_dev(uhci), "unable to start root hub\n"); - retval = -ENOMEM; - goto err_start_root_hub; - } - return 0; /* * error exits: */ -err_start_root_hub: - reset_hc(uhci); - del_timer_sync(&uhci->stall_timer); - err_alloc_skelqh: for (i = 0; i < UHCI_NUM_SKELQH; i++) if (uhci->skelqh[i]) { @@ -742,9 +720,6 @@ err_alloc_skelqh: uhci->term_td = NULL; err_alloc_term_td: - usb_put_dev(udev); - -err_alloc_root_hub: dma_pool_destroy(uhci->qh_pool); uhci->qh_pool = NULL; -- cgit v1.2.3 From 340600ab4cf0cc41efd01a65af97ebb7d35a7f85 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 28 Apr 2005 13:45:25 -0700 Subject: [PATCH] USB: rndis updates (mostly cleanup) Some bugfixes and lots of cleanup (net code shrink): - On reset, force the RNDIS state machine its initial state - Hook up the RNDIS (outgoing) filters to the CDC mechanism - Lots of cleanup: * Eliminate duplicate copy of OID table; * Unify handlying of the OID "query" response data pointer; * Reduce code duplication for calculating query response lengths; * Remove some checks for "can't happen" errors; * Get rid of debugging #ifdefs by making the debug flag an integer level Most of the patch, by volume, relates to those query response cleanups. It incidentally shaves off a few hundred bytes of object code. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 11 +- drivers/usb/gadget/ndis.h | 14 +- drivers/usb/gadget/rndis.c | 509 +++++++++++++++++++++++---------------------- drivers/usb/gadget/rndis.h | 95 +-------- 4 files changed, 285 insertions(+), 344 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 3f783cbdc7c3..a766c29c3ec9 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -94,8 +94,9 @@ static const char driver_desc [] = DRIVER_DESC; #ifdef CONFIG_USB_ETH_RNDIS #include "rndis.h" #else -#define rndis_init() 0 -#define rndis_exit() do{}while(0) +#define rndis_init() 0 +#define rndis_uninit(x) do{}while(0) +#define rndis_exit() do{}while(0) #endif /* CDC and RNDIS support the same host-chosen outgoing packet filters. */ @@ -395,7 +396,8 @@ static inline int BITRATE(struct usb_gadget *g) #define STRING_SUBSET 8 #define STRING_RNDIS 9 -#define USB_BUFSIZ 256 /* holds our biggest descriptor */ +/* holds our biggest descriptor (or RNDIS response) */ +#define USB_BUFSIZ 256 /* * This device advertises one configuration, eth_config, unless RNDIS @@ -1124,6 +1126,7 @@ static void eth_reset_config (struct eth_dev *dev) netif_stop_queue (dev->net); netif_carrier_off (dev->net); + rndis_uninit(dev->rndis_config); /* disable endpoints, forcing (synchronous) completion of * pending i/o. then free the requests. @@ -2565,7 +2568,7 @@ fail0: /* these set up a lot of the OIDs that RNDIS needs */ rndis_set_host_mac (dev->rndis_config, dev->host_mac); if (rndis_set_param_dev (dev->rndis_config, dev->net, - &dev->stats)) + &dev->stats, &dev->cdc_filter)) goto fail0; if (rndis_set_param_vendor (dev->rndis_config, vendorID, manufacturer)) diff --git a/drivers/usb/gadget/ndis.h b/drivers/usb/gadget/ndis.h index c553bbf68cab..09e3ee4eeae1 100644 --- a/drivers/usb/gadget/ndis.h +++ b/drivers/usb/gadget/ndis.h @@ -47,17 +47,17 @@ struct NDIS_PM_WAKE_UP_CAPABILITIES { #define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 struct NDIS_PNP_CAPABILITIES { - u32 Flags; + __le32 Flags; struct NDIS_PM_WAKE_UP_CAPABILITIES WakeUpCapabilities; }; struct NDIS_PM_PACKET_PATTERN { - u32 Priority; - u32 Reserved; - u32 MaskSize; - u32 PatternOffset; - u32 PatternSize; - u32 PatternFlags; + __le32 Priority; + __le32 Reserved; + __le32 MaskSize; + __le32 PatternOffset; + __le32 PatternSize; + __le32 PatternFlags; }; diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 7457268d5f28..c9a0af29ecb6 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -41,6 +41,7 @@ #undef RNDIS_PM +#undef RNDIS_WAKEUP #undef VERBOSE #include "rndis.h" @@ -60,7 +61,7 @@ } while (0) static int rndis_debug = 0; -module_param (rndis_debug, bool, 0); +module_param (rndis_debug, int, 0); MODULE_PARM_DESC (rndis_debug, "enable debugging"); #else @@ -78,22 +79,103 @@ static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS]; static const __le32 rndis_driver_version = __constant_cpu_to_le32 (1); /* Function Prototypes */ -static int rndis_init_response (int configNr, rndis_init_msg_type *buf); -static int rndis_query_response (int configNr, rndis_query_msg_type *buf); -static int rndis_set_response (int configNr, rndis_set_msg_type *buf); -static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf); -static int rndis_keepalive_response (int configNr, - rndis_keepalive_msg_type *buf); - static rndis_resp_t *rndis_add_response (int configNr, u32 length); +/* supported OIDs */ +static const u32 oid_supported_list [] = +{ + /* the general stuff */ + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MEDIA_CONNECT_STATUS, + OID_GEN_PHYSICAL_MEDIUM, +#if 0 + OID_GEN_RNDIS_CONFIG_PARAMETER, +#endif + + /* the statistical stuff */ + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, +#ifdef RNDIS_OPTIONAL_STATS + OID_GEN_DIRECTED_BYTES_XMIT, + OID_GEN_DIRECTED_FRAMES_XMIT, + OID_GEN_MULTICAST_BYTES_XMIT, + OID_GEN_MULTICAST_FRAMES_XMIT, + OID_GEN_BROADCAST_BYTES_XMIT, + OID_GEN_BROADCAST_FRAMES_XMIT, + OID_GEN_DIRECTED_BYTES_RCV, + OID_GEN_DIRECTED_FRAMES_RCV, + OID_GEN_MULTICAST_BYTES_RCV, + OID_GEN_MULTICAST_FRAMES_RCV, + OID_GEN_BROADCAST_BYTES_RCV, + OID_GEN_BROADCAST_FRAMES_RCV, + OID_GEN_RCV_CRC_ERROR, + OID_GEN_TRANSMIT_QUEUE_LENGTH, +#endif /* RNDIS_OPTIONAL_STATS */ + + /* mandatory 802.3 */ + /* the general stuff */ + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAC_OPTIONS, + OID_802_3_MAXIMUM_LIST_SIZE, + + /* the statistical stuff */ + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, +#ifdef RNDIS_OPTIONAL_STATS + OID_802_3_XMIT_DEFERRED, + OID_802_3_XMIT_MAX_COLLISIONS, + OID_802_3_RCV_OVERRUN, + OID_802_3_XMIT_UNDERRUN, + OID_802_3_XMIT_HEARTBEAT_FAILURE, + OID_802_3_XMIT_TIMES_CRS_LOST, + OID_802_3_XMIT_LATE_COLLISIONS, +#endif /* RNDIS_OPTIONAL_STATS */ + +#ifdef RNDIS_PM + /* PM and wakeup are mandatory for USB: */ + + /* power management */ + OID_PNP_CAPABILITIES, + OID_PNP_QUERY_POWER, + OID_PNP_SET_POWER, + +#ifdef RNDIS_WAKEUP + /* wake up host */ + OID_PNP_ENABLE_WAKE_UP, + OID_PNP_ADD_WAKE_UP_PATTERN, + OID_PNP_REMOVE_WAKE_UP_PATTERN, +#endif /* RNDIS_WAKEUP */ +#endif /* RNDIS_PM */ +}; + + /* NDIS Functions */ -static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) +static int +gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, + rndis_resp_t *r) { int retval = -ENOTSUPP; - u32 length = 0; - __le32 *tmp; + u32 length = 4; /* usually */ + __le32 *outbuf; int i, count; rndis_query_cmplt_type *resp; @@ -101,7 +183,22 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) resp = (rndis_query_cmplt_type *) r->buf; if (!resp) return -ENOMEM; - + + if (buf_len && rndis_debug > 1) { + DEBUG("query OID %08x value, len %d:\n", OID, buf_len); + for (i = 0; i < buf_len; i += 16) { + DEBUG ("%03d: %08x %08x %08x %08x\n", i, + le32_to_cpup((__le32 *)&buf[i]), + le32_to_cpup((__le32 *)&buf[i + 4]), + le32_to_cpup((__le32 *)&buf[i + 8]), + le32_to_cpup((__le32 *)&buf[i + 12])); + } + } + + /* response goes here, right after the header */ + outbuf = (__le32 *) &resp[1]; + resp->InformationBufferOffset = __constant_cpu_to_le32 (16); + switch (OID) { /* general oids (table 4-1) */ @@ -111,42 +208,36 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__); length = sizeof (oid_supported_list); count = length / sizeof (u32); - tmp = (__le32 *) ((u8 *)resp + 24); for (i = 0; i < count; i++) - tmp[i] = cpu_to_le32 (oid_supported_list[i]); + outbuf[i] = cpu_to_le32 (oid_supported_list[i]); retval = 0; break; /* mandatory */ case OID_GEN_HARDWARE_STATUS: DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__); - length = 4; /* Bogus question! * Hardware must be ready to receive high level protocols. * BTW: * reddite ergo quae sunt Caesaris Caesari * et quae sunt Dei Deo! */ - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; /* mandatory */ case OID_GEN_MEDIA_SUPPORTED: DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr].medium); + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); retval = 0; break; /* mandatory */ case OID_GEN_MEDIA_IN_USE: DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__); - length = 4; /* one medium, one transport... (maybe you do it better) */ - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr].medium); + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); retval = 0; break; @@ -154,25 +245,21 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_MAXIMUM_FRAME_SIZE: DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; /* mandatory */ case OID_GEN_LINK_SPEED: -// DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); - length = 4; + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); if (rndis_per_dev_params [configNr].media_state - == NDIS_MEDIA_STATE_DISCONNECTED) - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + == NDIS_MEDIA_STATE_DISCONNECTED) + *outbuf = __constant_cpu_to_le32 (0); else - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].speed); retval = 0; break; @@ -181,8 +268,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_TRANSMIT_BLOCK_SIZE: DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); retval = 0; } @@ -192,8 +278,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_RECEIVE_BLOCK_SIZE: DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); retval = 0; } @@ -202,8 +287,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_GEN_VENDOR_ID: DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].vendorID); retval = 0; break; @@ -212,51 +296,44 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_VENDOR_DESCRIPTION: DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__); length = strlen (rndis_per_dev_params [configNr].vendorDescr); - memcpy ((u8 *) resp + 24, + memcpy (outbuf, rndis_per_dev_params [configNr].vendorDescr, length); retval = 0; break; case OID_GEN_VENDOR_DRIVER_VERSION: DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__); - length = 4; /* Created as LE */ - *((__le32 *) resp + 6) = rndis_driver_version; + *outbuf = rndis_driver_version; retval = 0; break; /* mandatory */ case OID_GEN_CURRENT_PACKET_FILTER: DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params[configNr].filter); + *outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter); retval = 0; break; /* mandatory */ case OID_GEN_MAXIMUM_TOTAL_SIZE: DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32( - RNDIS_MAX_TOTAL_SIZE); + *outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE); retval = 0; break; /* mandatory */ case OID_GEN_MEDIA_CONNECT_STATUS: - DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__); + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .media_state); retval = 0; break; case OID_GEN_PHYSICAL_MEDIUM: DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; @@ -266,8 +343,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) */ case OID_GEN_MAC_OPTIONS: /* from WinME */ DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32( + *outbuf = __constant_cpu_to_le32( NDIS_MAC_OPTION_RECEIVE_SERIALIZED | NDIS_MAC_OPTION_FULL_DUPLEX); retval = 0; @@ -277,62 +353,49 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_GEN_XMIT_OK: - DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].stats->tx_packets - rndis_per_dev_params [configNr].stats->tx_errors - rndis_per_dev_params [configNr].stats->tx_dropped); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; /* mandatory */ case OID_GEN_RCV_OK: - DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].stats->rx_packets - rndis_per_dev_params [configNr].stats->rx_errors - rndis_per_dev_params [configNr].stats->rx_dropped); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; /* mandatory */ case OID_GEN_XMIT_ERROR: - DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__); + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_errors); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; /* mandatory */ case OID_GEN_RCV_ERROR: - DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__); + if (rndis_debug > 1) + DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_errors); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; @@ -340,13 +403,9 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_GEN_RCV_NO_BUFFER: DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_dropped); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; @@ -359,8 +418,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) * divided by weight of Alpha Centauri */ if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( (rndis_per_dev_params [configNr] .stats->tx_packets - rndis_per_dev_params [configNr] @@ -369,9 +427,6 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) .stats->tx_dropped) * 123); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; @@ -379,8 +434,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__); /* dito */ if (rndis_per_dev_params [configNr].stats) { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( + *outbuf = cpu_to_le32 ( (rndis_per_dev_params [configNr] .stats->tx_packets - rndis_per_dev_params [configNr] @@ -389,144 +443,105 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) .stats->tx_dropped) / 123); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_MULTICAST_BYTES_XMIT: DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast*1234); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_MULTICAST_FRAMES_XMIT: DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_BROADCAST_BYTES_XMIT: DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_packets/42*255); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_BROADCAST_FRAMES_XMIT: DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_packets/42); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_DIRECTED_BYTES_RCV: DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__); - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; case OID_GEN_DIRECTED_FRAMES_RCV: DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__); - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; case OID_GEN_MULTICAST_BYTES_RCV: DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast * 1111); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_MULTICAST_FRAMES_RCV: DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_BROADCAST_BYTES_RCV: DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_packets/42*255); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_BROADCAST_FRAMES_RCV: DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_packets/42); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_RCV_CRC_ERROR: DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_crc_errors); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; case OID_GEN_TRANSMIT_QUEUE_LENGTH: DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__); - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; #endif /* RNDIS_OPTIONAL_STATS */ @@ -538,13 +553,10 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { length = ETH_ALEN; - memcpy ((u8 *) resp + 24, + memcpy (outbuf, rndis_per_dev_params [configNr].host_mac, length); retval = 0; - } else { - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); - retval = 0; } break; @@ -553,7 +565,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { length = ETH_ALEN; - memcpy ((u8 *) resp + 24, + memcpy (outbuf, rndis_per_dev_params [configNr].host_mac, length); retval = 0; @@ -563,18 +575,16 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_802_3_MULTICAST_LIST: DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); - length = 4; /* Multicast base address only */ - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0xE0000000); + *outbuf = __constant_cpu_to_le32 (0xE0000000); retval = 0; break; /* mandatory */ case OID_802_3_MAXIMUM_LIST_SIZE: DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); - length = 4; /* Multicast base address only */ - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (1); + *outbuf = __constant_cpu_to_le32 (1); retval = 0; break; @@ -587,11 +597,8 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_802_3_RCV_ERROR_ALIGNMENT: DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__); - if (rndis_per_dev_params [configNr].stats) - { - length = 4; - *((__le32 *) resp + 6) = cpu_to_le32 ( - rndis_per_dev_params [configNr] + if (rndis_per_dev_params [configNr].stats) { + *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_frame_errors); retval = 0; } @@ -600,16 +607,14 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) /* mandatory */ case OID_802_3_XMIT_ONE_COLLISION: DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; /* mandatory */ case OID_802_3_XMIT_MORE_COLLISIONS: DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__); - length = 4; - *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0); + *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; @@ -655,27 +660,18 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) case OID_PNP_CAPABILITIES: DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__); - /* just PM, and remote wakeup on link status change - * (not magic packet or pattern match) - */ + /* for now, no wakeup capabilities */ length = sizeof (struct NDIS_PNP_CAPABILITIES); - memset (resp, 0, length); - { - struct NDIS_PNP_CAPABILITIES *caps = (void *) resp; - - caps->Flags = NDIS_DEVICE_WAKE_UP_ENABLE; - caps->WakeUpCapabilities.MinLinkChangeWakeUp - = NdisDeviceStateD3; - - /* FIXME then use usb_gadget_wakeup(), and - * set USB_CONFIG_ATT_WAKEUP in config desc - */ - } + memset(outbuf, 0, length); retval = 0; break; case OID_PNP_QUERY_POWER: - DEBUG("%s: OID_PNP_QUERY_POWER\n", __FUNCTION__); - /* sure, handle any power state that maps to USB suspend */ + DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__, + le32_to_cpup((__le32 *) buf) - 1); + /* only suspend is a real power state, and + * it can't be entered by OID_PNP_SET_POWER... + */ + length = 0; retval = 0; break; #endif @@ -684,11 +680,12 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) printk (KERN_WARNING "%s: query unknown OID 0x%08X\n", __FUNCTION__, OID); } + if (retval < 0) + length = 0; - resp->InformationBufferOffset = __constant_cpu_to_le32 (16); resp->InformationBufferLength = cpu_to_le32 (length); - resp->MessageLength = cpu_to_le32 (24 + length); - r->length = 24 + length; + r->length = length + sizeof *resp; + resp->MessageLength = cpu_to_le32 (r->length); return retval; } @@ -705,45 +702,40 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, if (!resp) return -ENOMEM; - DEBUG("set OID %08x value, len %d:\n", OID, buf_len); - for (i = 0; i < buf_len; i += 16) { - DEBUG ("%03d: " - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - "\n", - i, - buf[i], buf [i+1], - buf[i+2], buf[i+3], - buf[i+4], buf [i+5], - buf[i+6], buf[i+7], - buf[i+8], buf [i+9], - buf[i+10], buf[i+11], - buf[i+12], buf [i+13], - buf[i+14], buf[i+15]); + if (buf_len && rndis_debug > 1) { + DEBUG("set OID %08x value, len %d:\n", OID, buf_len); + for (i = 0; i < buf_len; i += 16) { + DEBUG ("%03d: %08x %08x %08x %08x\n", i, + le32_to_cpup((__le32 *)&buf[i]), + le32_to_cpup((__le32 *)&buf[i + 4]), + le32_to_cpup((__le32 *)&buf[i + 8]), + le32_to_cpup((__le32 *)&buf[i + 12])); + } } + params = &rndis_per_dev_params [configNr]; switch (OID) { case OID_GEN_CURRENT_PACKET_FILTER: - params = &rndis_per_dev_params [configNr]; - retval = 0; - /* FIXME use these NDIS_PACKET_TYPE_* bitflags to - * set the cdc_filter; it's not RNDIS-specific + /* these NDIS_PACKET_TYPE_* bitflags are shared with + * cdc_filter; it's not RNDIS-specific * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in: * PROMISCUOUS, DIRECTED, * MULTICAST, ALL_MULTICAST, BROADCAST */ - params->filter = le32_to_cpup((__le32 *)buf); + *params->filter = (u16) le32_to_cpup((__le32 *)buf); DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", - __FUNCTION__, params->filter); + __FUNCTION__, *params->filter); /* this call has a significant side effect: it's * what makes the packet flow start and stop, like * activating the CDC Ethernet altsetting. */ - if (params->filter) { +#ifdef RNDIS_PM +update_linkstate: +#endif + retval = 0; + if (*params->filter) { params->state = RNDIS_DATA_INITIALIZED; netif_carrier_on(params->dev); if (netif_running(params->dev)) @@ -776,21 +768,34 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, #ifdef RNDIS_PM case OID_PNP_SET_POWER: - DEBUG ("OID_PNP_SET_POWER\n"); - /* sure, handle any power state that maps to USB suspend */ - retval = 0; - break; - - case OID_PNP_ENABLE_WAKE_UP: - /* always-connected ... */ - DEBUG ("OID_PNP_ENABLE_WAKE_UP\n"); - retval = 0; + /* The only real power state is USB suspend, and RNDIS requests + * can't enter it; this one isn't really about power. After + * resuming, Windows forces a reset, and then SET_POWER D0. + * FIXME ... then things go batty; Windows wedges itself. + */ + i = le32_to_cpup((__force __le32 *)buf); + DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1); + switch (i) { + case NdisDeviceStateD0: + *params->filter = params->saved_filter; + goto update_linkstate; + case NdisDeviceStateD3: + case NdisDeviceStateD2: + case NdisDeviceStateD1: + params->saved_filter = *params->filter; + retval = 0; + break; + } break; - // no PM resume patterns supported (specified where?) - // so OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN always fails +#ifdef RNDIS_WAKEUP + // no wakeup support advertised, so wakeup OIDs always fail: + // - OID_PNP_ENABLE_WAKE_UP + // - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN #endif +#endif /* RNDIS_PM */ + default: printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n", __FUNCTION__, OID, buf_len); @@ -811,13 +816,10 @@ static int rndis_init_response (int configNr, rndis_init_msg_type *buf) if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP; r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type)); - - if (!r) return -ENOMEM; - + if (!r) + return -ENOMEM; resp = (rndis_init_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; - resp->MessageType = __constant_cpu_to_le32 ( REMOTE_NDIS_INITIALIZE_CMPLT); resp->MessageLength = __constant_cpu_to_le32 (52); @@ -857,20 +859,22 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf) * oid_supported_list is the largest answer */ r = rndis_add_response (configNr, sizeof (oid_supported_list)); - - if (!r) return -ENOMEM; + if (!r) + return -ENOMEM; resp = (rndis_query_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; - resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT); - resp->MessageLength = __constant_cpu_to_le32 (24); resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ - - if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), r)) { + + if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), + le32_to_cpu(buf->InformationBufferOffset) + + 8 + (u8 *) buf, + le32_to_cpu(buf->InformationBufferLength), + r)) { /* OID not supported */ resp->Status = __constant_cpu_to_le32 ( RNDIS_STATUS_NOT_SUPPORTED); + resp->MessageLength = __constant_cpu_to_le32 (sizeof *resp); resp->InformationBufferLength = __constant_cpu_to_le32 (0); resp->InformationBufferOffset = __constant_cpu_to_le32 (0); } else @@ -889,10 +893,9 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf) rndis_resp_t *r; r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type)); - - if (!r) return -ENOMEM; + if (!r) + return -ENOMEM; resp = (rndis_set_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; BufLength = le32_to_cpu (buf->InformationBufferLength); BufOffset = le32_to_cpu (buf->InformationBufferOffset); @@ -930,10 +933,9 @@ static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf) rndis_resp_t *r; r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type)); - - if (!r) return -ENOMEM; + if (!r) + return -ENOMEM; resp = (rndis_reset_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT); resp->MessageLength = __constant_cpu_to_le32 (16); @@ -957,8 +959,9 @@ static int rndis_keepalive_response (int configNr, /* host "should" check only in RNDIS_DATA_INITIALIZED state */ r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type)); + if (!r) + return -ENOMEM; resp = (rndis_keepalive_cmplt_type *) r->buf; - if (!resp) return -ENOMEM; resp->MessageType = __constant_cpu_to_le32 ( REMOTE_NDIS_KEEPALIVE_CMPLT); @@ -987,10 +990,9 @@ static int rndis_indicate_status_msg (int configNr, u32 status) r = rndis_add_response (configNr, sizeof (rndis_indicate_status_msg_type)); - if (!r) return -ENOMEM; - + if (!r) + return -ENOMEM; resp = (rndis_indicate_status_msg_type *) r->buf; - if (!resp) return -ENOMEM; resp->MessageType = __constant_cpu_to_le32 ( REMOTE_NDIS_INDICATE_STATUS_MSG); @@ -1021,6 +1023,15 @@ int rndis_signal_disconnect (int configNr) RNDIS_STATUS_MEDIA_DISCONNECT); } +void rndis_uninit (int configNr) +{ + if (configNr >= RNDIS_MAX_CONFIGS) + return; + rndis_per_dev_params [configNr].used = 0; + rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED; + return; +} + void rndis_set_host_mac (int configNr, const u8 *addr) { rndis_per_dev_params [configNr].host_mac = addr; @@ -1046,9 +1057,13 @@ int rndis_msg_parser (u8 configNr, u8 *buf) return -ENOTSUPP; params = &rndis_per_dev_params [configNr]; + /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for + * rx/tx statistics and link status, in addition to KEEPALIVE traffic + * and normal HC level polling to see if there's any IN traffic. + */ + /* For USB: responses may take up to 10 seconds */ - switch (MsgType) - { + switch (MsgType) { case REMOTE_NDIS_INITIALIZE_MSG: DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", __FUNCTION__ ); @@ -1082,10 +1097,9 @@ int rndis_msg_parser (u8 configNr, u8 *buf) case REMOTE_NDIS_KEEPALIVE_MSG: /* For USB: host does this every 5 seconds */ -#ifdef VERBOSE - DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", - __FUNCTION__ ); -#endif + if (rndis_debug > 1) + DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", + __FUNCTION__ ); return rndis_keepalive_response (configNr, (rndis_keepalive_msg_type *) buf); @@ -1152,7 +1166,8 @@ void rndis_deregister (int configNr) } int rndis_set_param_dev (u8 configNr, struct net_device *dev, - struct net_device_stats *stats) + struct net_device_stats *stats, + u16 *cdc_filter) { DEBUG("%s:\n", __FUNCTION__ ); if (!dev || !stats) return -1; @@ -1160,6 +1175,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev, rndis_per_dev_params [configNr].dev = dev; rndis_per_dev_params [configNr].stats = stats; + rndis_per_dev_params [configNr].filter = cdc_filter; return 0; } @@ -1178,7 +1194,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr) int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed) { - DEBUG("%s:\n", __FUNCTION__ ); + DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed); if (configNr >= RNDIS_MAX_CONFIGS) return -1; rndis_per_dev_params [configNr].medium = medium; @@ -1242,6 +1258,7 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length) { rndis_resp_t *r; + /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */ r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC); if (!r) return NULL; diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h index 2b5b55df3cfd..95b4c6326100 100644 --- a/drivers/usb/gadget/rndis.h +++ b/drivers/usb/gadget/rndis.h @@ -69,90 +69,6 @@ #define OID_PNP_ENABLE_WAKE_UP 0xFD010106 -/* supported OIDs */ -static const u32 oid_supported_list [] = -{ - /* the general stuff */ - OID_GEN_SUPPORTED_LIST, - OID_GEN_HARDWARE_STATUS, - OID_GEN_MEDIA_SUPPORTED, - OID_GEN_MEDIA_IN_USE, - OID_GEN_MAXIMUM_FRAME_SIZE, - OID_GEN_LINK_SPEED, - OID_GEN_TRANSMIT_BLOCK_SIZE, - OID_GEN_RECEIVE_BLOCK_SIZE, - OID_GEN_VENDOR_ID, - OID_GEN_VENDOR_DESCRIPTION, - OID_GEN_VENDOR_DRIVER_VERSION, - OID_GEN_CURRENT_PACKET_FILTER, - OID_GEN_MAXIMUM_TOTAL_SIZE, - OID_GEN_MEDIA_CONNECT_STATUS, - OID_GEN_PHYSICAL_MEDIUM, -#if 0 - OID_GEN_RNDIS_CONFIG_PARAMETER, -#endif - - /* the statistical stuff */ - OID_GEN_XMIT_OK, - OID_GEN_RCV_OK, - OID_GEN_XMIT_ERROR, - OID_GEN_RCV_ERROR, - OID_GEN_RCV_NO_BUFFER, -#ifdef RNDIS_OPTIONAL_STATS - OID_GEN_DIRECTED_BYTES_XMIT, - OID_GEN_DIRECTED_FRAMES_XMIT, - OID_GEN_MULTICAST_BYTES_XMIT, - OID_GEN_MULTICAST_FRAMES_XMIT, - OID_GEN_BROADCAST_BYTES_XMIT, - OID_GEN_BROADCAST_FRAMES_XMIT, - OID_GEN_DIRECTED_BYTES_RCV, - OID_GEN_DIRECTED_FRAMES_RCV, - OID_GEN_MULTICAST_BYTES_RCV, - OID_GEN_MULTICAST_FRAMES_RCV, - OID_GEN_BROADCAST_BYTES_RCV, - OID_GEN_BROADCAST_FRAMES_RCV, - OID_GEN_RCV_CRC_ERROR, - OID_GEN_TRANSMIT_QUEUE_LENGTH, -#endif /* RNDIS_OPTIONAL_STATS */ - - /* mandatory 802.3 */ - /* the general stuff */ - OID_802_3_PERMANENT_ADDRESS, - OID_802_3_CURRENT_ADDRESS, - OID_802_3_MULTICAST_LIST, - OID_802_3_MAC_OPTIONS, - OID_802_3_MAXIMUM_LIST_SIZE, - - /* the statistical stuff */ - OID_802_3_RCV_ERROR_ALIGNMENT, - OID_802_3_XMIT_ONE_COLLISION, - OID_802_3_XMIT_MORE_COLLISIONS, -#ifdef RNDIS_OPTIONAL_STATS - OID_802_3_XMIT_DEFERRED, - OID_802_3_XMIT_MAX_COLLISIONS, - OID_802_3_RCV_OVERRUN, - OID_802_3_XMIT_UNDERRUN, - OID_802_3_XMIT_HEARTBEAT_FAILURE, - OID_802_3_XMIT_TIMES_CRS_LOST, - OID_802_3_XMIT_LATE_COLLISIONS, -#endif /* RNDIS_OPTIONAL_STATS */ - -#ifdef RNDIS_PM - /* PM and wakeup are mandatory for USB: */ - - /* power management */ - OID_PNP_CAPABILITIES, - OID_PNP_QUERY_POWER, - OID_PNP_SET_POWER, - - /* wake up host */ - OID_PNP_ENABLE_WAKE_UP, - OID_PNP_ADD_WAKE_UP_PATTERN, - OID_PNP_REMOVE_WAKE_UP_PATTERN, -#endif -}; - - typedef struct rndis_init_msg_type { __le32 MessageType; @@ -309,15 +225,18 @@ typedef struct rndis_resp_t typedef struct rndis_params { u8 confignr; - int used; + u8 used; + u16 saved_filter; enum rndis_state state; - u32 filter; u32 medium; u32 speed; u32 media_state; + const u8 *host_mac; + u16 *filter; struct net_device *dev; struct net_device_stats *stats; + u32 vendorID; const char *vendorDescr; int (*ack) (struct net_device *); @@ -329,7 +248,8 @@ int rndis_msg_parser (u8 configNr, u8 *buf); int rndis_register (int (*rndis_control_ack) (struct net_device *)); void rndis_deregister (int configNr); int rndis_set_param_dev (u8 configNr, struct net_device *dev, - struct net_device_stats *stats); + struct net_device_stats *stats, + u16 *cdc_filter); int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr); int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed); @@ -338,6 +258,7 @@ int rndis_rm_hdr (struct sk_buff *skb); u8 *rndis_get_next_response (int configNr, u32 *length); void rndis_free_response (int configNr, u8 *buf); +void rndis_uninit (int configNr); int rndis_signal_connect (int configNr); int rndis_signal_disconnect (int configNr); int rndis_state (int configNr); -- cgit v1.2.3 From 907cba35f7f24587f0eff60073e1f4e1e01c976d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 28 Apr 2005 13:48:09 -0700 Subject: [PATCH] USB: ethernet gadget updates (mostly cleanup) Some cleanup for the the Ethernet part of the Ethernet/RNDIS gadget driver: - Remove remnants of ancient endpoint init logic; this is simpler, clearer - Save a smidgeon of space in the object file - Get rid of some #ifdeffery, mostly by using some newish inlines - Reset more driver state as part of USB reset - Remove a needless wrapper around an RNDIS call - Improve and comment the status interrupt handling: * RNDIS sometimes needs to queue these transfers (rarely in normal cases, but reproducibly while Windows was deadlocking its USB stack) * Mark requests as busy/not - Enable the SET_NETDEV_DEV() call; sysfs seems to behave sanely now This is a net shrink of source code. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 287 +++++++++++++++++---------------------------- 1 file changed, 107 insertions(+), 180 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index a766c29c3ec9..3830a0a0fd50 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -84,7 +84,7 @@ */ #define DRIVER_DESC "Ethernet Gadget" -#define DRIVER_VERSION "Equinox 2004" +#define DRIVER_VERSION "May Day 2005" static const char shortname [] = "ether"; static const char driver_desc [] = DRIVER_DESC; @@ -141,9 +141,6 @@ struct eth_dev { * It also ASSUMES a self-powered device, without remote wakeup, * although remote wakeup support would make sense. */ -static const char *EP_IN_NAME; -static const char *EP_OUT_NAME; -static const char *EP_STATUS_NAME; /*-------------------------------------------------------------------------*/ @@ -313,6 +310,7 @@ static inline int rndis_active(struct eth_dev *dev) #define FS_BPS (19 * 64 * 1 * 1000 * 8) #ifdef CONFIG_USB_GADGET_DUALSPEED +#define DEVSPEED USB_SPEED_HIGH static unsigned qmult = 5; module_param (qmult, uint, S_IRUGO|S_IWUSR); @@ -331,6 +329,8 @@ static inline int BITRATE(struct usb_gadget *g) } #else /* full speed (low speed doesn't do bulk) */ +#define DEVSPEED USB_SPEED_FULL + #define qlen(gadget) DEFAULT_QLEN static inline int BITRATE(struct usb_gadget *g) @@ -540,7 +540,7 @@ static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = { .bDataInterface = 0x01, }; -static struct usb_cdc_acm_descriptor acm_descriptor = { +static const struct usb_cdc_acm_descriptor acm_descriptor = { .bLength = sizeof acm_descriptor, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_ACM_TYPE, @@ -848,7 +848,7 @@ static const struct usb_descriptor_header *hs_rndis_function [] = { #else /* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) fs +#define ep_desc(g,hs,fs) (((void)(g)), (fs)) static inline void __init hs_subset_descriptors(void) { @@ -948,10 +948,31 @@ config_buf (enum usb_device_speed speed, static void eth_start (struct eth_dev *dev, int gfp_flags); static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags); -#ifdef DEV_CONFIG_CDC -static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep) +static int +set_ether_config (struct eth_dev *dev, int gfp_flags) { - const struct usb_endpoint_descriptor *d; + int result = 0; + struct usb_gadget *gadget = dev->gadget; + + /* status endpoint used for RNDIS and (optionally) CDC */ + if (!subset_active(dev) && dev->status_ep) { + dev->status = ep_desc (gadget, &hs_status_desc, + &fs_status_desc); + dev->status_ep->driver_data = dev; + + result = usb_ep_enable (dev->status_ep, dev->status); + if (result != 0) { + DEBUG (dev, "enable %s --> %d\n", + dev->status_ep->name, result); + goto done; + } + } + + dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); + dev->in_ep->driver_data = dev; + + dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); + dev->out_ep->driver_data = dev; /* With CDC, the host isn't allowed to use these two data * endpoints in the default altsetting for the interface. @@ -961,135 +982,33 @@ static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep) * a side effect of setting a packet filter. Deactivation is * from REMOTE_NDIS_HALT_MSG, reset from REMOTE_NDIS_RESET_MSG. */ - - /* one endpoint writes data back IN to the host */ - if (strcmp (ep->name, EP_IN_NAME) == 0) { - d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); - ep->driver_data = dev; - dev->in = d; - - /* one endpoint just reads OUT packets */ - } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { - d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); - ep->driver_data = dev; - dev->out = d; - - /* optional status/notification endpoint */ - } else if (EP_STATUS_NAME && - strcmp (ep->name, EP_STATUS_NAME) == 0) { - int result; - - d = ep_desc (dev->gadget, &hs_status_desc, &fs_status_desc); - result = usb_ep_enable (ep, d); - if (result < 0) - return result; - - ep->driver_data = dev; - dev->status = d; - } - return 0; -} -#endif - -#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) -static inline int ether_ep_setup (struct eth_dev *dev, struct usb_ep *ep) -{ - int result; - const struct usb_endpoint_descriptor *d; - - /* CDC subset is simpler: if the device is there, - * it's live with rx and tx endpoints. - * - * Do this as a shortcut for RNDIS too. - */ - - /* one endpoint writes data back IN to the host */ - if (strcmp (ep->name, EP_IN_NAME) == 0) { - d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); - result = usb_ep_enable (ep, d); - if (result < 0) - return result; - - ep->driver_data = dev; - dev->in = d; - - /* one endpoint just reads OUT packets */ - } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { - d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); - result = usb_ep_enable (ep, d); - if (result < 0) - return result; - - ep->driver_data = dev; - dev->out = d; - } - - return 0; -} -#endif - -static int -set_ether_config (struct eth_dev *dev, int gfp_flags) -{ - int result = 0; - struct usb_ep *ep; - struct usb_gadget *gadget = dev->gadget; - - gadget_for_each_ep (ep, gadget) { -#ifdef DEV_CONFIG_CDC - if (!dev->rndis && dev->cdc) { - result = ether_alt_ep_setup (dev, ep); - if (result == 0) - continue; + if (!cdc_active(dev)) { + result = usb_ep_enable (dev->in_ep, dev->in); + if (result != 0) { + DEBUG(dev, "enable %s --> %d\n", + dev->in_ep->name, result); + goto done; } -#endif -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis && strcmp (ep->name, EP_STATUS_NAME) == 0) { - const struct usb_endpoint_descriptor *d; - d = ep_desc (gadget, &hs_status_desc, &fs_status_desc); - result = usb_ep_enable (ep, d); - if (result == 0) { - ep->driver_data = dev; - dev->status = d; - continue; - } - } else -#endif - - { -#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) - result = ether_ep_setup (dev, ep); - if (result == 0) - continue; -#endif + result = usb_ep_enable (dev->out_ep, dev->out); + if (result != 0) { + DEBUG (dev, "enable %s --> %d\n", + dev->in_ep->name, result); + goto done; } - - /* stop on error */ - ERROR (dev, "can't enable %s, result %d\n", ep->name, result); - break; } - if (!result && (!dev->in_ep || !dev->out_ep)) - result = -ENODEV; +done: if (result == 0) result = alloc_requests (dev, qlen (gadget), gfp_flags); /* on error, disable any endpoints */ if (result < 0) { -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (dev->status) + if (!subset_active(dev)) (void) usb_ep_disable (dev->status_ep); -#endif dev->status = NULL; -#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) - if (dev->rndis || !dev->cdc) { - if (dev->in) - (void) usb_ep_disable (dev->in_ep); - if (dev->out) - (void) usb_ep_disable (dev->out_ep); - } -#endif + (void) usb_ep_disable (dev->in_ep); + (void) usb_ep_disable (dev->out_ep); dev->in = NULL; dev->out = NULL; } else @@ -1097,8 +1016,7 @@ set_ether_config (struct eth_dev *dev, int gfp_flags) /* activate non-CDC configs right away * this isn't strictly according to the RNDIS spec */ -#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) - if (dev->rndis || !dev->cdc) { + if (!cdc_active (dev)) { netif_carrier_on (dev->net); if (netif_running (dev->net)) { spin_unlock (&dev->lock); @@ -1106,7 +1024,6 @@ set_ether_config (struct eth_dev *dev, int gfp_flags) spin_lock (&dev->lock); } } -#endif if (result == 0) DEBUG (dev, "qlen %d\n", qlen (gadget)); @@ -1153,6 +1070,8 @@ static void eth_reset_config (struct eth_dev *dev) if (dev->status) { usb_ep_disable (dev->status_ep); } + dev->rndis = 0; + dev->cdc_filter = 0; dev->config = 0; } @@ -1165,9 +1084,6 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) int result = 0; struct usb_gadget *gadget = dev->gadget; - if (number == dev->config) - return 0; - if (gadget_is_sa1100 (gadget) && dev->config && atomic_read (&dev->tx_qlen) != 0) { @@ -1177,12 +1093,8 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) } eth_reset_config (dev); - /* default: pass all packets, no multicast filtering */ - dev->cdc_filter = DEFAULT_FILTER; - switch (number) { case DEV_CONFIG_VALUE: - dev->rndis = 0; result = set_ether_config (dev, gfp_flags); break; #ifdef CONFIG_USB_ETH_RNDIS @@ -1234,6 +1146,13 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) #ifdef DEV_CONFIG_CDC +/* The interrupt endpoint is used in CDC networking models (Ethernet, ATM) + * only to notify the host about link status changes (which we support) or + * report completion of some encapsulated command (as used in RNDIS). Since + * we want this CDC Ethernet code to be vendor-neutral, we don't use that + * command mechanism; and only one status request is ever queued. + */ + static void eth_status_complete (struct usb_ep *ep, struct usb_request *req) { struct usb_cdc_notification *event = req->buf; @@ -1262,7 +1181,7 @@ static void eth_status_complete (struct usb_ep *ep, struct usb_request *req) } else if (value != -ECONNRESET) DEBUG (dev, "event %02x --> %d\n", event->bNotificationType, value); - event->bmRequestType = 0xff; + req->context = NULL; } static void issue_start_status (struct eth_dev *dev) @@ -1279,6 +1198,8 @@ static void issue_start_status (struct eth_dev *dev) * a "cancel the whole queue" primitive since any * unlink-one primitive has way too many error modes. * here, we "know" toggle is already clear... + * + * FIXME iff req->context != null just dequeue it */ usb_ep_disable (dev->status_ep); usb_ep_enable (dev->status_ep, dev->status); @@ -1295,6 +1216,8 @@ static void issue_start_status (struct eth_dev *dev) req->length = sizeof *event; req->complete = eth_status_complete; + req->context = dev; + value = usb_ep_queue (dev->status_ep, req, GFP_ATOMIC); if (value < 0) DEBUG (dev, "status buf queue --> %d\n", value); @@ -1459,9 +1382,11 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) /* CDC requires the data transfers not be done from * the default interface setting ... also, setting - * the non-default interface clears filters etc. + * the non-default interface resets filters etc. */ if (wValue == 1) { + if (!cdc_active (dev)) + break; usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); dev->cdc_filter = DEFAULT_FILTER; @@ -1691,10 +1616,8 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) */ size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA); size += dev->out_ep->maxpacket - 1; -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis) + if (rndis_active(dev)) size += sizeof (struct rndis_packet_msg_type); -#endif size -= size % dev->out_ep->maxpacket; if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) { @@ -1862,8 +1785,6 @@ static void rx_fill (struct eth_dev *dev, int gfp_flags) struct usb_request *req; unsigned long flags; - clear_bit (WORK_RX_MEMORY, &dev->todo); - /* fill unused rxq slots with some skb */ spin_lock_irqsave (&dev->lock, flags); while (!list_empty (&dev->rx_reqs)) { @@ -1886,11 +1807,9 @@ static void eth_work (void *_dev) { struct eth_dev *dev = _dev; - if (test_bit (WORK_RX_MEMORY, &dev->todo)) { + if (test_and_clear_bit (WORK_RX_MEMORY, &dev->todo)) { if (netif_running (dev->net)) rx_fill (dev, GFP_KERNEL); - else - clear_bit (WORK_RX_MEMORY, &dev->todo); } if (dev->todo) @@ -2039,27 +1958,31 @@ drop: #ifdef CONFIG_USB_ETH_RNDIS -static void rndis_send_media_state (struct eth_dev *dev, int connect) -{ - if (!dev) - return; - - if (connect) { - if (rndis_signal_connect (dev->rndis_config)) - return; - } else { - if (rndis_signal_disconnect (dev->rndis_config)) - return; - } -} +/* The interrupt endpoint is used in RNDIS to notify the host when messages + * other than data packets are available ... notably the REMOTE_NDIS_*_CMPLT + * messages, but also REMOTE_NDIS_INDICATE_STATUS_MSG and potentially even + * REMOTE_NDIS_KEEPALIVE_MSG. + * + * The RNDIS control queue is processed by GET_ENCAPSULATED_RESPONSE, and + * normally just one notification will be queued. + */ + +static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, unsigned); +static void eth_req_free (struct usb_ep *ep, struct usb_request *req); static void rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req) { + struct eth_dev *dev = ep->driver_data; + if (req->status || req->actual != req->length) - DEBUG ((struct eth_dev *) ep->driver_data, + DEBUG (dev, "rndis control ack complete --> %d, %d/%d\n", req->status, req->actual, req->length); + req->context = NULL; + + if (req != dev->stat_req) + eth_req_free(ep, req); } static int rndis_control_ack (struct net_device *net) @@ -2074,11 +1997,19 @@ static int rndis_control_ack (struct net_device *net) return -ENODEV; } + /* in case queue length > 1 */ + if (resp->context) { + resp = eth_req_alloc (dev->status_ep, 8, GFP_ATOMIC); + if (!resp) + return -ENOMEM; + } + /* Send RNDIS RESPONSE_AVAILABLE notification; * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too */ resp->length = 8; resp->complete = rndis_control_ack_complete; + resp->context = dev; *((__le32 *) resp->buf) = __constant_cpu_to_le32 (1); *((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0); @@ -2109,7 +2040,7 @@ static void eth_start (struct eth_dev *dev, int gfp_flags) rndis_set_param_medium (dev->rndis_config, NDIS_MEDIUM_802_3, BITRATE(dev->gadget)/100); - rndis_send_media_state (dev, 1); + (void) rndis_signal_connect (dev->rndis_config); } #endif } @@ -2156,7 +2087,7 @@ static int eth_stop (struct net_device *net) if (dev->rndis) { rndis_set_param_medium (dev->rndis_config, NDIS_MEDIUM_802_3, 0); - rndis_send_media_state (dev, 0); + (void) rndis_signal_disconnect (dev->rndis_config); } #endif @@ -2165,15 +2096,16 @@ static int eth_stop (struct net_device *net) /*-------------------------------------------------------------------------*/ -static struct usb_request *eth_req_alloc (struct usb_ep *ep, unsigned size) +static struct usb_request * +eth_req_alloc (struct usb_ep *ep, unsigned size, unsigned gfp_flags) { struct usb_request *req; - req = usb_ep_alloc_request (ep, GFP_KERNEL); + req = usb_ep_alloc_request (ep, gfp_flags); if (!req) return NULL; - req->buf = kmalloc (size, GFP_KERNEL); + req->buf = kmalloc (size, gfp_flags); if (!req->buf) { usb_ep_free_request (ep, req); req = NULL; @@ -2371,13 +2303,11 @@ autoconf_fail: gadget->name); return -ENODEV; } - EP_IN_NAME = in_ep->name; in_ep->driver_data = in_ep; /* claim */ out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc); if (!out_ep) goto autoconf_fail; - EP_OUT_NAME = out_ep->name; out_ep->driver_data = out_ep; /* claim */ #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) @@ -2387,7 +2317,6 @@ autoconf_fail: if (cdc || rndis) { status_ep = usb_ep_autoconfig (gadget, &fs_status_desc); if (status_ep) { - EP_STATUS_NAME = status_ep->name; status_ep->driver_data = status_ep; /* claim */ } else if (rndis) { dev_err (&gadget->dev, @@ -2429,7 +2358,7 @@ autoconf_fail: hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (EP_STATUS_NAME) + if (status_ep) hs_status_desc.bEndpointAddress = fs_status_desc.bEndpointAddress; #endif @@ -2502,7 +2431,7 @@ autoconf_fail: SET_ETHTOOL_OPS(net, &ops); /* preallocate control message data and buffer */ - dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ); + dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ, GFP_KERNEL); if (!dev->req) goto fail; dev->req->complete = eth_setup_complete; @@ -2510,11 +2439,12 @@ autoconf_fail: /* ... and maybe likewise for status transfer */ if (dev->status_ep) { dev->stat_req = eth_req_alloc (dev->status_ep, - STATUS_BYTECOUNT); + STATUS_BYTECOUNT, GFP_KERNEL); if (!dev->stat_req) { eth_req_free (gadget->ep0, dev->req); goto fail; } + dev->stat_req->context = NULL; } /* finish hookup to lower layer ... */ @@ -2529,16 +2459,16 @@ autoconf_fail: netif_stop_queue (dev->net); netif_carrier_off (dev->net); - // SET_NETDEV_DEV (dev->net, &gadget->dev); + SET_NETDEV_DEV (dev->net, &gadget->dev); status = register_netdev (dev->net); if (status < 0) goto fail1; INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); INFO (dev, "using %s, OUT %s IN %s%s%s\n", gadget->name, - EP_OUT_NAME, EP_IN_NAME, - EP_STATUS_NAME ? " STATUS " : "", - EP_STATUS_NAME ? EP_STATUS_NAME : "" + out_ep->name, in_ep->name, + status_ep ? " STATUS " : "", + status_ep ? status_ep->name : "" ); INFO (dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", net->dev_addr [0], net->dev_addr [1], @@ -2613,11 +2543,8 @@ eth_resume (struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver eth_driver = { -#ifdef CONFIG_USB_GADGET_DUALSPEED - .speed = USB_SPEED_HIGH, -#else - .speed = USB_SPEED_FULL, -#endif + .speed = DEVSPEED, + .function = (char *) driver_desc, .bind = eth_bind, .unbind = eth_unbind, -- cgit v1.2.3 From 65111084c63d7674dc37833e8eb59cfdaa4d0bda Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 28 Apr 2005 13:52:31 -0700 Subject: [PATCH] USB: more omap_udc updates (dma and omap1710) More omap_udc updates: * OMAP 1710 updates - new UDC bit for clearing endpoint toggle, affecting CLEAR_HALT - new OTG bits affecting wakeup * Fix the bug Vladimir noted, that IN-DMA transfer code path kicks in for under 1024 bytes (not "up to 1024 bytes") * Handle transceiver setup more intelligently - use transceiver whenever one's available; this can be handy for GPIO based, loopback, or transceiverless configs - cleanup correctly after the "unrecognized HMC" case * DMA performance tweaks - allow burst/pack for memory access - use 16 bit DMA access most of the time on TIPB * Add workarounds for some DMA errata (not observed "in the wild"): - DMA CSAC/CDAC reads returning zero - RX/TX DMA config registers bit 12 always reads as zero (TI patch) * More "sparse" warnings removed, notably "changing" the SETUP packet to return data in USB byteorder (an API change, null effect on OMAP except for these warnings). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/omap_udc.c | 153 +++++++++++++++++++++++++++++----------- drivers/usb/gadget/omap_udc.h | 4 +- include/asm-arm/arch-omap/usb.h | 9 +++ 3 files changed, 125 insertions(+), 41 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 4ec91a68f96c..a2b812af6e66 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -166,7 +166,7 @@ static int omap_ep_enable(struct usb_ep *_ep, maxp = le16_to_cpu (desc->wMaxPacketSize); if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK && maxp != ep->maxpacket) - || desc->wMaxPacketSize > ep->maxpacket + || le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket || !desc->wMaxPacketSize) { DBG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name); return -ERANGE; @@ -213,7 +213,7 @@ static int omap_ep_enable(struct usb_ep *_ep, ep->has_dma = 0; ep->lch = -1; use_ep(ep, UDC_EP_SEL); - UDC_CTRL_REG = UDC_RESET_EP; + UDC_CTRL_REG = udc->clr_halt; ep->ackwait = 0; deselect_ep(); @@ -537,6 +537,32 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req) /*-------------------------------------------------------------------------*/ +static inline dma_addr_t dma_csac(unsigned lch) +{ + dma_addr_t csac; + + /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is + * read before the DMA controller finished disabling the channel. + */ + csac = omap_readw(OMAP_DMA_CSAC(lch)); + if (csac == 0) + csac = omap_readw(OMAP_DMA_CSAC(lch)); + return csac; +} + +static inline dma_addr_t dma_cdac(unsigned lch) +{ + dma_addr_t cdac; + + /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is + * read before the DMA controller finished disabling the channel. + */ + cdac = omap_readw(OMAP_DMA_CDAC(lch)); + if (cdac == 0) + cdac = omap_readw(OMAP_DMA_CDAC(lch)); + return cdac; +} + static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start) { dma_addr_t end; @@ -547,7 +573,7 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start) if (cpu_is_omap15xx()) return 0; - end = omap_readw(OMAP_DMA_CSAC(ep->lch)); + end = dma_csac(ep->lch); if (end == ep->dma_counter) return 0; @@ -558,14 +584,14 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start) } #define DMA_DEST_LAST(x) (cpu_is_omap15xx() \ - ? OMAP_DMA_CSAC(x) /* really: CPC */ \ - : OMAP_DMA_CDAC(x)) + ? omap_readw(OMAP_DMA_CSAC(x)) /* really: CPC */ \ + : dma_cdac(x)) static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start) { dma_addr_t end; - end = omap_readw(DMA_DEST_LAST(ep->lch)); + end = DMA_DEST_LAST(ep->lch); if (end == ep->dma_counter) return 0; @@ -592,7 +618,7 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req) : OMAP_DMA_SYNC_ELEMENT; /* measure length in either bytes or packets */ - if ((cpu_is_omap16xx() && length <= (UDC_TXN_TSC + 1)) + if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC) || (cpu_is_omap15xx() && length < ep->maxpacket)) { txdma_ctrl = UDC_TXN_EOT | length; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, @@ -601,15 +627,15 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req) length = min(length / ep->maxpacket, (unsigned) UDC_TXN_TSC + 1); txdma_ctrl = length; - omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, - ep->ep.maxpacket, length, sync_mode); + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, + ep->ep.maxpacket >> 1, length, sync_mode); length *= ep->maxpacket; } omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); omap_start_dma(ep->lch); - ep->dma_counter = omap_readw(OMAP_DMA_CSAC(ep->lch)); + ep->dma_counter = dma_csac(ep->lch); UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel); UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl; req->dma_bytes = length; @@ -649,12 +675,12 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req) packets = (req->req.length - req->req.actual) / ep->ep.maxpacket; packets = min(packets, (unsigned)UDC_RXN_TC + 1); req->dma_bytes = packets * ep->ep.maxpacket; - omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, - ep->ep.maxpacket, packets, + omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, + ep->ep.maxpacket >> 1, packets, OMAP_DMA_SYNC_ELEMENT); omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual); - ep->dma_counter = omap_readw(DMA_DEST_LAST(ep->lch)); + ep->dma_counter = DMA_DEST_LAST(ep->lch); UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1); UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel); @@ -762,7 +788,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) reg = UDC_TXDMA_CFG_REG; else reg = UDC_RXDMA_CFG_REG; - reg |= 1 << 12; /* "pulse" activated */ + reg |= UDC_DMA_REQ; /* "pulse" activated */ ep->dma_channel = 0; ep->lch = -1; @@ -786,6 +812,11 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) ep->ep.name, dma_error, ep, &ep->lch); if (status == 0) { UDC_TXDMA_CFG_REG = reg; + /* EMIFF */ + omap_set_dma_src_burst_mode(ep->lch, + OMAP_DMA_DATA_BURST_4); + omap_set_dma_src_data_pack(ep->lch, 1); + /* TIPB */ omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_TIPB, OMAP_DMA_AMODE_CONSTANT, @@ -796,10 +827,15 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel) ep->ep.name, dma_error, ep, &ep->lch); if (status == 0) { UDC_RXDMA_CFG_REG = reg; + /* TIPB */ omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_TIPB, OMAP_DMA_AMODE_CONSTANT, (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG)); + /* EMIFF */ + omap_set_dma_dest_burst_mode(ep->lch, + OMAP_DMA_DATA_BURST_4); + omap_set_dma_dest_data_pack(ep->lch, 1); } } if (status) @@ -864,9 +900,13 @@ static void dma_channel_release(struct omap_ep *ep) (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r', ep->dma_channel - 1, req); + /* NOTE: re-setting RX_REQ/TX_REQ because of a chip bug (before + * OMAP 1710 ES2.0) where reading the DMA_CFG can clear them. + */ + /* wait till current packet DMA finishes, and fifo empties */ if (ep->bEndpointAddress & USB_DIR_IN) { - UDC_TXDMA_CFG_REG &= ~mask; + UDC_TXDMA_CFG_REG = (UDC_TXDMA_CFG_REG & ~mask) | UDC_DMA_REQ; if (req) { finish_in_dma(ep, req, -ECONNRESET); @@ -879,7 +919,7 @@ static void dma_channel_release(struct omap_ep *ep) while (UDC_TXDMA_CFG_REG & mask) udelay(10); } else { - UDC_RXDMA_CFG_REG &= ~mask; + UDC_RXDMA_CFG_REG = (UDC_RXDMA_CFG_REG & ~mask) | UDC_DMA_REQ; /* dma empties the fifo */ while (UDC_RXDMA_CFG_REG & mask) @@ -1140,7 +1180,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value) dma_channel_claim(ep, channel); } else { use_ep(ep, 0); - UDC_CTRL_REG = UDC_RESET_EP; + UDC_CTRL_REG = ep->udc->clr_halt; ep->ackwait = 0; if (!(ep->bEndpointAddress & USB_DIR_IN)) { UDC_CTRL_REG = UDC_SET_FIFO_EN; @@ -1514,6 +1554,10 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) UDC_EP_NUM_REG = 0; } while (UDC_IRQ_SRC_REG & UDC_SETUP); +#define w_value le16_to_cpup (&u.r.wValue) +#define w_index le16_to_cpup (&u.r.wIndex) +#define w_length le16_to_cpup (&u.r.wLength) + /* Delegate almost all control requests to the gadget driver, * except for a handful of ch9 status/feature requests that * hardware doesn't autodecode _and_ the gadget API hides. @@ -1528,11 +1572,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) /* udc needs to know when ep != 0 is valid */ if (u.r.bRequestType != USB_RECIP_DEVICE) goto delegate; - if (u.r.wLength != 0) + if (w_length != 0) goto do_stall; udc->ep0_set_config = 1; - udc->ep0_reset_config = (u.r.wValue == 0); - VDBG("set config %d\n", u.r.wValue); + udc->ep0_reset_config = (w_value == 0); + VDBG("set config %d\n", w_value); /* update udc NOW since gadget driver may start * queueing requests immediately; clear config @@ -1548,18 +1592,18 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) /* clear endpoint halt */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) + if (w_value != USB_ENDPOINT_HALT + || w_length != 0) goto do_stall; - ep = &udc->ep[u.r.wIndex & 0xf]; + ep = &udc->ep[w_index & 0xf]; if (ep != ep0) { - if (u.r.wIndex & USB_DIR_IN) + if (w_index & USB_DIR_IN) ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || !ep->desc) goto do_stall; use_ep(ep, 0); - UDC_CTRL_REG = UDC_RESET_EP; + UDC_CTRL_REG = udc->clr_halt; ep->ackwait = 0; if (!(ep->bEndpointAddress & USB_DIR_IN)) { UDC_CTRL_REG = UDC_SET_FIFO_EN; @@ -1577,11 +1621,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) /* set endpoint halt */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) + if (w_value != USB_ENDPOINT_HALT + || w_length != 0) goto do_stall; - ep = &udc->ep[u.r.wIndex & 0xf]; - if (u.r.wIndex & USB_DIR_IN) + ep = &udc->ep[w_index & 0xf]; + if (w_index & USB_DIR_IN) ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || ep == ep0 || !ep->desc) @@ -1619,13 +1663,13 @@ ep0out_status_stage: UDC_CTRL_REG = UDC_SET_FIFO_EN; UDC_EP_NUM_REG = UDC_EP_DIR; status = 0; - VDBG("GET_STATUS, interface %d\n", u.r.wIndex); + VDBG("GET_STATUS, interface %d\n", w_index); /* next, status stage */ break; default: delegate: /* activate the ep0out fifo right away */ - if (!udc->ep0_in && u.r.wLength) { + if (!udc->ep0_in && w_length) { UDC_EP_NUM_REG = 0; UDC_CTRL_REG = UDC_SET_FIFO_EN; } @@ -1636,7 +1680,11 @@ delegate: */ VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n", u.r.bRequestType, u.r.bRequest, - u.r.wValue, u.r.wIndex, u.r.wLength); + w_value, w_index, w_length); + +#undef w_value +#undef w_index +#undef w_length /* The gadget driver may return an error here, * causing an immediate protocol stall. @@ -2181,14 +2229,14 @@ static int proc_otg_show(struct seq_file *s) tmp = OTG_REV_REG; trans = USB_TRANSCEIVER_CTRL_REG; - seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %03x\n", + seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %05x\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), trans & CONF_USB2_UNI_R), trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R), - (USB0_TRX_MODE(tmp) == 0) + (USB0_TRX_MODE(tmp) == 0 && !cpu_is_omap1710()) ? "internal" : trx_mode(USB0_TRX_MODE(tmp), 1), (tmp & OTG_IDLE_EN) ? " !otg" : "", @@ -2418,6 +2466,10 @@ static inline void remove_proc_file(void) {} /* Before this controller can enumerate, we need to pick an endpoint * configuration, or "fifo_mode" That involves allocating 2KB of packet * buffer space among the endpoints we'll be operating. + * + * NOTE: as of OMAP 1710 ES2.0, writing a new endpoint config when + * UDC_SYSCON_1_REG.CFG_LOCK is set can now work. We won't use that + * capability yet though. */ static unsigned __init omap_ep_setup(char *name, u8 addr, u8 type, @@ -2690,6 +2742,19 @@ static int __init omap_udc_probe(struct device *dev) FUNC_MUX_CTRL_0_REG = tmp; } } else { + /* The transceiver may package some GPIO logic or handle + * loopback and/or transceiverless setup; if we find one, + * use it. Except for OTG, we don't _need_ to talk to one; + * but not having one probably means no VBUS detection. + */ + xceiv = otg_get_transceiver(); + if (xceiv) + type = xceiv->label; + else if (config->otg) { + DBG("OTG requires external transceiver!\n"); + goto cleanup0; + } + hmc = HMC_1610; switch (hmc) { case 0: /* POWERUP DEFAULT == 0 */ @@ -2706,25 +2771,27 @@ static int __init omap_udc_probe(struct device *dev) case 16: case 19: case 25: - xceiv = otg_get_transceiver(); if (!xceiv) { DBG("external transceiver not registered!\n"); - if (config->otg) - goto cleanup0; type = "unknown"; - } else - type = xceiv->label; + } break; case 21: /* internal loopback */ type = "loopback"; break; case 14: /* transceiverless */ + if (cpu_is_omap1710()) + goto bad_on_1710; + /* FALL THROUGH */ + case 13: + case 15: type = "no"; break; default: +bad_on_1710: ERR("unrecognized UDC HMC mode %d\n", hmc); - return -ENODEV; + goto cleanup0; } } INFO("hmc mode %d, %s transceiver\n", hmc, type); @@ -2741,6 +2808,12 @@ static int __init omap_udc_probe(struct device *dev) udc->gadget.is_otg = (config->otg != 0); #endif + /* starting with omap1710 es2.0, clear toggle is a separate bit */ + if (UDC_REV_REG >= 0x61) + udc->clr_halt = UDC_RESET_EP | UDC_CLRDATA_TOGGLE; + else + udc->clr_halt = UDC_RESET_EP; + /* USB general purpose IRQ: ep0, state changes, dma, etc */ status = request_irq(odev->resource[1].start, omap_udc_irq, SA_SAMPLE_RANDOM, driver_name, udc); diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h index c9e68541622c..652ee4627344 100644 --- a/drivers/usb/gadget/omap_udc.h +++ b/drivers/usb/gadget/omap_udc.h @@ -20,6 +20,7 @@ #define UDC_CTRL_REG UDC_REG(0x0C) /* Endpoint control */ # define UDC_CLR_HALT (1 << 7) # define UDC_SET_HALT (1 << 6) +# define UDC_CLRDATA_TOGGLE (1 << 3) # define UDC_SET_FIFO_EN (1 << 2) # define UDC_CLR_EP (1 << 1) # define UDC_RESET_EP (1 << 0) @@ -99,6 +100,7 @@ /* DMA configuration registers: up to three channels in each direction. */ #define UDC_RXDMA_CFG_REG UDC_REG(0x40) /* 3 eps for RX DMA */ +# define UDC_DMA_REQ (1 << 12) #define UDC_TXDMA_CFG_REG UDC_REG(0x44) /* 3 eps for TX DMA */ #define UDC_DATA_DMA_REG UDC_REG(0x48) /* rx/tx fifo addr */ @@ -162,6 +164,7 @@ struct omap_udc { spinlock_t lock; struct omap_ep ep[32]; u16 devstat; + u16 clr_halt; struct otg_transceiver *transceiver; struct list_head iso; unsigned softconnect:1; @@ -171,7 +174,6 @@ struct omap_udc { unsigned ep0_set_config:1; unsigned ep0_reset_config:1; unsigned ep0_setup:1; - struct completion *done; }; diff --git a/include/asm-arm/arch-omap/usb.h b/include/asm-arm/arch-omap/usb.h index 1438c6cef0ca..054fb9a8e0c6 100644 --- a/include/asm-arm/arch-omap/usb.h +++ b/include/asm-arm/arch-omap/usb.h @@ -47,6 +47,15 @@ # define HMC_TLLATTACH (1 << 6) # define OTG_HMC(w) (((w)>>0)&0x3f) #define OTG_CTRL_REG OTG_REG32(0x0c) +# define OTG_USB2_EN (1 << 29) +# define OTG_USB2_DP (1 << 28) +# define OTG_USB2_DM (1 << 27) +# define OTG_USB1_EN (1 << 26) +# define OTG_USB1_DP (1 << 25) +# define OTG_USB1_DM (1 << 24) +# define OTG_USB0_EN (1 << 23) +# define OTG_USB0_DP (1 << 22) +# define OTG_USB0_DM (1 << 21) # define OTG_ASESSVLD (1 << 20) # define OTG_BSESSEND (1 << 19) # define OTG_BSESSVLD (1 << 18) -- cgit v1.2.3 From 5742b0c95026c817d9c266174ca39a909e8d38ca Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 2 May 2005 11:25:17 -0400 Subject: [PATCH] USB dummy_hcd: Partial OTG emulation Partial OTG support for dummy_hcd, mostly as a framework for further work. It emulates the new OTG flags in the host and peripheral frameworks, if that option is configured. But it's incomplete: - Resetting the peripheral needs to clear the OTG state bits; a second enumeration won't work correctly. - This stops modeling HNP right when roles should switch the first time. It should probably disconnect, then set the usb_bus.is_b_host and usb_gadget.is_a_peripheral flags; then it'd enumerate almost normally, except for the role reversal. Roles could then switch a second time, back to "normal" (with those flags cleared). - SRP should be modeled as "resume from port-unpowered", which is a state that usbcore doesn't yet use. HNP can be triggered by enabling the OTG whitelist and configuring a gadget driver that's not in that list; or by configuring Gadget Zero to identify itself as the HNP test device. Sent-by: David Brownell Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 1918d10f7569..e9b95df5b23d 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -601,8 +601,10 @@ static int dummy_wakeup (struct usb_gadget *_gadget) struct dummy *dum; dum = gadget_to_dummy (_gadget); - if ((dum->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) == 0 - || !(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND))) + if (!(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) + || !(dum->devstatus & + ( (1 << USB_DEVICE_B_HNP_ENABLE) + | (1 << USB_DEVICE_REMOTE_WAKEUP)))) return -EINVAL; /* hub notices our request, issues downstream resume, etc */ @@ -713,6 +715,9 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) dum->gadget.ops = &dummy_ops; dum->gadget.is_dualspeed = 1; + /* maybe claim OTG support, though we won't complete HNP */ + dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0); + dum->devstatus = 0; dum->resuming = 0; @@ -1215,6 +1220,16 @@ restart: switch (setup.wValue) { case USB_DEVICE_REMOTE_WAKEUP: break; + case USB_DEVICE_B_HNP_ENABLE: + dum->gadget.b_hnp_enable = 1; + break; + case USB_DEVICE_A_HNP_SUPPORT: + dum->gadget.a_hnp_support = 1; + break; + case USB_DEVICE_A_ALT_HNP_SUPPORT: + dum->gadget.a_alt_hnp_support + = 1; + break; default: value = -EOPNOTSUPP; } @@ -1533,6 +1548,13 @@ static int dummy_hub_control ( spin_unlock (&dum->lock); dum->driver->suspend (&dum->gadget); spin_lock (&dum->lock); + /* HNP would happen here; for now we + * assume b_bus_req is always true. + */ + if (((1 << USB_DEVICE_B_HNP_ENABLE) + & dum->devstatus) != 0) + dev_dbg (dummy_dev(dum), + "no HNP yet!\n"); } } break; @@ -1648,6 +1670,10 @@ static int dummy_start (struct usb_hcd *hcd) hcd->power_budget = 8; hcd->state = HC_STATE_RUNNING; +#ifdef CONFIG_USB_OTG + hcd->self.otg_port = 1; +#endif + /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ device_create_file (dummy_dev(dum), &dev_attr_urbs); return 0; -- cgit v1.2.3 From c2db8b5e5692a6f35913a829607ee6efde3c7cbd Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 29 Apr 2005 16:30:48 -0400 Subject: [PATCH] USB: dummy_hcd: USB_PORT_FEAT changed to USB_PORT_STAT This patch makes some cosmetic changes to dummy_hcd: Minor alterations of comments and whitespace. Replace USB_PORT_FEAT_xxx with USB_PORT_STAT_xxx. This is appropriate as the values are stored in a status variable and they aren't feature indices. Also it allows the elimination of a bunch of awkward bit shift operations. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 50 +++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 27 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index e9b95df5b23d..ffedf4d1b747 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -601,7 +601,7 @@ static int dummy_wakeup (struct usb_gadget *_gadget) struct dummy *dum; dum = gadget_to_dummy (_gadget); - if (!(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) + if (!(dum->port_status & USB_PORT_STAT_SUSPEND) || !(dum->devstatus & ( (1 << USB_DEVICE_B_HNP_ENABLE) | (1 << USB_DEVICE_REMOTE_WAKEUP)))) @@ -609,7 +609,7 @@ static int dummy_wakeup (struct usb_gadget *_gadget) /* hub notices our request, issues downstream resume, etc */ dum->resuming = 1; - dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); + dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); return 0; } @@ -661,15 +661,15 @@ DEVICE_ATTR (function, S_IRUGO, show_function, NULL); * for each driver that registers: just add to a big root hub. */ +/* This doesn't need to do anything because the udc device structure is + * stored inside the hcd and will be deallocated along with it. */ static void -dummy_udc_release (struct device *dev) -{ -} +dummy_udc_release (struct device *dev) {} +/* This doesn't need to do anything because the pdev structure is + * statically allocated. */ static void -dummy_pdev_release (struct device *dev) -{ -} +dummy_pdev_release (struct device *dev) {} static int dummy_register_udc (struct dummy *dum) @@ -753,15 +753,13 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) return retval; } - // FIXME: Check these calls for errors and re-order driver->driver.bus = dum->gadget.dev.parent->bus; driver_register (&driver->driver); - device_bind_driver (&dum->gadget.dev); /* khubd will enumerate this in a while */ dum->port_status |= USB_PORT_STAT_CONNECTION - | (1 << USB_PORT_FEAT_C_CONNECTION); + | (USB_PORT_STAT_C_CONNECTION << 16); return 0; } EXPORT_SYMBOL (usb_gadget_register_driver); @@ -807,14 +805,13 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) stop_activity (dum, driver); dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); - dum->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); + dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); spin_unlock_irqrestore (&dum->lock, flags); driver->unbind (&dum->gadget); dum->driver = NULL; device_release_driver (&dum->gadget.dev); - driver_unregister (&driver->driver); return 0; @@ -1406,11 +1403,11 @@ return_urb: /*-------------------------------------------------------------------------*/ #define PORT_C_MASK \ - ((1 << USB_PORT_FEAT_C_CONNECTION) \ - | (1 << USB_PORT_FEAT_C_ENABLE) \ - | (1 << USB_PORT_FEAT_C_SUSPEND) \ - | (1 << USB_PORT_FEAT_C_OVER_CURRENT) \ - | (1 << USB_PORT_FEAT_C_RESET)) + ((USB_PORT_STAT_C_CONNECTION \ + | USB_PORT_STAT_C_ENABLE \ + | USB_PORT_STAT_C_SUSPEND \ + | USB_PORT_STAT_C_OVERCURRENT \ + | USB_PORT_STAT_C_RESET) << 16) static int dummy_hub_status (struct usb_hcd *hcd, char *buf) { @@ -1465,7 +1462,7 @@ static int dummy_hub_control ( case ClearPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - if (dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) { + if (dum->port_status & USB_PORT_STAT_SUSPEND) { /* 20msec resume signaling */ dum->resuming = 1; dum->re_timeout = jiffies + @@ -1495,8 +1492,8 @@ static int dummy_hub_control ( * complete it!! */ if (dum->resuming && time_after (jiffies, dum->re_timeout)) { - dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); - dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND); + dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); + dum->port_status &= ~USB_PORT_STAT_SUSPEND; dum->resuming = 0; dum->re_timeout = 0; if (dum->driver && dum->driver->resume) { @@ -1505,10 +1502,10 @@ static int dummy_hub_control ( spin_lock (&dum->lock); } } - if ((dum->port_status & (1 << USB_PORT_FEAT_RESET)) != 0 + if ((dum->port_status & USB_PORT_STAT_RESET) != 0 && time_after (jiffies, dum->re_timeout)) { - dum->port_status |= (1 << USB_PORT_FEAT_C_RESET); - dum->port_status &= ~(1 << USB_PORT_FEAT_RESET); + dum->port_status |= (USB_PORT_STAT_C_RESET << 16); + dum->port_status &= ~USB_PORT_STAT_RESET; dum->re_timeout = 0; if (dum->driver) { dum->port_status |= USB_PORT_STAT_ENABLE; @@ -1540,10 +1537,9 @@ static int dummy_hub_control ( case SetPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - if ((dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) + if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0) { - dum->port_status |= - (1 << USB_PORT_FEAT_SUSPEND); + dum->port_status |= USB_PORT_STAT_SUSPEND; if (dum->driver && dum->driver->suspend) { spin_unlock (&dum->lock); dum->driver->suspend (&dum->gadget); -- cgit v1.2.3 From d9b762510c186584a6be0d3ece03e8a4b2ac13a8 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 3 May 2005 16:15:43 -0400 Subject: [PATCH] USB dummy_hcd: Use separate pdevs for HC and UDC This patch makes the dummy_hcd driver create separate platform devices for the emulated host controller and emulated device controller. This gives a more accurate simulation and will permit testing of situations where only one of the two devices is suspended. This also changes the name of the host controller platform device to match the name of the driver. That way the normal platform bus probe mechanism will handle binding the driver to the device. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 231 ++++++++++++++++++++++++----------------- 1 file changed, 133 insertions(+), 98 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index ffedf4d1b747..dc0e3233b0e9 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -141,6 +141,8 @@ static const char *const ep_name [] = { }; #define DUMMY_ENDPOINTS (sizeof(ep_name)/sizeof(char *)) +/*-------------------------------------------------------------------------*/ + #define FIFO_SIZE 64 struct urbp { @@ -189,6 +191,11 @@ static inline struct device *dummy_dev (struct dummy *dum) return dummy_to_hcd(dum)->self.controller; } +static inline struct device *udc_dev (struct dummy *dum) +{ + return dum->gadget.dev.parent; +} + static inline struct dummy *ep_to_dummy (struct dummy_ep *ep) { return container_of (ep->gadget, struct dummy, gadget); @@ -208,19 +215,6 @@ static struct dummy *the_controller; /*-------------------------------------------------------------------------*/ -/* - * This "hardware" may look a bit odd in diagnostics since it's got both - * host and device sides; and it binds different drivers to each side. - */ -static struct platform_device the_pdev; - -static struct device_driver dummy_driver = { - .name = (char *) driver_name, - .bus = &platform_bus_type, -}; - -/*-------------------------------------------------------------------------*/ - /* SLAVE/GADGET SIDE DRIVER * * This only tracks gadget state. All the work is done when the host @@ -324,7 +318,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) _ep->maxpacket = max; ep->desc = desc; - dev_dbg (dummy_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n", + dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n", _ep->name, desc->bEndpointAddress & 0x0f, (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", @@ -379,7 +373,7 @@ static int dummy_disable (struct usb_ep *_ep) nuke (dum, ep); spin_unlock_irqrestore (&dum->lock, flags); - dev_dbg (dummy_dev(dum), "disabled %s\n", _ep->name); + dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name); return retval; } @@ -474,7 +468,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags) return -ESHUTDOWN; #if 0 - dev_dbg (dummy_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n", + dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n", ep, _req, _ep->name, _req->length, _req->buf); #endif @@ -537,7 +531,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) spin_unlock_irqrestore (&dum->lock, flags); if (retval == 0) { - dev_dbg (dummy_dev(dum), + dev_dbg (udc_dev(dum), "dequeued req %p from %s, len %d buf %p\n", req, _ep->name, _req->length, _req->buf); _req->complete (_ep, _req); @@ -661,38 +655,6 @@ DEVICE_ATTR (function, S_IRUGO, show_function, NULL); * for each driver that registers: just add to a big root hub. */ -/* This doesn't need to do anything because the udc device structure is - * stored inside the hcd and will be deallocated along with it. */ -static void -dummy_udc_release (struct device *dev) {} - -/* This doesn't need to do anything because the pdev structure is - * statically allocated. */ -static void -dummy_pdev_release (struct device *dev) {} - -static int -dummy_register_udc (struct dummy *dum) -{ - int rc; - - strcpy (dum->gadget.dev.bus_id, "udc"); - dum->gadget.dev.parent = dummy_dev(dum); - dum->gadget.dev.release = dummy_udc_release; - - rc = device_register (&dum->gadget.dev); - if (rc == 0) - device_create_file (&dum->gadget.dev, &dev_attr_function); - return rc; -} - -static void -dummy_unregister_udc (struct dummy *dum) -{ - device_remove_file (&dum->gadget.dev, &dev_attr_function); - device_unregister (&dum->gadget.dev); -} - int usb_gadget_register_driver (struct usb_gadget_driver *driver) { @@ -711,12 +673,6 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) * SLAVE side init ... the layer above hardware, which * can't enumerate without help from the driver we're binding. */ - dum->gadget.name = gadget_name; - dum->gadget.ops = &dummy_ops; - dum->gadget.is_dualspeed = 1; - - /* maybe claim OTG support, though we won't complete HNP */ - dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0); dum->devstatus = 0; dum->resuming = 0; @@ -745,7 +701,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) dum->driver = driver; dum->gadget.dev.driver = &driver->driver; - dev_dbg (dummy_dev(dum), "binding gadget driver '%s'\n", + dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n", driver->driver.name); if ((retval = driver->bind (&dum->gadget)) != 0) { dum->driver = NULL; @@ -798,7 +754,7 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) if (!driver || driver != dum->driver) return -EINVAL; - dev_dbg (dummy_dev(dum), "unregister gadget driver '%s'\n", + dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n", driver->driver.name); spin_lock_irqsave (&dum->lock, flags); @@ -826,6 +782,64 @@ int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) } EXPORT_SYMBOL (net2280_set_fifo_mode); + +/* The gadget structure is stored inside the hcd structure and will be + * released along with it. */ +static void +dummy_gadget_release (struct device *dev) +{ +#if 0 /* usb_bus_put isn't EXPORTed! */ + struct dummy *dum = gadget_dev_to_dummy (dev); + + usb_bus_put (&dummy_to_hcd (dum)->self); +#endif +} + +static int dummy_udc_probe (struct device *dev) +{ + struct dummy *dum = the_controller; + int rc; + + dum->gadget.name = gadget_name; + dum->gadget.ops = &dummy_ops; + dum->gadget.is_dualspeed = 1; + + /* maybe claim OTG support, though we won't complete HNP */ + dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0); + + strcpy (dum->gadget.dev.bus_id, "gadget"); + dum->gadget.dev.parent = dev; + dum->gadget.dev.release = dummy_gadget_release; + rc = device_register (&dum->gadget.dev); + if (rc < 0) + return rc; + +#if 0 /* usb_bus_get isn't EXPORTed! */ + usb_bus_get (&dummy_to_hcd (dum)->self); +#endif + + dev_set_drvdata (dev, dum); + device_create_file (&dum->gadget.dev, &dev_attr_function); + return rc; +} + +static int dummy_udc_remove (struct device *dev) +{ + struct dummy *dum = dev_get_drvdata (dev); + + dev_set_drvdata (dev, NULL); + device_remove_file (&dum->gadget.dev, &dev_attr_function); + device_unregister (&dum->gadget.dev); + return 0; +} + +static struct device_driver dummy_udc_driver = { + .name = (char *) gadget_name, + .bus = &platform_bus_type, + .probe = dummy_udc_probe, + .remove = dummy_udc_remove, +}; + /*-------------------------------------------------------------------------*/ /* MASTER/HOST SIDE DRIVER @@ -1184,7 +1198,7 @@ restart: list_for_each_entry (req, &ep->queue, queue) { list_del_init (&req->queue); req->req.status = -EOVERFLOW; - dev_dbg (dummy_dev(dum), "stale req = %p\n", + dev_dbg (udc_dev(dum), "stale req = %p\n", req); spin_unlock (&dum->lock); @@ -1207,7 +1221,7 @@ restart: break; dum->address = setup.wValue; maybe_set_status (urb, 0); - dev_dbg (dummy_dev(dum), "set_address = %d\n", + dev_dbg (udc_dev(dum), "set_address = %d\n", setup.wValue); value = 0; break; @@ -1333,7 +1347,7 @@ restart: if (value < 0) { if (value != -EOPNOTSUPP) - dev_dbg (dummy_dev(dum), + dev_dbg (udc_dev(dum), "setup --> %d\n", value); maybe_set_status (urb, -EPIPE); @@ -1561,7 +1575,7 @@ static int dummy_hub_control ( | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); if (dum->driver) { - dev_dbg (dummy_dev(dum), + dev_dbg (udc_dev(dum), "disconnect\n"); stop_activity (dum, dum->driver); } @@ -1643,7 +1657,6 @@ static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); static int dummy_start (struct usb_hcd *hcd) { struct dummy *dum; - int retval; dum = hcd_to_dummy (hcd); @@ -1659,9 +1672,6 @@ static int dummy_start (struct usb_hcd *hcd) INIT_LIST_HEAD (&dum->urbp_list); - if ((retval = dummy_register_udc (dum)) != 0) - return retval; - /* only show a low-power port: just 8mA */ hcd->power_budget = 8; hcd->state = HC_STATE_RUNNING; @@ -1682,10 +1692,7 @@ static void dummy_stop (struct usb_hcd *hcd) dum = hcd_to_dummy (hcd); device_remove_file (dummy_dev(dum), &dev_attr_urbs); - usb_gadget_unregister_driver (dum->driver); - dummy_unregister_udc (dum); - dev_info (dummy_dev(dum), "stopped\n"); } @@ -1715,7 +1722,7 @@ static const struct hc_driver dummy_hcd = { .hub_control = dummy_hub_control, }; -static int dummy_probe (struct device *dev) +static int dummy_hcd_probe (struct device *dev) { struct usb_hcd *hcd; int retval; @@ -1735,7 +1742,7 @@ static int dummy_probe (struct device *dev) return retval; } -static void dummy_remove (struct device *dev) +static int dummy_hcd_remove (struct device *dev) { struct usb_hcd *hcd; @@ -1743,35 +1750,41 @@ static void dummy_remove (struct device *dev) usb_remove_hcd (hcd); usb_put_hcd (hcd); the_controller = NULL; + return 0; } -/*-------------------------------------------------------------------------*/ - -static int dummy_pdev_detect (void) -{ - int retval; - - retval = driver_register (&dummy_driver); - if (retval < 0) - return retval; +static struct device_driver dummy_hcd_driver = { + .name = (char *) driver_name, + .bus = &platform_bus_type, + .probe = dummy_hcd_probe, + .remove = dummy_hcd_remove, +}; - the_pdev.name = "hc"; - the_pdev.dev.driver = &dummy_driver; - the_pdev.dev.release = dummy_pdev_release; +/*-------------------------------------------------------------------------*/ - retval = platform_device_register (&the_pdev); - if (retval < 0) - driver_unregister (&dummy_driver); - return retval; -} +/* These don't need to do anything because the pdev structures are + * statically allocated. */ +static void +dummy_udc_release (struct device *dev) {} -static void dummy_pdev_remove (void) -{ - platform_device_unregister (&the_pdev); - driver_unregister (&dummy_driver); -} +static void +dummy_hcd_release (struct device *dev) {} + +static struct platform_device the_udc_pdev = { + .name = (char *) gadget_name, + .id = -1, + .dev = { + .release = dummy_udc_release, + }, +}; -/*-------------------------------------------------------------------------*/ +static struct platform_device the_hcd_pdev = { + .name = (char *) driver_name, + .id = -1, + .dev = { + .release = dummy_hcd_release, + }, +}; static int __init init (void) { @@ -1779,17 +1792,39 @@ static int __init init (void) if (usb_disabled ()) return -ENODEV; - if ((retval = dummy_pdev_detect ()) != 0) + + retval = driver_register (&dummy_hcd_driver); + if (retval < 0) return retval; - if ((retval = dummy_probe (&the_pdev.dev)) != 0) - dummy_pdev_remove (); + + retval = driver_register (&dummy_udc_driver); + if (retval < 0) + goto err_register_udc_driver; + + retval = platform_device_register (&the_hcd_pdev); + if (retval < 0) + goto err_register_hcd; + + retval = platform_device_register (&the_udc_pdev); + if (retval < 0) + goto err_register_udc; + return retval; + +err_register_udc: + platform_device_unregister (&the_hcd_pdev); +err_register_hcd: + driver_unregister (&dummy_udc_driver); +err_register_udc_driver: + driver_unregister (&dummy_hcd_driver); return retval; } module_init (init); static void __exit cleanup (void) { - dummy_remove (&the_pdev.dev); - dummy_pdev_remove (); + platform_device_unregister (&the_udc_pdev); + platform_device_unregister (&the_hcd_pdev); + driver_unregister (&dummy_udc_driver); + driver_unregister (&dummy_hcd_driver); } module_exit (cleanup); -- cgit v1.2.3 From f1c39fad7d1bbea31744138cd3a532ff346cd4ab Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 3 May 2005 16:24:04 -0400 Subject: [PATCH] USB dummy_hcd: Centralize link state computations This patch adds to the dummy_hcd driver a new routine for keeping track of all changes in the state of the emulated USB link. The logic is now kept in one spot instead of spread around, and it's easier to verify and update the code. The behavior of the port features has been corrected in a few respects as well (for instance, if the POWER feature is clear then none of the other features can be set). Also added is support for the (relatively new) _connect() and _disconnect() calls of the Gadget API. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 254 ++++++++++++++++++++++++++--------------- 1 file changed, 162 insertions(+), 92 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index dc0e3233b0e9..2d6d22951326 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -163,12 +163,16 @@ struct dummy { struct dummy_request fifo_req; u8 fifo_buf [FIFO_SIZE]; u16 devstatus; + unsigned pullup:1; + unsigned active:1; + unsigned old_active:1; /* * MASTER/HOST side support */ struct timer_list timer; u32 port_status; + u32 old_status; unsigned resuming:1; unsigned long re_timeout; @@ -215,6 +219,98 @@ static struct dummy *the_controller; /*-------------------------------------------------------------------------*/ +/* SLAVE/GADGET SIDE UTILITY ROUTINES */ + +/* called with spinlock held */ +static void nuke (struct dummy *dum, struct dummy_ep *ep) +{ + while (!list_empty (&ep->queue)) { + struct dummy_request *req; + + req = list_entry (ep->queue.next, struct dummy_request, queue); + list_del_init (&req->queue); + req->req.status = -ESHUTDOWN; + + spin_unlock (&dum->lock); + req->req.complete (&ep->ep, &req->req); + spin_lock (&dum->lock); + } +} + +/* caller must hold lock */ +static void +stop_activity (struct dummy *dum) +{ + struct dummy_ep *ep; + + /* prevent any more requests */ + dum->address = 0; + + /* The timer is left running so that outstanding URBs can fail */ + + /* nuke any pending requests first, so driver i/o is quiesced */ + list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) + nuke (dum, ep); + + /* driver now does any non-usb quiescing necessary */ +} + +/* caller must hold lock */ +static void +set_link_state (struct dummy *dum) +{ + dum->active = 0; + if ((dum->port_status & USB_PORT_STAT_POWER) == 0) + dum->port_status = 0; + else if (!dum->pullup) { + dum->port_status &= ~(USB_PORT_STAT_CONNECTION | + USB_PORT_STAT_ENABLE | + USB_PORT_STAT_LOW_SPEED | + USB_PORT_STAT_HIGH_SPEED | + USB_PORT_STAT_SUSPEND); + if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0) + dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); + } else { + dum->port_status |= USB_PORT_STAT_CONNECTION; + if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0) + dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); + if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0) + dum->port_status &= ~USB_PORT_STAT_SUSPEND; + else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0) + dum->active = 1; + } + + if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active) + dum->resuming = 0; + + if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 || + (dum->port_status & USB_PORT_STAT_RESET) != 0) { + if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 && + (dum->old_status & USB_PORT_STAT_RESET) == 0 && + dum->driver) { + stop_activity (dum); + spin_unlock (&dum->lock); + dum->driver->disconnect (&dum->gadget); + spin_lock (&dum->lock); + } + } else if (dum->active != dum->old_active) { + if (dum->old_active && dum->driver->suspend) { + spin_unlock (&dum->lock); + dum->driver->suspend (&dum->gadget); + spin_lock (&dum->lock); + } else if (!dum->old_active && dum->driver->resume) { + spin_unlock (&dum->lock); + dum->driver->resume (&dum->gadget); + spin_lock (&dum->lock); + } + } + + dum->old_status = dum->port_status; + dum->old_active = dum->active; +} + +/*-------------------------------------------------------------------------*/ + /* SLAVE/GADGET SIDE DRIVER * * This only tracks gadget state. All the work is done when the host @@ -339,22 +435,6 @@ done: return retval; } -/* called with spinlock held */ -static void nuke (struct dummy *dum, struct dummy_ep *ep) -{ - while (!list_empty (&ep->queue)) { - struct dummy_request *req; - - req = list_entry (ep->queue.next, struct dummy_request, queue); - list_del_init (&req->queue); - req->req.status = -ESHUTDOWN; - - spin_unlock (&dum->lock); - req->req.complete (&ep->ep, &req->req); - spin_lock (&dum->lock); - } -} - static int dummy_disable (struct usb_ep *_ep) { struct dummy_ep *ep; @@ -603,7 +683,7 @@ static int dummy_wakeup (struct usb_gadget *_gadget) /* hub notices our request, issues downstream resume, etc */ dum->resuming = 1; - dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); + dum->re_timeout = jiffies + msecs_to_jiffies(20); return 0; } @@ -619,10 +699,24 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value) return 0; } +static int dummy_pullup (struct usb_gadget *_gadget, int value) +{ + struct dummy *dum; + unsigned long flags; + + dum = gadget_to_dummy (_gadget); + spin_lock_irqsave (&dum->lock, flags); + dum->pullup = (value != 0); + set_link_state (dum); + spin_unlock_irqrestore (&dum->lock, flags); + return 0; +} + static const struct usb_gadget_ops dummy_ops = { .get_frame = dummy_g_get_frame, .wakeup = dummy_wakeup, .set_selfpowered = dummy_set_selfpowered, + .pullup = dummy_pullup, }; /*-------------------------------------------------------------------------*/ @@ -675,7 +769,6 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) */ dum->devstatus = 0; - dum->resuming = 0; INIT_LIST_HEAD (&dum->gadget.ep_list); for (i = 0; i < DUMMY_ENDPOINTS; i++) { @@ -714,35 +807,14 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) device_bind_driver (&dum->gadget.dev); /* khubd will enumerate this in a while */ - dum->port_status |= USB_PORT_STAT_CONNECTION - | (USB_PORT_STAT_C_CONNECTION << 16); + spin_lock_irq (&dum->lock); + dum->pullup = 1; + set_link_state (dum); + spin_unlock_irq (&dum->lock); return 0; } EXPORT_SYMBOL (usb_gadget_register_driver); -/* caller must hold lock */ -static void -stop_activity (struct dummy *dum, struct usb_gadget_driver *driver) -{ - struct dummy_ep *ep; - - /* prevent any more requests */ - dum->address = 0; - - /* The timer is left running so that outstanding URBs can fail */ - - /* nuke any pending requests first, so driver i/o is quiesced */ - list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) - nuke (dum, ep); - - /* driver now does any non-usb quiescing necessary */ - if (driver) { - spin_unlock (&dum->lock); - driver->disconnect (&dum->gadget); - spin_lock (&dum->lock); - } -} - int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) { @@ -758,10 +830,8 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) driver->driver.name); spin_lock_irqsave (&dum->lock, flags); - stop_activity (dum, driver); - dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | - USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); - dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); + dum->pullup = 0; + set_link_state (dum); spin_unlock_irqrestore (&dum->lock, flags); driver->unbind (&dum->gadget); @@ -770,6 +840,11 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) device_release_driver (&dum->gadget.dev); driver_unregister (&driver->driver); + spin_lock_irqsave (&dum->lock, flags); + dum->pullup = 0; + set_link_state (dum); + spin_unlock_irqrestore (&dum->lock, flags); + return 0; } EXPORT_SYMBOL (usb_gadget_unregister_driver); @@ -1432,6 +1507,13 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf) dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); + + if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { + dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); + dum->port_status &= ~USB_PORT_STAT_SUSPEND; + set_link_state (dum); + } + if (!(dum->port_status & PORT_C_MASK)) retval = 0; else { @@ -1480,16 +1562,16 @@ static int dummy_hub_control ( /* 20msec resume signaling */ dum->resuming = 1; dum->re_timeout = jiffies + - msecs_to_jiffies(20); + msecs_to_jiffies(20); } break; case USB_PORT_FEAT_POWER: - dum->port_status = 0; - dum->resuming = 0; - stop_activity(dum, dum->driver); - break; + if (dum->port_status & USB_PORT_STAT_POWER) + dev_dbg (dummy_dev(dum), "power-off\n"); + /* FALLS THROUGH */ default: dum->port_status &= ~(1 << wValue); + set_link_state (dum); } break; case GetHubDescriptor: @@ -1505,23 +1587,16 @@ static int dummy_hub_control ( /* whoever resets or resumes must GetPortStatus to * complete it!! */ - if (dum->resuming && time_after (jiffies, dum->re_timeout)) { + if (dum->resuming && + time_after_eq (jiffies, dum->re_timeout)) { dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); dum->port_status &= ~USB_PORT_STAT_SUSPEND; - dum->resuming = 0; - dum->re_timeout = 0; - if (dum->driver && dum->driver->resume) { - spin_unlock (&dum->lock); - dum->driver->resume (&dum->gadget); - spin_lock (&dum->lock); - } } - if ((dum->port_status & USB_PORT_STAT_RESET) != 0 - && time_after (jiffies, dum->re_timeout)) { + if ((dum->port_status & USB_PORT_STAT_RESET) != 0 && + time_after_eq (jiffies, dum->re_timeout)) { dum->port_status |= (USB_PORT_STAT_C_RESET << 16); dum->port_status &= ~USB_PORT_STAT_RESET; - dum->re_timeout = 0; - if (dum->driver) { + if (dum->pullup) { dum->port_status |= USB_PORT_STAT_ENABLE; /* give it the best speed we agree on */ dum->gadget.speed = dum->driver->speed; @@ -1542,6 +1617,7 @@ static int dummy_hub_control ( } } } + set_link_state (dum); ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status); ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); break; @@ -1551,42 +1627,36 @@ static int dummy_hub_control ( case SetPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - if ((dum->port_status & USB_PORT_STAT_SUSPEND) - == 0) { + if (dum->active) { dum->port_status |= USB_PORT_STAT_SUSPEND; - if (dum->driver && dum->driver->suspend) { - spin_unlock (&dum->lock); - dum->driver->suspend (&dum->gadget); - spin_lock (&dum->lock); - /* HNP would happen here; for now we - * assume b_bus_req is always true. - */ - if (((1 << USB_DEVICE_B_HNP_ENABLE) - & dum->devstatus) != 0) - dev_dbg (dummy_dev(dum), + + /* HNP would happen here; for now we + * assume b_bus_req is always true. + */ + set_link_state (dum); + if (((1 << USB_DEVICE_B_HNP_ENABLE) + & dum->devstatus) != 0) + dev_dbg (dummy_dev(dum), "no HNP yet!\n"); - } } break; + case USB_PORT_FEAT_POWER: + dum->port_status |= USB_PORT_STAT_POWER; + set_link_state (dum); + break; case USB_PORT_FEAT_RESET: - /* if it's already running, disconnect first */ - if (dum->port_status & USB_PORT_STAT_ENABLE) { - dum->port_status &= ~(USB_PORT_STAT_ENABLE - | USB_PORT_STAT_LOW_SPEED - | USB_PORT_STAT_HIGH_SPEED); - if (dum->driver) { - dev_dbg (udc_dev(dum), - "disconnect\n"); - stop_activity (dum, dum->driver); - } - - /* FIXME test that code path! */ - } + /* if it's already enabled, disable */ + dum->port_status &= ~(USB_PORT_STAT_ENABLE + | USB_PORT_STAT_LOW_SPEED + | USB_PORT_STAT_HIGH_SPEED); /* 50msec reset signaling */ dum->re_timeout = jiffies + msecs_to_jiffies(50); - /* FALLTHROUGH */ + /* FALLS THROUGH */ default: - dum->port_status |= (1 << wValue); + if ((dum->port_status & USB_PORT_STAT_POWER) != 0) { + dum->port_status |= (1 << wValue); + set_link_state (dum); + } } break; -- cgit v1.2.3 From 685eb93f086eb15d9fb1e82c7400fd750f564640 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 3 May 2005 16:27:26 -0400 Subject: [PATCH] USB dummy_hcd: Use root-hub interrupts instead of polling This patch makes the dummy_hcd driver use emulated root-hub interrupts instead of polling. It's in the spirit of similar changes being made to the other HCDs. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 2d6d22951326..73d2f24050ab 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -684,6 +684,7 @@ static int dummy_wakeup (struct usb_gadget *_gadget) /* hub notices our request, issues downstream resume, etc */ dum->resuming = 1; dum->re_timeout = jiffies + msecs_to_jiffies(20); + mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout); return 0; } @@ -709,6 +710,8 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value) dum->pullup = (value != 0); set_link_state (dum); spin_unlock_irqrestore (&dum->lock, flags); + + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; } @@ -811,6 +814,8 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) dum->pullup = 1; set_link_state (dum); spin_unlock_irq (&dum->lock); + + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; } EXPORT_SYMBOL (usb_gadget_register_driver); @@ -845,6 +850,7 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) set_link_state (dum); spin_unlock_irqrestore (&dum->lock, flags); + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; } EXPORT_SYMBOL (usb_gadget_unregister_driver); @@ -1669,6 +1675,9 @@ static int dummy_hub_control ( retval = -EPIPE; } spin_unlock_irqrestore (&dum->lock, flags); + + if ((dum->port_status & PORT_C_MASK) != 0) + usb_hcd_poll_rh_status (hcd); return retval; } @@ -1745,6 +1754,7 @@ static int dummy_start (struct usb_hcd *hcd) /* only show a low-power port: just 8mA */ hcd->power_budget = 8; hcd->state = HC_STATE_RUNNING; + hcd->uses_new_polling = 1; #ifdef CONFIG_USB_OTG hcd->self.otg_port = 1; -- cgit v1.2.3 From 4244f72436ab77c3c29a6447af81734ab3925d85 Mon Sep 17 00:00:00 2001 From: Florian Echtler Date: Fri, 6 May 2005 19:05:39 +0200 Subject: [PATCH] USB: upgrade of the idmouse driver Signed-off-by: Florian Echtler Signed-off-by: Andreas Deresch Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/idmouse.c | 149 ++++++++++++++++++++++++++------------------- 1 file changed, 88 insertions(+), 61 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index ce030d1f1c1f..733acc213726 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -1,4 +1,4 @@ -/* Siemens ID Mouse driver v0.5 +/* Siemens ID Mouse driver v0.6 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -11,6 +11,9 @@ Derived from the USB Skeleton driver 1.1, Copyright (C) 2003 Greg Kroah-Hartman (greg@kroah.com) + Additional information provided by Martin Reising + + */ #include @@ -25,29 +28,44 @@ #include #include +/* image constants */ #define WIDTH 225 -#define HEIGHT 288 -#define HEADER "P5 225 288 255 " +#define HEIGHT 289 +#define HEADER "P5 225 289 255 " #define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1) -/* Version Information */ -#define DRIVER_VERSION "0.5" +/* version information */ +#define DRIVER_VERSION "0.6" #define DRIVER_SHORT "idmouse" #define DRIVER_AUTHOR "Florian 'Floe' Echtler " #define DRIVER_DESC "Siemens ID Mouse FingerTIP Sensor Driver" -/* Siemens ID Mouse */ -#define USB_IDMOUSE_VENDOR_ID 0x0681 -#define USB_IDMOUSE_PRODUCT_ID 0x0005 - -/* we still need a minor number */ +/* minor number for misc USB devices */ #define USB_IDMOUSE_MINOR_BASE 132 +/* vendor and device IDs */ +#define ID_SIEMENS 0x0681 +#define ID_IDMOUSE 0x0005 +#define ID_CHERRY 0x0010 + +/* device ID table */ static struct usb_device_id idmouse_table[] = { - {USB_DEVICE(USB_IDMOUSE_VENDOR_ID, USB_IDMOUSE_PRODUCT_ID)}, - {} /* null entry at the end */ + {USB_DEVICE(ID_SIEMENS, ID_IDMOUSE)}, /* Siemens ID Mouse (Professional) */ + {USB_DEVICE(ID_SIEMENS, ID_CHERRY )}, /* Cherry FingerTIP ID Board */ + {} /* terminating null entry */ }; +/* sensor commands */ +#define FTIP_RESET 0x20 +#define FTIP_ACQUIRE 0x21 +#define FTIP_RELEASE 0x22 +#define FTIP_BLINK 0x23 /* LSB of value = blink pulse width */ +#define FTIP_SCROLL 0x24 + +#define ftip_command(dev, command, value, index) \ + usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), command, \ + USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000) + MODULE_DEVICE_TABLE(usb, idmouse_table); /* structure to hold all of our device specific stuff */ @@ -57,7 +75,8 @@ struct usb_idmouse { struct usb_interface *interface; /* the interface for this device */ unsigned char *bulk_in_buffer; /* the buffer to receive data */ - size_t bulk_in_size; /* the size of the receive buffer */ + size_t bulk_in_size; /* the maximum bulk packet size */ + size_t orig_bi_size; /* same as above, but reported by the device */ __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ int open; /* if the port is open or not */ @@ -103,7 +122,7 @@ static struct usb_driver idmouse_driver = { .id_table = idmouse_table, }; -// prevent races between open() and disconnect() +/* prevent races between open() and disconnect() */ static DECLARE_MUTEX(disconnect_sem); static int idmouse_create_image(struct usb_idmouse *dev) @@ -112,42 +131,34 @@ static int idmouse_create_image(struct usb_idmouse *dev) int bulk_read = 0; int result = 0; - if (dev->bulk_in_size < sizeof(HEADER)) - return -ENOMEM; - - memcpy(dev->bulk_in_buffer,HEADER,sizeof(HEADER)-1); + memcpy(dev->bulk_in_buffer, HEADER, sizeof(HEADER)-1); bytes_read += sizeof(HEADER)-1; - /* Dump the setup packets. Yes, they are uncommented, simply - because they were sniffed under Windows using SnoopyPro. - I _guess_ that 0x22 is a kind of reset command and 0x21 - means init.. - */ - result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), - 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, 1000); + /* reset the device and set a fast blink rate */ + result = ftip_command(dev, FTIP_RELEASE, 0, 0); if (result < 0) - return result; - result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), - 0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000); + goto reset; + result = ftip_command(dev, FTIP_BLINK, 1, 0); if (result < 0) - return result; + goto reset; - result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), - 0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000); + /* initialize the sensor - sending this command twice */ + /* significantly reduces the rate of failed reads */ + result = ftip_command(dev, FTIP_ACQUIRE, 0, 0); if (result < 0) - return result; - result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), - 0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000); + goto reset; + result = ftip_command(dev, FTIP_ACQUIRE, 0, 0); if (result < 0) - return result; - result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), - 0x20, 0x42, 0x0000, 0x0002, NULL, 0, 1000); + goto reset; + + /* start the readout - sending this command twice */ + /* presumably enables the high dynamic range mode */ + result = ftip_command(dev, FTIP_RESET, 0, 0); if (result < 0) - return result; + goto reset; + result = ftip_command(dev, FTIP_RESET, 0, 0); + if (result < 0) + goto reset; /* loop over a blocking bulk read to get data from the device */ while (bytes_read < IMGSIZE) { @@ -155,22 +166,40 @@ static int idmouse_create_image(struct usb_idmouse *dev) usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr), dev->bulk_in_buffer + bytes_read, dev->bulk_in_size, &bulk_read, 5000); - if (result < 0) - return result; - if (signal_pending(current)) - return -EINTR; + if (result < 0) { + /* Maybe this error was caused by the increased packet size? */ + /* Reset to the original value and tell userspace to retry. */ + if (dev->bulk_in_size != dev->orig_bi_size) { + dev->bulk_in_size = dev->orig_bi_size; + result = -EAGAIN; + } + break; + } + if (signal_pending(current)) { + result = -EINTR; + break; + } bytes_read += bulk_read; } /* reset the device */ - result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), - 0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000); - if (result < 0) - return result; +reset: + ftip_command(dev, FTIP_RELEASE, 0, 0); + + /* check for valid image */ + /* right border should be black (0x00) */ + for (bytes_read = sizeof(HEADER)-1 + WIDTH-1; bytes_read < IMGSIZE; bytes_read += WIDTH) + if (dev->bulk_in_buffer[bytes_read] != 0x00) + return -EAGAIN; - /* should be IMGSIZE == 64815 */ + /* lower border should be white (0xFF) */ + for (bytes_read = IMGSIZE-WIDTH; bytes_read < IMGSIZE-1; bytes_read++) + if (dev->bulk_in_buffer[bytes_read] != 0xFF) + return -EAGAIN; + + /* should be IMGSIZE == 65040 */ dbg("read %d bytes fingerprint data", bytes_read); - return 0; + return result; } static inline void idmouse_delete(struct usb_idmouse *dev) @@ -282,10 +311,10 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count dev = (struct usb_idmouse *) file->private_data; - // lock this object + /* lock this object */ down (&dev->sem); - // verify that the device wasn't unplugged + /* verify that the device wasn't unplugged */ if (!dev->present) { up (&dev->sem); return -ENODEV; @@ -296,8 +325,7 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count return 0; } - if (count > IMGSIZE - *ppos) - count = IMGSIZE - *ppos; + count = min ((loff_t)count, IMGSIZE - (*ppos)); if (copy_to_user (buffer, dev->bulk_in_buffer + *ppos, count)) { result = -EFAULT; @@ -306,7 +334,7 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count *ppos += count; } - // unlock the device + /* unlock the device */ up(&dev->sem); return result; } @@ -318,7 +346,6 @@ static int idmouse_probe(struct usb_interface *interface, struct usb_idmouse *dev = NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; - size_t buffer_size; int result; /* check if we have gotten the data or the hid interface */ @@ -344,11 +371,11 @@ static int idmouse_probe(struct usb_interface *interface, USB_ENDPOINT_XFER_BULK)) { /* we found a bulk in endpoint */ - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - dev->bulk_in_size = buffer_size; + dev->orig_bi_size = le16_to_cpu(endpoint->wMaxPacketSize); + dev->bulk_in_size = 0x200; /* works _much_ faster */ dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; dev->bulk_in_buffer = - kmalloc(IMGSIZE + buffer_size, GFP_KERNEL); + kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL); if (!dev->bulk_in_buffer) { err("Unable to allocate input buffer."); -- cgit v1.2.3 From 028b271b687714f9fc7a1e89bb79f1fbeef154ee Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 6 May 2005 07:02:01 -0700 Subject: [PATCH] USB: Kconfig fixes for usb/gadget This prevents gadget drivers from being selected when no controller has been selected, by adding an additional boolean and depending on it. It's mostly to help "allmodconfig". Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Kconfig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 3b24f9f2c234..ff075a53c8d6 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -53,6 +53,9 @@ config USB_GADGET_DEBUG_FILES driver on a new board. Enable these files by choosing "Y" here. If in doubt, or to conserve kernel memory, say "N". +config USB_GADGET_SELECTED + boolean + # # USB Peripheral Controller Support # @@ -85,6 +88,7 @@ config USB_NET2280 tristate depends on USB_GADGET_NET2280 default USB_GADGET + select USB_GADGET_SELECTED config USB_GADGET_PXA2XX boolean "PXA 25x or IXP 4xx" @@ -105,6 +109,7 @@ config USB_PXA2XX tristate depends on USB_GADGET_PXA2XX default USB_GADGET + select USB_GADGET_SELECTED # if there's only one gadget driver, using only two bulk endpoints, # don't waste memory for the other endpoints @@ -134,6 +139,7 @@ config USB_GOKU tristate depends on USB_GADGET_GOKU default USB_GADGET + select USB_GADGET_SELECTED config USB_GADGET_LH7A40X @@ -146,6 +152,7 @@ config USB_LH7A40X tristate depends on USB_GADGET_LH7A40X default USB_GADGET + select USB_GADGET_SELECTED config USB_GADGET_OMAP @@ -167,6 +174,7 @@ config USB_OMAP tristate depends on USB_GADGET_OMAP default USB_GADGET + select USB_GADGET_SELECTED config USB_OTG boolean "OTG Support" @@ -207,6 +215,7 @@ config USB_DUMMY_HCD tristate depends on USB_GADGET_DUMMY_HCD default USB_GADGET + select USB_GADGET_SELECTED # NOTE: Please keep dummy_hcd LAST so that "real hardware" appears # first and will be selected by default. @@ -226,7 +235,7 @@ config USB_GADGET_DUALSPEED # choice tristate "USB Gadget Drivers" - depends on USB_GADGET + depends on USB_GADGET && USB_GADGET_SELECTED default USB_ETH help A Linux "Gadget Driver" talks to the USB Peripheral Controller -- cgit v1.2.3 From 1bbc169621cbe502b9143a27eb12802a0f1d43a0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 7 May 2005 13:05:13 -0700 Subject: [PATCH] USB: gadget driver updates (SETUP api change) This updates most of the gadget framework to expect SETUP packets use USB byteorder (matching the annotation in and usage in the host side stack): - definition in - gadget drivers: Ethernet/RNDIS, serial/ACM, file_storage, gadgetfs. - dummy_hcd It also includes some other similar changes as suggested by "sparse", which was used to detect byteorder bugs. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 3 --- drivers/usb/gadget/ether.c | 6 +++--- drivers/usb/gadget/file_storage.c | 19 +++++++++---------- drivers/usb/gadget/inode.c | 12 ++++++------ drivers/usb/gadget/serial.c | 36 +++++++++++++++++++----------------- drivers/usb/gadget/zero.c | 6 +++--- include/linux/usb_gadget.h | 2 +- 7 files changed, 41 insertions(+), 43 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 73d2f24050ab..f9540adf2a4f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1267,9 +1267,6 @@ restart: struct dummy_ep *ep2; setup = *(struct usb_ctrlrequest*) urb->setup_packet; - le16_to_cpus (&setup.wIndex); - le16_to_cpus (&setup.wValue); - le16_to_cpus (&setup.wLength); if (setup.wLength != urb->transfer_buffer_length) { maybe_set_status (urb, -EOVERFLOW); goto return_urb; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 3830a0a0fd50..9f8413e3c10a 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1277,9 +1277,9 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) struct eth_dev *dev = get_gadget_data (gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; - u16 wIndex = (__force u16) ctrl->wIndex; - u16 wValue = (__force u16) ctrl->wValue; - u16 wLength = (__force u16) ctrl->wLength; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); /* descriptors just go into the pre-allocated ep0 buffer, * while config change events may enable network traffic. diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index f5ce45c4b2a3..4f57085619b4 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -819,7 +819,7 @@ static void inline put_be32(u8 *buf, u32 val) buf[0] = val >> 24; buf[1] = val >> 16; buf[2] = val >> 8; - buf[3] = val; + buf[3] = val & 0xff; } @@ -1277,8 +1277,8 @@ static int class_setup_req(struct fsg_dev *fsg, { struct usb_request *req = fsg->ep0req; int value = -EOPNOTSUPP; - u16 w_index = ctrl->wIndex; - u16 w_length = ctrl->wLength; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_length = le16_to_cpu(ctrl->wLength); if (!fsg->config) return value; @@ -1345,7 +1345,7 @@ static int class_setup_req(struct fsg_dev *fsg, "unknown class-specific control req " "%02x.%02x v%04x i%04x l%u\n", ctrl->bRequestType, ctrl->bRequest, - ctrl->wValue, w_index, w_length); + le16_to_cpu(ctrl->wValue), w_index, w_length); return value; } @@ -1359,8 +1359,8 @@ static int standard_setup_req(struct fsg_dev *fsg, { struct usb_request *req = fsg->ep0req; int value = -EOPNOTSUPP; - u16 w_index = ctrl->wIndex; - u16 w_value = ctrl->wValue; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); /* Usually this just stores reply data in the pre-allocated ep0 buffer, * but config change events will also reconfigure hardware. */ @@ -1469,7 +1469,7 @@ static int standard_setup_req(struct fsg_dev *fsg, VDBG(fsg, "unknown control req %02x.%02x v%04x i%04x l%u\n", ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, ctrl->wLength); + w_value, w_index, le16_to_cpu(ctrl->wLength)); } return value; @@ -1481,7 +1481,7 @@ static int fsg_setup(struct usb_gadget *gadget, { struct fsg_dev *fsg = get_gadget_data(gadget); int rc; - int w_length = ctrl->wLength; + int w_length = le16_to_cpu(ctrl->wLength); ++fsg->ep0_req_tag; // Record arrival of a new request fsg->ep0req->context = NULL; @@ -1497,8 +1497,7 @@ static int fsg_setup(struct usb_gadget *gadget, if (rc >= 0 && rc != DELAYED_STATUS) { rc = min(rc, w_length); fsg->ep0req->length = rc; - fsg->ep0req->zero = (rc < w_length && - (rc % gadget->ep0->maxpacket) == 0); + fsg->ep0req->zero = rc < w_length; fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"); rc = ep0_queue(fsg); diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 1e5e6ddef787..020815397a49 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -417,8 +417,8 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) goto free1; value = ep_io (data, kbuf, len); - VDEBUG (data->dev, "%s read %d OUT, status %d\n", - data->name, len, value); + VDEBUG (data->dev, "%s read %zu OUT, status %d\n", + data->name, len, (int) value); if (value >= 0 && copy_to_user (buf, kbuf, value)) value = -EFAULT; @@ -465,8 +465,8 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) } value = ep_io (data, kbuf, len); - VDEBUG (data->dev, "%s write %d IN, status %d\n", - data->name, len, value); + VDEBUG (data->dev, "%s write %zu IN, status %d\n", + data->name, len, (int) value); free1: up (&data->lock); kfree (kbuf); @@ -1318,8 +1318,8 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) struct usb_request *req = dev->req; int value = -EOPNOTSUPP; struct usb_gadgetfs_event *event; - u16 w_value = ctrl->wValue; - u16 w_length = ctrl->wLength; + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); spin_lock (&dev->lock); dev->setup_abort = 0; diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 4d591c764e38..9e4f1c6935a5 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -300,18 +300,18 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, - int kmalloc_flags); + unsigned kmalloc_flags); static void gs_free_req(struct usb_ep *ep, struct usb_request *req); static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, - int kmalloc_flags); + unsigned kmalloc_flags); static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req); -static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags); +static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags); static void gs_free_ports(struct gs_dev *dev); /* circular buffer */ -static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags); +static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags); static void gs_buf_free(struct gs_buf *gb); static void gs_buf_clear(struct gs_buf *gb); static unsigned int gs_buf_data_avail(struct gs_buf *gb); @@ -1607,9 +1607,9 @@ static int gs_setup(struct usb_gadget *gadget, int ret = -EOPNOTSUPP; struct gs_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->dev_ctrl_req; - u16 wIndex = ctrl->wIndex; - u16 wValue = ctrl->wValue; - u16 wLength = ctrl->wLength; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); switch (ctrl->bRequestType & USB_TYPE_MASK) { case USB_TYPE_STANDARD: @@ -1651,9 +1651,9 @@ static int gs_setup_standard(struct usb_gadget *gadget, int ret = -EOPNOTSUPP; struct gs_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->dev_ctrl_req; - u16 wIndex = ctrl->wIndex; - u16 wValue = ctrl->wValue; - u16 wLength = ctrl->wLength; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: @@ -1782,9 +1782,9 @@ static int gs_setup_class(struct usb_gadget *gadget, struct gs_dev *dev = get_gadget_data(gadget); struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */ struct usb_request *req = dev->dev_ctrl_req; - u16 wIndex = ctrl->wIndex; - u16 wValue = ctrl->wValue; - u16 wLength = ctrl->wLength; + u16 wIndex = le16_to_cpu(ctrl->wIndex); + u16 wValue = le16_to_cpu(ctrl->wValue); + u16 wLength = le16_to_cpu(ctrl->wLength); switch (ctrl->bRequest) { case USB_CDC_REQ_SET_LINE_CODING: @@ -2119,7 +2119,8 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, * Allocate a usb_request and its buffer. Returns a pointer to the * usb_request or NULL if there is an error. */ -static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int kmalloc_flags) +static struct usb_request * +gs_alloc_req(struct usb_ep *ep, unsigned int len, unsigned kmalloc_flags) { struct usb_request *req; @@ -2159,7 +2160,8 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req) * Allocates a request and its buffer, using the given * endpoint, buffer len, and kmalloc flags. */ -static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, int kmalloc_flags) +static struct gs_req_entry * +gs_alloc_req_entry(struct usb_ep *ep, unsigned len, unsigned kmalloc_flags) { struct gs_req_entry *req; @@ -2200,7 +2202,7 @@ static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req) * * The device lock is normally held when calling this function. */ -static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags) +static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags) { int i; struct gs_port *port; @@ -2282,7 +2284,7 @@ static void gs_free_ports(struct gs_dev *dev) * * Allocate a circular buffer and all associated memory. */ -static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags) +static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags) { struct gs_buf *gb; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 6e49432071a1..a6e035e24479 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -919,9 +919,9 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) struct zero_dev *dev = get_gadget_data (gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; - u16 w_index = ctrl->wIndex; - u16 w_value = ctrl->wValue; - u16 w_length = ctrl->wLength; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); /* usually this stores reply data in the pre-allocated ep0 buffer, * but config change events will reconfigure hardware. diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index 9bba9997947b..b00f127cb447 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -711,7 +711,7 @@ usb_gadget_disconnect (struct usb_gadget *gadget) * the hardware level driver. Most calls must be handled by * the gadget driver, including descriptor and configuration * management. The 16 bit members of the setup data are in - * cpu order. Called in_interrupt; this may not sleep. Driver + * USB byte order. Called in_interrupt; this may not sleep. Driver * queues a response to ep0, or returns negative to stall. * @disconnect: Invoked after all transfers have been stopped, * when the host is disconnected. May be called in_interrupt; this -- cgit v1.2.3 From 320f34595c3cf37d180a087a935c050e4ac0e4d5 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 7 May 2005 13:05:18 -0700 Subject: [PATCH] USB: net2280 updates (sparse, SETUP api change) This is mostly "sparse" related updates, one of which was a missing le32_to_cpu() should have affected big-endian hardware. Notable is the API change: setup packets are now provided in USB byte order. This affects only big-endian hardware, and the gadget drivers have been updated in a separate patch. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/net2280.c | 51 +++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 22 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index e47e398daeb5..13a3dbc9949b 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -448,7 +448,7 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req) #elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE) #define USE_KMALLOC -#elif defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO) +#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT) #define USE_KMALLOC /* FIXME there are other cases, including an x86-64 one ... */ @@ -1113,7 +1113,7 @@ static void restart_dma (struct net2280_ep *ep) if (ep->in_fifo_validate) dmactl |= (1 << DMA_FIFO_VALIDATE); list_for_each_entry (entry, &ep->queue, queue) { - u32 dmacount; + __le32 dmacount; if (entry == req) continue; @@ -1238,7 +1238,7 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req) &ep->dma->dmadesc); if (req->td->dmacount & dma_done_ie) writel (readl (&ep->dma->dmacount) - | dma_done_ie, + | le32_to_cpu(dma_done_ie), &ep->dma->dmacount); } else { struct net2280_request *prev; @@ -1779,6 +1779,9 @@ static void set_fifo_mode (struct net2280 *dev, int mode) list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list); } +/* just declare this in any driver that really need it */ +extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); + /** * net2280_set_fifo_mode - change allocation of fifo buffers * @gadget: access to the net2280 device that will be updated @@ -2382,9 +2385,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) cpu_to_le32s (&u.raw [0]); cpu_to_le32s (&u.raw [1]); - le16_to_cpus (&u.r.wValue); - le16_to_cpus (&u.r.wIndex); - le16_to_cpus (&u.r.wLength); +#define w_value le16_to_cpup (&u.r.wValue) +#define w_index le16_to_cpup (&u.r.wIndex) +#define w_length le16_to_cpup (&u.r.wLength) /* ack the irq */ writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0); @@ -2413,25 +2416,25 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) switch (u.r.bRequest) { case USB_REQ_GET_STATUS: { struct net2280_ep *e; - u16 status; + __le32 status; /* hw handles device and interface status */ if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT)) goto delegate; - if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0 - || u.r.wLength > 2) + if ((e = get_ep_by_addr (dev, w_index)) == 0 + || w_length > 2) goto do_stall; if (readl (&e->regs->ep_rsp) & (1 << SET_ENDPOINT_HALT)) - status = __constant_cpu_to_le16 (1); + status = __constant_cpu_to_le32 (1); else - status = __constant_cpu_to_le16 (0); + status = __constant_cpu_to_le32 (0); /* don't bother with a request object! */ writel (0, &dev->epregs [0].ep_irqenb); - set_fifo_bytecount (ep, u.r.wLength); - writel (status, &dev->epregs [0].ep_data); + set_fifo_bytecount (ep, w_length); + writel ((__force u32)status, &dev->epregs [0].ep_data); allow_status (ep); VDEBUG (dev, "%s stat %02x\n", ep->ep.name, status); goto next_endpoints; @@ -2443,10 +2446,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) + if (w_value != USB_ENDPOINT_HALT + || w_length != 0) goto do_stall; - if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) + if ((e = get_ep_by_addr (dev, w_index)) == 0) goto do_stall; clear_halt (e); allow_status (ep); @@ -2460,10 +2463,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) + if (w_value != USB_ENDPOINT_HALT + || w_length != 0) goto do_stall; - if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) + if ((e = get_ep_by_addr (dev, w_index)) == 0) goto do_stall; set_halt (e); allow_status (ep); @@ -2473,10 +2476,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) break; default: delegate: - VDEBUG (dev, "setup %02x.%02x v%04x i%04x " + VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x" "ep_cfg %08x\n", u.r.bRequestType, u.r.bRequest, - u.r.wValue, u.r.wIndex, + w_value, w_index, w_length, readl (&ep->regs->ep_cfg)); spin_unlock (&dev->lock); tmp = dev->driver->setup (&dev->gadget, &u.r); @@ -2497,6 +2500,10 @@ do_stall: */ } +#undef w_value +#undef w_index +#undef w_length + next_endpoints: /* endpoint data irq ? */ scratch = stat & 0x7f; @@ -2653,7 +2660,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) restart_dma (ep); else if (ep->is_in && use_dma_chaining) { struct net2280_request *req; - u32 dmacount; + __le32 dmacount; /* the descriptor at the head of the chain * may still have VALID_BIT clear; that's -- cgit v1.2.3 From 988199fe34411b413d5a388fc751c91eb4686f36 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 7 May 2005 13:05:52 -0700 Subject: [PATCH] USB: goku_udc updates (sparse, SETUP api change) Sparse updates; and the API change for SETUP packets being in USB byteorder. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/goku_udc.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 005db7cca292..ed773a9111de 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -70,7 +70,7 @@ MODULE_LICENSE("GPL"); * seem to behave quite as expected. Used by default. * * OUT dma documents design problems handling the common "short packet" - * transfer termination policy; it couldn't enabled by default, even + * transfer termination policy; it couldn't be enabled by default, even * if the OUT-dma abort problems had a resolution. */ static unsigned use_dma = 1; @@ -313,7 +313,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req) #if defined(CONFIG_X86) #define USE_KMALLOC -#elif defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO) +#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT) #define USE_KMALLOC #elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE) @@ -1524,9 +1524,12 @@ static void ep0_setup(struct goku_udc *dev) /* read SETUP packet and enter DATA stage */ ctrl.bRequestType = readl(®s->bRequestType); ctrl.bRequest = readl(®s->bRequest); - ctrl.wValue = (readl(®s->wValueH) << 8) | readl(®s->wValueL); - ctrl.wIndex = (readl(®s->wIndexH) << 8) | readl(®s->wIndexL); - ctrl.wLength = (readl(®s->wLengthH) << 8) | readl(®s->wLengthL); + ctrl.wValue = cpu_to_le16((readl(®s->wValueH) << 8) + | readl(®s->wValueL)); + ctrl.wIndex = cpu_to_le16((readl(®s->wIndexH) << 8) + | readl(®s->wIndexL)); + ctrl.wLength = cpu_to_le16((readl(®s->wLengthH) << 8) + | readl(®s->wLengthL)); writel(0, ®s->SetupRecv); nuke(&dev->ep[0], 0); @@ -1548,18 +1551,20 @@ static void ep0_setup(struct goku_udc *dev) case USB_REQ_CLEAR_FEATURE: switch (ctrl.bRequestType) { case USB_RECIP_ENDPOINT: - tmp = ctrl.wIndex & 0x0f; + tmp = le16_to_cpu(ctrl.wIndex) & 0x0f; /* active endpoint */ if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0)) goto stall; - if (ctrl.wIndex & USB_DIR_IN) { + if (ctrl.wIndex & __constant_cpu_to_le16( + USB_DIR_IN)) { if (!dev->ep[tmp].is_in) goto stall; } else { if (dev->ep[tmp].is_in) goto stall; } - if (ctrl.wValue != USB_ENDPOINT_HALT) + if (ctrl.wValue != __constant_cpu_to_le16( + USB_ENDPOINT_HALT)) goto stall; if (tmp) goku_clear_halt(&dev->ep[tmp]); @@ -1571,7 +1576,7 @@ succeed: return; case USB_RECIP_DEVICE: /* device remote wakeup: always clear */ - if (ctrl.wValue != 1) + if (ctrl.wValue != __constant_cpu_to_le16(1)) goto stall; VDBG(dev, "clear dev remote wakeup\n"); goto succeed; @@ -1589,14 +1594,15 @@ succeed: #ifdef USB_TRACE VDBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", ctrl.bRequestType, ctrl.bRequest, - ctrl.wValue, ctrl.wIndex, ctrl.wLength); + le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex), + le16_to_cpu(ctrl.wLength)); #endif /* hw wants to know when we're configured (or not) */ dev->req_config = (ctrl.bRequest == USB_REQ_SET_CONFIGURATION && ctrl.bRequestType == USB_RECIP_DEVICE); if (unlikely(dev->req_config)) - dev->configured = (ctrl.wValue != 0); + dev->configured = (ctrl.wValue != __constant_cpu_to_le16(0)); /* delegate everything to the gadget driver. * it may respond after this irq handler returns. -- cgit v1.2.3 From 9198769363d4dc1d63d49ecb2e2b189aceb42d94 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 7 May 2005 13:20:19 -0700 Subject: [PATCH] USB: pxa2xx_udc updates This has several small updates to the px2xx UDC driver: * small fixes from Eugeny S. Mints - local_irq_save() around potential endpoint disable race - fix handling of enqueue to OUT endpoints (potential oops) * add shutdown() method to disable any D+ pullup * rename methods accessing raw signals, referencing the signals * describes itself as for "pxa25x", since pxa27x is different Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/pxa2xx_udc.c | 43 ++++++++++++++++++++++++++--------------- drivers/usb/gadget/pxa2xx_udc.h | 10 +++++----- 2 files changed, 32 insertions(+), 21 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index b8b4524ed746..6a0b957af335 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -1,6 +1,6 @@ /* * linux/drivers/usb/gadget/pxa2xx_udc.c - * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers + * Intel PXA25x and IXP4xx on-chip full speed USB device controllers * * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) * Copyright (C) 2003 Robert Schwebel, Pengutronix @@ -63,7 +63,7 @@ /* - * This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx + * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x * series processors. The UDC for the IXP 4xx series is very similar. * There are fifteen endpoints, in addition to ep0. * @@ -79,8 +79,8 @@ * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. */ -#define DRIVER_VERSION "14-Dec-2003" -#define DRIVER_DESC "PXA 2xx USB Device Controller driver" +#define DRIVER_VERSION "4-May-2005" +#define DRIVER_DESC "PXA 25x USB Device Controller driver" static const char driver_name [] = "pxa2xx_udc"; @@ -290,6 +290,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep, static int pxa2xx_ep_disable (struct usb_ep *_ep) { struct pxa2xx_ep *ep; + unsigned long flags; ep = container_of (_ep, struct pxa2xx_ep, ep); if (!_ep || !ep->desc) { @@ -297,6 +298,8 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) _ep ? ep->ep.name : NULL); return -EINVAL; } + local_irq_save(flags); + nuke (ep, -ESHUTDOWN); #ifdef USE_DMA @@ -313,6 +316,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) ep->desc = NULL; ep->stopped = 1; + local_irq_restore(flags); DBG(DBG_VERBOSE, "%s disabled\n", _ep->name); return 0; } @@ -971,10 +975,10 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) kick_dma(ep, req); #endif /* can the FIFO can satisfy the request immediately? */ - } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0 - && (*ep->reg_udccs & UDCCS_BI_TFS) != 0 - && write_fifo(ep, req)) { - req = NULL; + } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { + if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0 + && write_fifo(ep, req)) + req = NULL; } else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0 && read_fifo(ep, req)) { req = NULL; @@ -1290,7 +1294,7 @@ udc_proc_read(char *page, char **start, off_t off, int count, "%s version: %s\nGadget driver: %s\nHost %s\n\n", driver_name, DRIVER_VERSION SIZE_STR DMASTR, dev->driver ? dev->driver->driver.name : "(none)", - is_usb_connected() ? "full speed" : "disconnected"); + is_vbus_present() ? "full speed" : "disconnected"); size -= t; next += t; @@ -1339,7 +1343,7 @@ udc_proc_read(char *page, char **start, off_t off, int count, next += t; } - if (!is_usb_connected() || !dev->driver) + if (!is_vbus_present() || !dev->driver) goto done; t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", @@ -1454,7 +1458,7 @@ static void udc_disable(struct pxa2xx_udc *dev) UFNRH = UFNRH_SIM; /* if hardware supports it, disconnect from usb */ - make_usb_disappear(); + pullup_off(); udc_clear_mask_UDCCR(UDCCR_UDE); @@ -1567,7 +1571,7 @@ static void udc_enable (struct pxa2xx_udc *dev) UICR0 &= ~UICR0_IM0; /* if hardware supports it, pullup D+ and wait for reset */ - let_usb_appear(); + pullup_on(); } @@ -2052,10 +2056,10 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r) if (unlikely(udccr & UDCCR_SUSIR)) { udc_ack_int_UDCCR(UDCCR_SUSIR); handled = 1; - DBG(DBG_VERBOSE, "USB suspend%s\n", is_usb_connected() + DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present() ? "" : "+disconnect"); - if (!is_usb_connected()) + if (!is_vbus_present()) stop_activity(dev, dev->driver); else if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver @@ -2073,7 +2077,7 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r) if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->resume - && is_usb_connected()) + && is_vbus_present()) dev->driver->resume(&dev->gadget); } @@ -2509,7 +2513,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev) udc_disable(dev); udc_reinit(dev); - dev->vbus = is_usb_connected(); + dev->vbus = is_vbus_present(); /* irq setup after old hardware state is cleaned up */ retval = request_irq(IRQ_USB, pxa2xx_udc_irq, @@ -2555,6 +2559,12 @@ lubbock_fail0: return 0; } + +static void pxa2xx_udc_shutdown(struct device *_dev) +{ + pullup_off(); +} + static int __exit pxa2xx_udc_remove(struct device *_dev) { struct pxa2xx_udc *dev = dev_get_drvdata(_dev); @@ -2624,6 +2634,7 @@ static struct device_driver udc_driver = { .name = "pxa2xx-udc", .bus = &platform_bus_type, .probe = pxa2xx_udc_probe, + .shutdown = pxa2xx_udc_shutdown, .remove = __exit_p(pxa2xx_udc_remove), .suspend = pxa2xx_udc_suspend, .resume = pxa2xx_udc_resume, diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index 1f3a7d999da7..d0bc396a85d5 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -177,23 +177,23 @@ struct pxa2xx_udc { static struct pxa2xx_udc *the_controller; -/* one GPIO should be used to detect host disconnect */ -static inline int is_usb_connected(void) +/* one GPIO should be used to detect VBUS from the host */ +static inline int is_vbus_present(void) { if (!the_controller->mach->udc_is_connected) return 1; return the_controller->mach->udc_is_connected(); } -/* one GPIO should force the host to see this device (or not) */ -static inline void make_usb_disappear(void) +/* one GPIO should control a D+ pullup, so host sees this device (or not) */ +static inline void pullup_off(void) { if (!the_controller->mach->udc_command) return; the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); } -static inline void let_usb_appear(void) +static inline void pullup_on(void) { if (!the_controller->mach->udc_command) return; -- cgit v1.2.3 From d49d431744007cec0ee1a3ade96f9e0f100c7907 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 7 May 2005 13:21:50 -0700 Subject: [PATCH] USB: misc ehci updates Various minor EHCI updates * Dump some more info in the debug dumps, notably the product description (e.g. chip vendor), BIOS handhake flags, and debug port status (when it's not managed by the HCD). * Minor updates to the BIOS handoff code: always flag the HCD as owned by Linux (in case BIOS doesn't grab it "early"), and on the buggy-BIOS path always match the "early handoff" code and forcibly disable SMI IRQs. * For the disabled 64bit DMA support, there's now a constant to use for the mask; use it. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-dbg.c | 59 +++++++++++++++++++++++++++++++++++++++++---- drivers/usb/host/ehci-hcd.c | 27 +++++++++++---------- drivers/usb/host/ehci-hub.c | 2 +- drivers/usb/host/ehci-q.c | 2 +- 4 files changed, 70 insertions(+), 20 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 2ff11d53567b..50cb01831075 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -254,7 +254,7 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status) } return scnprintf (buf, len, - "%s%sport %d status %06x%s%s sig=%s %s%s%s%s%s%s%s%s%s", + "%s%sport %d status %06x%s%s sig=%s%s%s%s%s%s%s%s%s%s", label, label [0] ? " " : "", port, status, (status & PORT_POWER) ? " POWER" : "", (status & PORT_OWNER) ? " OWNER" : "", @@ -644,9 +644,11 @@ show_registers (struct class_device *class_dev, char *buf) if (bus->controller->power.power_state) { size = scnprintf (next, size, "bus %s, device %s (driver " DRIVER_VERSION ")\n" + "%s\n" "SUSPENDED (no register access)\n", hcd->self.controller->bus->name, - hcd->self.controller->bus_id); + hcd->self.controller->bus_id, + hcd->product_desc); goto done; } @@ -654,13 +656,53 @@ show_registers (struct class_device *class_dev, char *buf) i = HC_VERSION(readl (&ehci->caps->hc_capbase)); temp = scnprintf (next, size, "bus %s, device %s (driver " DRIVER_VERSION ")\n" + "%s\n" "EHCI %x.%02x, hcd state %d\n", hcd->self.controller->bus->name, hcd->self.controller->bus_id, + hcd->product_desc, i >> 8, i & 0x0ff, hcd->state); size -= temp; next += temp; +#ifdef CONFIG_PCI + /* EHCI 0.96 and later may have "extended capabilities" */ + if (hcd->self.controller->bus == &pci_bus_type) { + struct pci_dev *pdev; + u32 offset, cap, cap2; + unsigned count = 256/4; + + pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); + offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); + while (offset && count--) { + pci_read_config_dword (pdev, offset, &cap); + switch (cap & 0xff) { + case 1: + temp = scnprintf (next, size, + "ownership %08x%s%s\n", cap, + (cap & (1 << 24)) ? " linux" : "", + (cap & (1 << 16)) ? " firmware" : ""); + size -= temp; + next += temp; + + offset += 4; + pci_read_config_dword (pdev, offset, &cap2); + temp = scnprintf (next, size, + "SMI sts/enable 0x%08x\n", cap2); + size -= temp; + next += temp; + break; + case 0: /* illegal reserved capability */ + cap = 0; + /* FALLTHROUGH */ + default: /* unknown */ + break; + } + temp = (cap >> 8) & 0xff; + } + } +#endif + // FIXME interpret both types of params i = readl (&ehci->caps->hcs_params); temp = scnprintf (next, size, "structural params 0x%08x\n", i); @@ -696,12 +738,19 @@ show_registers (struct class_device *class_dev, char *buf) size -= temp; next += temp; - for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) { - temp = dbg_port_buf (scratch, sizeof scratch, label, i + 1, - readl (&ehci->regs->port_status [i])); + for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) { + temp = dbg_port_buf (scratch, sizeof scratch, label, i, + readl (&ehci->regs->port_status [i - 1])); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; + if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) { + temp = scnprintf (next, size, + " debug control %08x\n", + readl (&ehci->debug->control)); + size -= temp; + next += temp; + } } if (ehci->reclaim) { diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 527abc693b17..35248a37b717 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -304,30 +304,31 @@ static void ehci_watchdog (unsigned long param) */ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) { + struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); + + /* always say Linux will own the hardware */ + pci_write_config_byte(pdev, where + 3, 1); + + /* maybe wait a while for BIOS to respond */ if (cap & (1 << 16)) { int msec = 5000; - struct pci_dev *pdev = - to_pci_dev(ehci_to_hcd(ehci)->self.controller); - /* request handoff to OS */ - cap |= 1 << 24; - pci_write_config_dword(pdev, where, cap); - - /* and wait a while for it to happen */ do { msleep(10); msec -= 10; pci_read_config_dword(pdev, where, &cap); } while ((cap & (1 << 16)) && msec); if (cap & (1 << 16)) { - ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n", + ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n", where, cap); // some BIOS versions seem buggy... // return 1; ehci_warn (ehci, "continuing after BIOS bug...\n"); - return 0; - } - ehci_dbg (ehci, "BIOS handoff succeeded\n"); + /* disable all SMIs, and clear "BIOS owns" flag */ + pci_write_config_dword(pdev, where + 4, 0); + pci_write_config_byte(pdev, where + 2, 0); + } else + ehci_dbg(ehci, "BIOS handoff succeeded\n"); } return 0; } @@ -586,8 +587,8 @@ static int ehci_start (struct usb_hcd *hcd) writel (0, &ehci->regs->segment); #if 0 // this is deeply broken on almost all architectures - if (!pci_set_dma_mask (to_pci_dev(hcd->self.controller), 0xffffffffffffffffULL)) - ehci_info (ehci, "enabled 64bit PCI DMA\n"); + if (!dma_set_mask (hcd->self.controller, DMA_64BIT_MASK)) + ehci_info (ehci, "enabled 64bit DMA\n"); #endif } diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index d7b4f7939ded..36cc1f2218d5 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2002 by David Brownell + * Copyright (C) 2001-2004 by 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 the diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 7df9b9af54f6..45d89a7083b1 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2002 by David Brownell + * Copyright (C) 2001-2004 by 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 the -- cgit v1.2.3 From c59bba75fa500f13ef14215d599ee0d7faa1b954 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Wed, 11 May 2005 20:24:03 +0200 Subject: [PATCH] USB ATM: new usbatm core Rework the core usbatm code: minidrivers (i.e. drivers for particular modems) now register themselves with the usbatm core, supplying methods for binding/unbinding etc. The design was inspired by usb-serial and usbnet. At the same time, more common code from the speedtch and cxacru (patch 3/5) drivers was generalized and moved into the core. The transmission and reception parts have been unified and simplified. Since this is a major change and I don't like underscores in file names, usb_atm.[ch] has been renamed usbatm.[ch]. Many thanks to Roman Kagan, who did a lot of the coding. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/usb_atm.c | 1188 ------------------------------------------- drivers/usb/atm/usb_atm.h | 176 ------- drivers/usb/atm/usbatm.c | 1231 +++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/atm/usbatm.h | 183 +++++++ 4 files changed, 1414 insertions(+), 1364 deletions(-) delete mode 100644 drivers/usb/atm/usb_atm.c delete mode 100644 drivers/usb/atm/usb_atm.h create mode 100644 drivers/usb/atm/usbatm.c create mode 100644 drivers/usb/atm/usbatm.h (limited to 'drivers/usb') diff --git a/drivers/usb/atm/usb_atm.c b/drivers/usb/atm/usb_atm.c deleted file mode 100644 index a4cd4476d49a..000000000000 --- a/drivers/usb/atm/usb_atm.c +++ /dev/null @@ -1,1188 +0,0 @@ -/****************************************************************************** - * usb_atm.c - Generic USB xDSL driver core - * - * Copyright (C) 2001, Alcatel - * Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas - * Copyright (C) 2004, David Woodhouse - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - ******************************************************************************/ - -/* - * Written by Johan Verrept, maintained by Duncan Sands (duncan.sands@free.fr) - * - * 1.7+: - See the check-in logs - * - * 1.6: - No longer opens a connection if the firmware is not loaded - * - Added support for the speedtouch 330 - * - Removed the limit on the number of devices - * - Module now autoloads on device plugin - * - Merged relevant parts of sarlib - * - Replaced the kernel thread with a tasklet - * - New packet transmission code - * - Changed proc file contents - * - Fixed all known SMP races - * - Many fixes and cleanups - * - Various fixes by Oliver Neukum (oliver@neukum.name) - * - * 1.5A: - Version for inclusion in 2.5 series kernel - * - Modifications by Richard Purdie (rpurdie@rpsys.net) - * - made compatible with kernel 2.5.6 onwards by changing - * udsl_usb_send_data_context->urb to a pointer and adding code - * to alloc and free it - * - remove_wait_queue() added to udsl_atm_processqueue_thread() - * - * 1.5: - fixed memory leak when atmsar_decode_aal5 returned NULL. - * (reported by stephen.robinson@zen.co.uk) - * - * 1.4: - changed the spin_lock() under interrupt to spin_lock_irqsave() - * - unlink all active send urbs of a vcc that is being closed. - * - * 1.3.1: - added the version number - * - * 1.3: - Added multiple send urb support - * - fixed memory leak and vcc->tx_inuse starvation bug - * when not enough memory left in vcc. - * - * 1.2: - Fixed race condition in udsl_usb_send_data() - * 1.1: - Turned off packet debugging - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "usb_atm.h" - -#ifdef VERBOSE_DEBUG -static int udsl_print_packet(const unsigned char *data, int len); -#define PACKETDEBUG(arg...) udsl_print_packet (arg) -#define vdbg(arg...) dbg (arg) -#else -#define PACKETDEBUG(arg...) -#define vdbg(arg...) -#endif - -#define DRIVER_AUTHOR "Johan Verrept, Duncan Sands " -#define DRIVER_VERSION "1.8" -#define DRIVER_DESC "Generic USB ATM/DSL I/O, version " DRIVER_VERSION - -static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS; -static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS; -static unsigned int num_rcv_bufs = UDSL_DEFAULT_RCV_BUFS; -static unsigned int num_snd_bufs = UDSL_DEFAULT_SND_BUFS; -static unsigned int rcv_buf_size = UDSL_DEFAULT_RCV_BUF_SIZE; -static unsigned int snd_buf_size = UDSL_DEFAULT_SND_BUF_SIZE; - -module_param(num_rcv_urbs, uint, 0444); -MODULE_PARM_DESC(num_rcv_urbs, - "Number of urbs used for reception (range: 0-" - __MODULE_STRING(UDSL_MAX_RCV_URBS) ", default: " - __MODULE_STRING(UDSL_DEFAULT_RCV_URBS) ")"); - -module_param(num_snd_urbs, uint, 0444); -MODULE_PARM_DESC(num_snd_urbs, - "Number of urbs used for transmission (range: 0-" - __MODULE_STRING(UDSL_MAX_SND_URBS) ", default: " - __MODULE_STRING(UDSL_DEFAULT_SND_URBS) ")"); - -module_param(num_rcv_bufs, uint, 0444); -MODULE_PARM_DESC(num_rcv_bufs, - "Number of buffers used for reception (range: 0-" - __MODULE_STRING(UDSL_MAX_RCV_BUFS) ", default: " - __MODULE_STRING(UDSL_DEFAULT_RCV_BUFS) ")"); - -module_param(num_snd_bufs, uint, 0444); -MODULE_PARM_DESC(num_snd_bufs, - "Number of buffers used for transmission (range: 0-" - __MODULE_STRING(UDSL_MAX_SND_BUFS) ", default: " - __MODULE_STRING(UDSL_DEFAULT_SND_BUFS) ")"); - -module_param(rcv_buf_size, uint, 0444); -MODULE_PARM_DESC(rcv_buf_size, - "Size of the buffers used for reception (range: 0-" - __MODULE_STRING(UDSL_MAX_RCV_BUF_SIZE) ", default: " - __MODULE_STRING(UDSL_DEFAULT_RCV_BUF_SIZE) ")"); - -module_param(snd_buf_size, uint, 0444); -MODULE_PARM_DESC(snd_buf_size, - "Size of the buffers used for transmission (range: 0-" - __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: " - __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")"); - -/* ATM */ - -static void udsl_atm_dev_close(struct atm_dev *dev); -static int udsl_atm_open(struct atm_vcc *vcc); -static void udsl_atm_close(struct atm_vcc *vcc); -static int udsl_atm_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg); -static int udsl_atm_send(struct atm_vcc *vcc, struct sk_buff *skb); -static int udsl_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page); - -static struct atmdev_ops udsl_atm_devops = { - .dev_close = udsl_atm_dev_close, - .open = udsl_atm_open, - .close = udsl_atm_close, - .ioctl = udsl_atm_ioctl, - .send = udsl_atm_send, - .proc_read = udsl_atm_proc_read, - .owner = THIS_MODULE, -}; - -/*********** -** misc ** -***********/ - -static inline void udsl_pop(struct atm_vcc *vcc, struct sk_buff *skb) -{ - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb(skb); -} - -/************* -** decode ** -*************/ - -static inline struct udsl_vcc_data *udsl_find_vcc(struct udsl_instance_data *instance, - short vpi, int vci) -{ - struct udsl_vcc_data *vcc; - - list_for_each_entry(vcc, &instance->vcc_list, list) - if ((vcc->vci == vci) && (vcc->vpi == vpi)) - return vcc; - return NULL; -} - -static void udsl_extract_cells(struct udsl_instance_data *instance, - unsigned char *source, unsigned int howmany) -{ - struct udsl_vcc_data *cached_vcc = NULL; - struct atm_vcc *vcc; - struct sk_buff *sarb; - struct udsl_vcc_data *vcc_data; - int cached_vci = 0; - unsigned int i; - int pti; - int vci; - short cached_vpi = 0; - short vpi; - - for (i = 0; i < howmany; - i++, source += ATM_CELL_SIZE + instance->rcv_padding) { - vpi = ((source[0] & 0x0f) << 4) | (source[1] >> 4); - vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4); - pti = (source[3] & 0x2) != 0; - - vdbg("udsl_extract_cells: vpi %hd, vci %d, pti %d", vpi, vci, pti); - - if (cached_vcc && (vci == cached_vci) && (vpi == cached_vpi)) - vcc_data = cached_vcc; - else if ((vcc_data = udsl_find_vcc(instance, vpi, vci))) { - cached_vcc = vcc_data; - cached_vpi = vpi; - cached_vci = vci; - } else { - dbg("udsl_extract_cells: unknown vpi/vci (%hd/%d)!", vpi, vci); - continue; - } - - vcc = vcc_data->vcc; - sarb = vcc_data->sarb; - - if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) { - dbg("udsl_extract_cells: buffer overrun (sarb->len %u, vcc: 0x%p)!", sarb->len, vcc); - /* discard cells already received */ - skb_trim(sarb, 0); - } - - memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD); - __skb_put(sarb, ATM_CELL_PAYLOAD); - - if (pti) { - struct sk_buff *skb; - unsigned int length; - unsigned int pdu_length; - - length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5]; - - /* guard against overflow */ - if (length > ATM_MAX_AAL5_PDU) { - dbg("udsl_extract_cells: bogus length %u (vcc: 0x%p)!", length, vcc); - atomic_inc(&vcc->stats->rx_err); - goto out; - } - - pdu_length = UDSL_NUM_CELLS(length) * ATM_CELL_PAYLOAD; - - if (sarb->len < pdu_length) { - dbg("udsl_extract_cells: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!", pdu_length, sarb->len, vcc); - atomic_inc(&vcc->stats->rx_err); - goto out; - } - - if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) { - dbg("udsl_extract_cells: packet failed crc check (vcc: 0x%p)!", vcc); - atomic_inc(&vcc->stats->rx_err); - goto out; - } - - vdbg("udsl_extract_cells: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", length, pdu_length, vcc); - - if (!(skb = dev_alloc_skb(length))) { - dbg("udsl_extract_cells: no memory for skb (length: %u)!", length); - atomic_inc(&vcc->stats->rx_drop); - goto out; - } - - vdbg("udsl_extract_cells: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", skb, skb->truesize); - - if (!atm_charge(vcc, skb->truesize)) { - dbg("udsl_extract_cells: failed atm_charge (skb->truesize: %u)!", skb->truesize); - dev_kfree_skb(skb); - goto out; /* atm_charge increments rx_drop */ - } - - memcpy(skb->data, sarb->tail - pdu_length, length); - __skb_put(skb, length); - - vdbg("udsl_extract_cells: sending skb 0x%p, skb->len %u, skb->truesize %u", skb, skb->len, skb->truesize); - - PACKETDEBUG(skb->data, skb->len); - - vcc->push(vcc, skb); - - atomic_inc(&vcc->stats->rx); - out: - skb_trim(sarb, 0); - } - } -} - -/************* -** encode ** -*************/ - -static inline void udsl_fill_cell_header(unsigned char *target, struct atm_vcc *vcc) -{ - target[0] = vcc->vpi >> 4; - target[1] = (vcc->vpi << 4) | (vcc->vci >> 12); - target[2] = vcc->vci >> 4; - target[3] = vcc->vci << 4; - target[4] = 0xec; -} - -static const unsigned char zeros[ATM_CELL_PAYLOAD]; - -static void udsl_groom_skb(struct atm_vcc *vcc, struct sk_buff *skb) -{ - struct udsl_control *ctrl = UDSL_SKB(skb); - unsigned int zero_padding; - u32 crc; - - ctrl->atm_data.vcc = vcc; - - ctrl->num_cells = UDSL_NUM_CELLS(skb->len); - ctrl->num_entire = skb->len / ATM_CELL_PAYLOAD; - - zero_padding = ctrl->num_cells * ATM_CELL_PAYLOAD - skb->len - ATM_AAL5_TRAILER; - - if (ctrl->num_entire + 1 < ctrl->num_cells) - ctrl->pdu_padding = zero_padding - (ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER); - else - ctrl->pdu_padding = zero_padding; - - ctrl->aal5_trailer[0] = 0; /* UU = 0 */ - ctrl->aal5_trailer[1] = 0; /* CPI = 0 */ - ctrl->aal5_trailer[2] = skb->len >> 8; - ctrl->aal5_trailer[3] = skb->len; - - crc = crc32_be(~0, skb->data, skb->len); - crc = crc32_be(crc, zeros, zero_padding); - crc = crc32_be(crc, ctrl->aal5_trailer, 4); - crc = ~crc; - - ctrl->aal5_trailer[4] = crc >> 24; - ctrl->aal5_trailer[5] = crc >> 16; - ctrl->aal5_trailer[6] = crc >> 8; - ctrl->aal5_trailer[7] = crc; -} - -static unsigned int udsl_write_cells(struct udsl_instance_data *instance, - unsigned int howmany, struct sk_buff *skb, - unsigned char **target_p) -{ - struct udsl_control *ctrl = UDSL_SKB(skb); - unsigned char *target = *target_p; - unsigned int nc, ne, i; - - vdbg("udsl_write_cells: howmany=%u, skb->len=%d, num_cells=%u, num_entire=%u, pdu_padding=%u", howmany, skb->len, ctrl->num_cells, ctrl->num_entire, ctrl->pdu_padding); - - nc = ctrl->num_cells; - ne = min(howmany, ctrl->num_entire); - - for (i = 0; i < ne; i++) { - udsl_fill_cell_header(target, ctrl->atm_data.vcc); - target += ATM_CELL_HEADER; - memcpy(target, skb->data, ATM_CELL_PAYLOAD); - target += ATM_CELL_PAYLOAD; - if (instance->snd_padding) { - memset(target, 0, instance->snd_padding); - target += instance->snd_padding; - } - __skb_pull(skb, ATM_CELL_PAYLOAD); - } - - ctrl->num_entire -= ne; - - if (!(ctrl->num_cells -= ne) || !(howmany -= ne)) - goto out; - - udsl_fill_cell_header(target, ctrl->atm_data.vcc); - target += ATM_CELL_HEADER; - memcpy(target, skb->data, skb->len); - target += skb->len; - __skb_pull(skb, skb->len); - memset(target, 0, ctrl->pdu_padding); - target += ctrl->pdu_padding; - - if (--ctrl->num_cells) { - if (!--howmany) { - ctrl->pdu_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER; - goto out; - } - - if (instance->snd_padding) { - memset(target, 0, instance->snd_padding); - target += instance->snd_padding; - } - udsl_fill_cell_header(target, ctrl->atm_data.vcc); - target += ATM_CELL_HEADER; - memset(target, 0, ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER); - target += ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER; - - --ctrl->num_cells; - UDSL_ASSERT(!ctrl->num_cells); - } - - memcpy(target, ctrl->aal5_trailer, ATM_AAL5_TRAILER); - target += ATM_AAL5_TRAILER; - /* set pti bit in last cell */ - *(target + 3 - ATM_CELL_SIZE) |= 0x2; - if (instance->snd_padding) { - memset(target, 0, instance->snd_padding); - target += instance->snd_padding; - } - out: - *target_p = target; - return nc - ctrl->num_cells; -} - -/************** -** receive ** -**************/ - -static void udsl_complete_receive(struct urb *urb, struct pt_regs *regs) -{ - struct udsl_receive_buffer *buf; - struct udsl_instance_data *instance; - struct udsl_receiver *rcv; - unsigned long flags; - - if (!urb || !(rcv = urb->context)) { - dbg("udsl_complete_receive: bad urb!"); - return; - } - - instance = rcv->instance; - buf = rcv->buffer; - - buf->filled_cells = urb->actual_length / (ATM_CELL_SIZE + instance->rcv_padding); - - vdbg("udsl_complete_receive: urb 0x%p, status %d, actual_length %d, filled_cells %u, rcv 0x%p, buf 0x%p", urb, urb->status, urb->actual_length, buf->filled_cells, rcv, buf); - - UDSL_ASSERT(buf->filled_cells <= rcv_buf_size); - - /* may not be in_interrupt() */ - spin_lock_irqsave(&instance->receive_lock, flags); - list_add(&rcv->list, &instance->spare_receivers); - list_add_tail(&buf->list, &instance->filled_receive_buffers); - if (likely(!urb->status)) - tasklet_schedule(&instance->receive_tasklet); - spin_unlock_irqrestore(&instance->receive_lock, flags); -} - -static void udsl_process_receive(unsigned long data) -{ - struct udsl_receive_buffer *buf; - struct udsl_instance_data *instance = (struct udsl_instance_data *)data; - struct udsl_receiver *rcv; - int err; - - made_progress: - while (!list_empty(&instance->spare_receive_buffers)) { - spin_lock_irq(&instance->receive_lock); - if (list_empty(&instance->spare_receivers)) { - spin_unlock_irq(&instance->receive_lock); - break; - } - rcv = list_entry(instance->spare_receivers.next, - struct udsl_receiver, list); - list_del(&rcv->list); - spin_unlock_irq(&instance->receive_lock); - - buf = list_entry(instance->spare_receive_buffers.next, - struct udsl_receive_buffer, list); - list_del(&buf->list); - - rcv->buffer = buf; - - usb_fill_bulk_urb(rcv->urb, instance->usb_dev, - usb_rcvbulkpipe(instance->usb_dev, instance->data_endpoint), - buf->base, - rcv_buf_size * (ATM_CELL_SIZE + instance->rcv_padding), - udsl_complete_receive, rcv); - - vdbg("udsl_process_receive: sending urb 0x%p, rcv 0x%p, buf 0x%p", - rcv->urb, rcv, buf); - - if ((err = usb_submit_urb(rcv->urb, GFP_ATOMIC)) < 0) { - dbg("udsl_process_receive: urb submission failed (%d)!", err); - list_add(&buf->list, &instance->spare_receive_buffers); - spin_lock_irq(&instance->receive_lock); - list_add(&rcv->list, &instance->spare_receivers); - spin_unlock_irq(&instance->receive_lock); - break; - } - } - - spin_lock_irq(&instance->receive_lock); - if (list_empty(&instance->filled_receive_buffers)) { - spin_unlock_irq(&instance->receive_lock); - return; /* done - no more buffers */ - } - buf = list_entry(instance->filled_receive_buffers.next, - struct udsl_receive_buffer, list); - list_del(&buf->list); - spin_unlock_irq(&instance->receive_lock); - - vdbg("udsl_process_receive: processing buf 0x%p", buf); - udsl_extract_cells(instance, buf->base, buf->filled_cells); - list_add(&buf->list, &instance->spare_receive_buffers); - goto made_progress; -} - -/*********** -** send ** -***********/ - -static void udsl_complete_send(struct urb *urb, struct pt_regs *regs) -{ - struct udsl_instance_data *instance; - struct udsl_sender *snd; - unsigned long flags; - - if (!urb || !(snd = urb->context) || !(instance = snd->instance)) { - dbg("udsl_complete_send: bad urb!"); - return; - } - - vdbg("udsl_complete_send: urb 0x%p, status %d, snd 0x%p, buf 0x%p", urb, - urb->status, snd, snd->buffer); - - /* may not be in_interrupt() */ - spin_lock_irqsave(&instance->send_lock, flags); - list_add(&snd->list, &instance->spare_senders); - list_add(&snd->buffer->list, &instance->spare_send_buffers); - tasklet_schedule(&instance->send_tasklet); - spin_unlock_irqrestore(&instance->send_lock, flags); -} - -static void udsl_process_send(unsigned long data) -{ - struct udsl_send_buffer *buf; - struct udsl_instance_data *instance = (struct udsl_instance_data *)data; - struct sk_buff *skb; - struct udsl_sender *snd; - int err; - unsigned int num_written; - - made_progress: - spin_lock_irq(&instance->send_lock); - while (!list_empty(&instance->spare_senders)) { - if (!list_empty(&instance->filled_send_buffers)) { - buf = list_entry(instance->filled_send_buffers.next, - struct udsl_send_buffer, list); - list_del(&buf->list); - } else if ((buf = instance->current_buffer)) { - instance->current_buffer = NULL; - } else /* all buffers empty */ - break; - - snd = list_entry(instance->spare_senders.next, - struct udsl_sender, list); - list_del(&snd->list); - spin_unlock_irq(&instance->send_lock); - - snd->buffer = buf; - usb_fill_bulk_urb(snd->urb, instance->usb_dev, - usb_sndbulkpipe(instance->usb_dev, instance->data_endpoint), - buf->base, - (snd_buf_size - buf->free_cells) * (ATM_CELL_SIZE + instance->snd_padding), - udsl_complete_send, snd); - - vdbg("udsl_process_send: submitting urb 0x%p (%d cells), snd 0x%p, buf 0x%p", - snd->urb, snd_buf_size - buf->free_cells, snd, buf); - - if ((err = usb_submit_urb(snd->urb, GFP_ATOMIC)) < 0) { - dbg("udsl_process_send: urb submission failed (%d)!", err); - spin_lock_irq(&instance->send_lock); - list_add(&snd->list, &instance->spare_senders); - spin_unlock_irq(&instance->send_lock); - list_add(&buf->list, &instance->filled_send_buffers); - return; /* bail out */ - } - - spin_lock_irq(&instance->send_lock); - } /* while */ - spin_unlock_irq(&instance->send_lock); - - if (!instance->current_skb) - instance->current_skb = skb_dequeue(&instance->sndqueue); - if (!instance->current_skb) - return; /* done - no more skbs */ - - skb = instance->current_skb; - - if (!(buf = instance->current_buffer)) { - spin_lock_irq(&instance->send_lock); - if (list_empty(&instance->spare_send_buffers)) { - instance->current_buffer = NULL; - spin_unlock_irq(&instance->send_lock); - return; /* done - no more buffers */ - } - buf = list_entry(instance->spare_send_buffers.next, - struct udsl_send_buffer, list); - list_del(&buf->list); - spin_unlock_irq(&instance->send_lock); - - buf->free_start = buf->base; - buf->free_cells = snd_buf_size; - - instance->current_buffer = buf; - } - - num_written = udsl_write_cells(instance, buf->free_cells, skb, &buf->free_start); - - vdbg("udsl_process_send: wrote %u cells from skb 0x%p to buffer 0x%p", - num_written, skb, buf); - - if (!(buf->free_cells -= num_written)) { - list_add_tail(&buf->list, &instance->filled_send_buffers); - instance->current_buffer = NULL; - } - - vdbg("udsl_process_send: buffer contains %d cells, %d left", - snd_buf_size - buf->free_cells, buf->free_cells); - - if (!UDSL_SKB(skb)->num_cells) { - struct atm_vcc *vcc = UDSL_SKB(skb)->atm_data.vcc; - - udsl_pop(vcc, skb); - instance->current_skb = NULL; - - atomic_inc(&vcc->stats->tx); - } - - goto made_progress; -} - -static void udsl_cancel_send(struct udsl_instance_data *instance, - struct atm_vcc *vcc) -{ - struct sk_buff *skb, *n; - - dbg("udsl_cancel_send entered"); - spin_lock_irq(&instance->sndqueue.lock); - for (skb = instance->sndqueue.next, n = skb->next; - skb != (struct sk_buff *)&instance->sndqueue; - skb = n, n = skb->next) - if (UDSL_SKB(skb)->atm_data.vcc == vcc) { - dbg("udsl_cancel_send: popping skb 0x%p", skb); - __skb_unlink(skb, &instance->sndqueue); - udsl_pop(vcc, skb); - } - spin_unlock_irq(&instance->sndqueue.lock); - - tasklet_disable(&instance->send_tasklet); - if ((skb = instance->current_skb) && (UDSL_SKB(skb)->atm_data.vcc == vcc)) { - dbg("udsl_cancel_send: popping current skb (0x%p)", skb); - instance->current_skb = NULL; - udsl_pop(vcc, skb); - } - tasklet_enable(&instance->send_tasklet); - dbg("udsl_cancel_send done"); -} - -static int udsl_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - struct udsl_instance_data *instance = vcc->dev->dev_data; - int err; - - vdbg("udsl_atm_send called (skb 0x%p, len %u)", skb, skb->len); - - if (!instance) { - dbg("udsl_atm_send: NULL data!"); - err = -ENODEV; - goto fail; - } - - if (vcc->qos.aal != ATM_AAL5) { - dbg("udsl_atm_send: unsupported ATM type %d!", vcc->qos.aal); - err = -EINVAL; - goto fail; - } - - if (skb->len > ATM_MAX_AAL5_PDU) { - dbg("udsl_atm_send: packet too long (%d vs %d)!", skb->len, - ATM_MAX_AAL5_PDU); - err = -EINVAL; - goto fail; - } - - PACKETDEBUG(skb->data, skb->len); - - udsl_groom_skb(vcc, skb); - skb_queue_tail(&instance->sndqueue, skb); - tasklet_schedule(&instance->send_tasklet); - - return 0; - - fail: - udsl_pop(vcc, skb); - return err; -} - -/******************** -** bean counting ** -********************/ - -static void udsl_destroy_instance(struct kref *kref) -{ - struct udsl_instance_data *instance = - container_of(kref, struct udsl_instance_data, refcount); - - tasklet_kill(&instance->receive_tasklet); - tasklet_kill(&instance->send_tasklet); - usb_put_dev(instance->usb_dev); - kfree(instance); -} - -void udsl_get_instance(struct udsl_instance_data *instance) -{ - kref_get(&instance->refcount); -} - -void udsl_put_instance(struct udsl_instance_data *instance) -{ - kref_put(&instance->refcount, udsl_destroy_instance); -} - -/********** -** ATM ** -**********/ - -static void udsl_atm_dev_close(struct atm_dev *dev) -{ - struct udsl_instance_data *instance = dev->dev_data; - - dev->dev_data = NULL; - udsl_put_instance(instance); -} - -static int udsl_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page) -{ - struct udsl_instance_data *instance = atm_dev->dev_data; - int left = *pos; - - if (!instance) { - dbg("udsl_atm_proc_read: NULL instance!"); - return -ENODEV; - } - - if (!left--) - return sprintf(page, "%s\n", instance->description); - - if (!left--) - return sprintf(page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", - atm_dev->esi[0], atm_dev->esi[1], - atm_dev->esi[2], atm_dev->esi[3], - atm_dev->esi[4], atm_dev->esi[5]); - - if (!left--) - return sprintf(page, - "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n", - atomic_read(&atm_dev->stats.aal5.tx), - atomic_read(&atm_dev->stats.aal5.tx_err), - atomic_read(&atm_dev->stats.aal5.rx), - atomic_read(&atm_dev->stats.aal5.rx_err), - atomic_read(&atm_dev->stats.aal5.rx_drop)); - - if (!left--) { - switch (atm_dev->signal) { - case ATM_PHY_SIG_FOUND: - sprintf(page, "Line up"); - break; - case ATM_PHY_SIG_LOST: - sprintf(page, "Line down"); - break; - default: - sprintf(page, "Line state unknown"); - break; - } - - if (instance->usb_dev->state == USB_STATE_NOTATTACHED) - strcat(page, ", disconnected\n"); - else { - if (instance->status == UDSL_LOADED_FIRMWARE) - strcat(page, ", firmware loaded\n"); - else if (instance->status == UDSL_LOADING_FIRMWARE) - strcat(page, ", firmware loading\n"); - else - strcat(page, ", no firmware\n"); - } - - return strlen(page); - } - - return 0; -} - -static int udsl_atm_open(struct atm_vcc *vcc) -{ - struct udsl_instance_data *instance = vcc->dev->dev_data; - struct udsl_vcc_data *new; - unsigned int max_pdu; - int vci = vcc->vci; - short vpi = vcc->vpi; - int err; - - dbg("udsl_atm_open: vpi %hd, vci %d", vpi, vci); - - if (!instance) { - dbg("udsl_atm_open: NULL data!"); - return -ENODEV; - } - - /* only support AAL5 */ - if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0) - || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) { - dbg("udsl_atm_open: unsupported ATM type %d!", vcc->qos.aal); - return -EINVAL; - } - - if (instance->firmware_wait && - (err = instance->firmware_wait(instance)) < 0) { - dbg("udsl_atm_open: firmware not loaded (%d)!", err); - return err; - } - - down(&instance->serialize); /* vs self, udsl_atm_close */ - - if (udsl_find_vcc(instance, vpi, vci)) { - dbg("udsl_atm_open: %hd/%d already in use!", vpi, vci); - up(&instance->serialize); - return -EADDRINUSE; - } - - if (!(new = kmalloc(sizeof(struct udsl_vcc_data), GFP_KERNEL))) { - dbg("udsl_atm_open: no memory for vcc_data!"); - up(&instance->serialize); - return -ENOMEM; - } - - memset(new, 0, sizeof(struct udsl_vcc_data)); - new->vcc = vcc; - new->vpi = vpi; - new->vci = vci; - - /* udsl_extract_cells requires at least one cell */ - max_pdu = max(1, UDSL_NUM_CELLS(vcc->qos.rxtp.max_sdu)) * ATM_CELL_PAYLOAD; - if (!(new->sarb = alloc_skb(max_pdu, GFP_KERNEL))) { - dbg("udsl_atm_open: no memory for SAR buffer!"); - kfree(new); - up(&instance->serialize); - return -ENOMEM; - } - - vcc->dev_data = new; - - tasklet_disable(&instance->receive_tasklet); - list_add(&new->list, &instance->vcc_list); - tasklet_enable(&instance->receive_tasklet); - - set_bit(ATM_VF_ADDR, &vcc->flags); - set_bit(ATM_VF_PARTIAL, &vcc->flags); - set_bit(ATM_VF_READY, &vcc->flags); - - up(&instance->serialize); - - tasklet_schedule(&instance->receive_tasklet); - - dbg("udsl_atm_open: allocated vcc data 0x%p (max_pdu: %u)", new, max_pdu); - - return 0; -} - -static void udsl_atm_close(struct atm_vcc *vcc) -{ - struct udsl_instance_data *instance = vcc->dev->dev_data; - struct udsl_vcc_data *vcc_data = vcc->dev_data; - - dbg("udsl_atm_close called"); - - if (!instance || !vcc_data) { - dbg("udsl_atm_close: NULL data!"); - return; - } - - dbg("udsl_atm_close: deallocating vcc 0x%p with vpi %d vci %d", - vcc_data, vcc_data->vpi, vcc_data->vci); - - udsl_cancel_send(instance, vcc); - - down(&instance->serialize); /* vs self, udsl_atm_open */ - - tasklet_disable(&instance->receive_tasklet); - list_del(&vcc_data->list); - tasklet_enable(&instance->receive_tasklet); - - kfree_skb(vcc_data->sarb); - vcc_data->sarb = NULL; - - kfree(vcc_data); - vcc->dev_data = NULL; - - vcc->vpi = ATM_VPI_UNSPEC; - vcc->vci = ATM_VCI_UNSPEC; - clear_bit(ATM_VF_READY, &vcc->flags); - clear_bit(ATM_VF_PARTIAL, &vcc->flags); - clear_bit(ATM_VF_ADDR, &vcc->flags); - - up(&instance->serialize); - - dbg("udsl_atm_close successful"); -} - -static int udsl_atm_ioctl(struct atm_dev *dev, unsigned int cmd, - void __user * arg) -{ - switch (cmd) { - case ATM_QUERYLOOP: - return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0; - default: - return -ENOIOCTLCMD; - } -} - -/********** -** USB ** -**********/ - -int udsl_instance_setup(struct usb_device *dev, - struct udsl_instance_data *instance) -{ - char *buf; - int i, length; - - kref_init(&instance->refcount); /* one for USB */ - udsl_get_instance(instance); /* one for ATM */ - - init_MUTEX(&instance->serialize); - - instance->usb_dev = dev; - - INIT_LIST_HEAD(&instance->vcc_list); - - instance->status = UDSL_NO_FIRMWARE; - init_waitqueue_head(&instance->firmware_waiters); - - spin_lock_init(&instance->receive_lock); - INIT_LIST_HEAD(&instance->spare_receivers); - INIT_LIST_HEAD(&instance->filled_receive_buffers); - - tasklet_init(&instance->receive_tasklet, udsl_process_receive, (unsigned long)instance); - INIT_LIST_HEAD(&instance->spare_receive_buffers); - - skb_queue_head_init(&instance->sndqueue); - - spin_lock_init(&instance->send_lock); - INIT_LIST_HEAD(&instance->spare_senders); - INIT_LIST_HEAD(&instance->spare_send_buffers); - - tasklet_init(&instance->send_tasklet, udsl_process_send, - (unsigned long)instance); - INIT_LIST_HEAD(&instance->filled_send_buffers); - - /* receive init */ - for (i = 0; i < num_rcv_urbs; i++) { - struct udsl_receiver *rcv = &(instance->receivers[i]); - - if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { - dbg("udsl_usb_probe: no memory for receive urb %d!", i); - goto fail; - } - - rcv->instance = instance; - - list_add(&rcv->list, &instance->spare_receivers); - } - - for (i = 0; i < num_rcv_bufs; i++) { - struct udsl_receive_buffer *buf = - &(instance->receive_buffers[i]); - - buf->base = kmalloc(rcv_buf_size * (ATM_CELL_SIZE + instance->rcv_padding), - GFP_KERNEL); - if (!buf->base) { - dbg("udsl_usb_probe: no memory for receive buffer %d!", i); - goto fail; - } - - list_add(&buf->list, &instance->spare_receive_buffers); - } - - /* send init */ - for (i = 0; i < num_snd_urbs; i++) { - struct udsl_sender *snd = &(instance->senders[i]); - - if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) { - dbg("udsl_usb_probe: no memory for send urb %d!", i); - goto fail; - } - - snd->instance = instance; - - list_add(&snd->list, &instance->spare_senders); - } - - for (i = 0; i < num_snd_bufs; i++) { - struct udsl_send_buffer *buf = &(instance->send_buffers[i]); - - buf->base = kmalloc(snd_buf_size * (ATM_CELL_SIZE + instance->snd_padding), - GFP_KERNEL); - if (!buf->base) { - dbg("udsl_usb_probe: no memory for send buffer %d!", i); - goto fail; - } - - list_add(&buf->list, &instance->spare_send_buffers); - } - - /* ATM init */ - instance->atm_dev = atm_dev_register(instance->driver_name, - &udsl_atm_devops, -1, NULL); - if (!instance->atm_dev) { - dbg("udsl_usb_probe: failed to register ATM device!"); - goto fail; - } - - instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX; - instance->atm_dev->ci_range.vci_bits = ATM_CI_MAX; - instance->atm_dev->signal = ATM_PHY_SIG_UNKNOWN; - - /* temp init ATM device, set to 128kbit */ - instance->atm_dev->link_rate = 128 * 1000 / 424; - - /* device description */ - buf = instance->description; - length = sizeof(instance->description); - - if ((i = usb_string(dev, dev->descriptor.iProduct, buf, length)) < 0) - goto finish; - - buf += i; - length -= i; - - i = scnprintf(buf, length, " ("); - buf += i; - length -= i; - - if (length <= 0 || (i = usb_make_path(dev, buf, length)) < 0) - goto finish; - - buf += i; - length -= i; - - snprintf(buf, length, ")"); - - finish: - /* ready for ATM callbacks */ - wmb(); - instance->atm_dev->dev_data = instance; - - usb_get_dev(dev); - - return 0; - - fail: - for (i = 0; i < num_snd_bufs; i++) - kfree(instance->send_buffers[i].base); - - for (i = 0; i < num_snd_urbs; i++) - usb_free_urb(instance->senders[i].urb); - - for (i = 0; i < num_rcv_bufs; i++) - kfree(instance->receive_buffers[i].base); - - for (i = 0; i < num_rcv_urbs; i++) - usb_free_urb(instance->receivers[i].urb); - - return -ENOMEM; -} - -void udsl_instance_disconnect(struct udsl_instance_data *instance) -{ - int i; - - dbg("udsl_instance_disconnect entered"); - - if (!instance) { - dbg("udsl_instance_disconnect: NULL instance!"); - return; - } - - /* receive finalize */ - tasklet_disable(&instance->receive_tasklet); - - for (i = 0; i < num_rcv_urbs; i++) - usb_kill_urb(instance->receivers[i].urb); - - /* no need to take the spinlock */ - INIT_LIST_HEAD(&instance->filled_receive_buffers); - INIT_LIST_HEAD(&instance->spare_receive_buffers); - - tasklet_enable(&instance->receive_tasklet); - - for (i = 0; i < num_rcv_urbs; i++) - usb_free_urb(instance->receivers[i].urb); - - for (i = 0; i < num_rcv_bufs; i++) - kfree(instance->receive_buffers[i].base); - - /* send finalize */ - tasklet_disable(&instance->send_tasklet); - - for (i = 0; i < num_snd_urbs; i++) - usb_kill_urb(instance->senders[i].urb); - - /* no need to take the spinlock */ - INIT_LIST_HEAD(&instance->spare_senders); - INIT_LIST_HEAD(&instance->spare_send_buffers); - instance->current_buffer = NULL; - - tasklet_enable(&instance->send_tasklet); - - for (i = 0; i < num_snd_urbs; i++) - usb_free_urb(instance->senders[i].urb); - - for (i = 0; i < num_snd_bufs; i++) - kfree(instance->send_buffers[i].base); - - /* ATM finalize */ - shutdown_atm_dev(instance->atm_dev); -} - -EXPORT_SYMBOL_GPL(udsl_get_instance); -EXPORT_SYMBOL_GPL(udsl_put_instance); -EXPORT_SYMBOL_GPL(udsl_instance_setup); -EXPORT_SYMBOL_GPL(udsl_instance_disconnect); - -/*********** -** init ** -***********/ - -static int __init udsl_usb_init(void) -{ - dbg("udsl_usb_init: driver version " DRIVER_VERSION); - - if (sizeof(struct udsl_control) > sizeof(((struct sk_buff *) 0)->cb)) { - printk(KERN_ERR __FILE__ ": unusable with this kernel!\n"); - return -EIO; - } - - if ((num_rcv_urbs > UDSL_MAX_RCV_URBS) - || (num_snd_urbs > UDSL_MAX_SND_URBS) - || (num_rcv_bufs > UDSL_MAX_RCV_BUFS) - || (num_snd_bufs > UDSL_MAX_SND_BUFS) - || (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE) - || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE)) - return -EINVAL; - - return 0; -} - -static void __exit udsl_usb_exit(void) -{ -} - -module_init(udsl_usb_init); -module_exit(udsl_usb_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); - -/************ -** debug ** -************/ - -#ifdef VERBOSE_DEBUG -static int udsl_print_packet(const unsigned char *data, int len) -{ - unsigned char buffer[256]; - int i = 0, j = 0; - - for (i = 0; i < len;) { - buffer[0] = '\0'; - sprintf(buffer, "%.3d :", i); - for (j = 0; (j < 16) && (i < len); j++, i++) { - sprintf(buffer, "%s %2.2x", buffer, data[i]); - } - dbg("%s", buffer); - } - return i; -} -#endif diff --git a/drivers/usb/atm/usb_atm.h b/drivers/usb/atm/usb_atm.h deleted file mode 100644 index cf8c53283530..000000000000 --- a/drivers/usb/atm/usb_atm.h +++ /dev/null @@ -1,176 +0,0 @@ -/****************************************************************************** - * usb_atm.h - Generic USB xDSL driver core - * - * Copyright (C) 2001, Alcatel - * Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas - * Copyright (C) 2004, David Woodhouse - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include - -/* -#define DEBUG -#define VERBOSE_DEBUG -*/ - -#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG) -# define DEBUG -#endif - -#include - -#ifdef DEBUG -#define UDSL_ASSERT(x) BUG_ON(!(x)) -#else -#define UDSL_ASSERT(x) do { if (!(x)) warn("failed assertion '" #x "' at line %d", __LINE__); } while(0) -#endif - -#define UDSL_MAX_RCV_URBS 4 -#define UDSL_MAX_SND_URBS 4 -#define UDSL_MAX_RCV_BUFS 8 -#define UDSL_MAX_SND_BUFS 8 -#define UDSL_MAX_RCV_BUF_SIZE 1024 /* ATM cells */ -#define UDSL_MAX_SND_BUF_SIZE 1024 /* ATM cells */ -#define UDSL_DEFAULT_RCV_URBS 2 -#define UDSL_DEFAULT_SND_URBS 2 -#define UDSL_DEFAULT_RCV_BUFS 4 -#define UDSL_DEFAULT_SND_BUFS 4 -#define UDSL_DEFAULT_RCV_BUF_SIZE 64 /* ATM cells */ -#define UDSL_DEFAULT_SND_BUF_SIZE 64 /* ATM cells */ - -#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD) -#define UDSL_NUM_CELLS(x) (((x) + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD) - -/* receive */ - -struct udsl_receive_buffer { - struct list_head list; - unsigned char *base; - unsigned int filled_cells; -}; - -struct udsl_receiver { - struct list_head list; - struct udsl_receive_buffer *buffer; - struct urb *urb; - struct udsl_instance_data *instance; -}; - -struct udsl_vcc_data { - /* vpi/vci lookup */ - struct list_head list; - short vpi; - int vci; - struct atm_vcc *vcc; - - /* raw cell reassembly */ - struct sk_buff *sarb; -}; - -/* send */ - -struct udsl_send_buffer { - struct list_head list; - unsigned char *base; - unsigned char *free_start; - unsigned int free_cells; -}; - -struct udsl_sender { - struct list_head list; - struct udsl_send_buffer *buffer; - struct urb *urb; - struct udsl_instance_data *instance; -}; - -struct udsl_control { - struct atm_skb_data atm_data; - unsigned int num_cells; - unsigned int num_entire; - unsigned int pdu_padding; - unsigned char aal5_trailer[ATM_AAL5_TRAILER]; -}; - -#define UDSL_SKB(x) ((struct udsl_control *)(x)->cb) - -/* main driver data */ - -enum udsl_status { - UDSL_NO_FIRMWARE, - UDSL_LOADING_FIRMWARE, - UDSL_LOADED_FIRMWARE -}; - -struct udsl_instance_data { - struct kref refcount; - struct semaphore serialize; - - /* USB device part */ - struct usb_device *usb_dev; - char description[64]; - int data_endpoint; - int snd_padding; - int rcv_padding; - const char *driver_name; - - /* ATM device part */ - struct atm_dev *atm_dev; - struct list_head vcc_list; - - /* firmware */ - int (*firmware_wait) (struct udsl_instance_data *); - enum udsl_status status; - wait_queue_head_t firmware_waiters; - - /* receive */ - struct udsl_receiver receivers[UDSL_MAX_RCV_URBS]; - struct udsl_receive_buffer receive_buffers[UDSL_MAX_RCV_BUFS]; - - spinlock_t receive_lock; - struct list_head spare_receivers; - struct list_head filled_receive_buffers; - - struct tasklet_struct receive_tasklet; - struct list_head spare_receive_buffers; - - /* send */ - struct udsl_sender senders[UDSL_MAX_SND_URBS]; - struct udsl_send_buffer send_buffers[UDSL_MAX_SND_BUFS]; - - struct sk_buff_head sndqueue; - - spinlock_t send_lock; - struct list_head spare_senders; - struct list_head spare_send_buffers; - - struct tasklet_struct send_tasklet; - struct sk_buff *current_skb; /* being emptied */ - struct udsl_send_buffer *current_buffer; /* being filled */ - struct list_head filled_send_buffers; -}; - -extern int udsl_instance_setup(struct usb_device *dev, - struct udsl_instance_data *instance); -extern void udsl_instance_disconnect(struct udsl_instance_data *instance); -extern void udsl_get_instance(struct udsl_instance_data *instance); -extern void udsl_put_instance(struct udsl_instance_data *instance); diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c new file mode 100644 index 000000000000..e134e2794486 --- /dev/null +++ b/drivers/usb/atm/usbatm.c @@ -0,0 +1,1231 @@ +/****************************************************************************** + * usbatm.c - Generic USB xDSL driver core + * + * Copyright (C) 2001, Alcatel + * Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas + * Copyright (C) 2004, David Woodhouse, Roman Kagan + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ******************************************************************************/ + +/* + * Written by Johan Verrept, Duncan Sands (duncan.sands@free.fr) and David Woodhouse + * + * 1.7+: - See the check-in logs + * + * 1.6: - No longer opens a connection if the firmware is not loaded + * - Added support for the speedtouch 330 + * - Removed the limit on the number of devices + * - Module now autoloads on device plugin + * - Merged relevant parts of sarlib + * - Replaced the kernel thread with a tasklet + * - New packet transmission code + * - Changed proc file contents + * - Fixed all known SMP races + * - Many fixes and cleanups + * - Various fixes by Oliver Neukum (oliver@neukum.name) + * + * 1.5A: - Version for inclusion in 2.5 series kernel + * - Modifications by Richard Purdie (rpurdie@rpsys.net) + * - made compatible with kernel 2.5.6 onwards by changing + * usbatm_usb_send_data_context->urb to a pointer and adding code + * to alloc and free it + * - remove_wait_queue() added to usbatm_atm_processqueue_thread() + * + * 1.5: - fixed memory leak when atmsar_decode_aal5 returned NULL. + * (reported by stephen.robinson@zen.co.uk) + * + * 1.4: - changed the spin_lock() under interrupt to spin_lock_irqsave() + * - unlink all active send urbs of a vcc that is being closed. + * + * 1.3.1: - added the version number + * + * 1.3: - Added multiple send urb support + * - fixed memory leak and vcc->tx_inuse starvation bug + * when not enough memory left in vcc. + * + * 1.2: - Fixed race condition in usbatm_usb_send_data() + * 1.1: - Turned off packet debugging + * + */ + +#include "usbatm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef VERBOSE_DEBUG +static int usbatm_print_packet(const unsigned char *data, int len); +#define PACKETDEBUG(arg...) usbatm_print_packet (arg) +#define vdbg(arg...) dbg (arg) +#else +#define PACKETDEBUG(arg...) +#define vdbg(arg...) +#endif + +#define DRIVER_AUTHOR "Johan Verrept, Duncan Sands " +#define DRIVER_VERSION "1.9" +#define DRIVER_DESC "Generic USB ATM/DSL I/O, version " DRIVER_VERSION + +static const char usbatm_driver_name[] = "usbatm"; + +#define UDSL_MAX_RCV_URBS 16 +#define UDSL_MAX_SND_URBS 16 +#define UDSL_MAX_RCV_BUF_SIZE 1024 /* ATM cells */ +#define UDSL_MAX_SND_BUF_SIZE 1024 /* ATM cells */ +#define UDSL_DEFAULT_RCV_URBS 4 +#define UDSL_DEFAULT_SND_URBS 4 +#define UDSL_DEFAULT_RCV_BUF_SIZE 64 /* ATM cells */ +#define UDSL_DEFAULT_SND_BUF_SIZE 64 /* ATM cells */ + +#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD) + +#define THROTTLE_MSECS 100 /* delay to recover processing after urb submission fails */ + +static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS; +static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS; +static unsigned int rcv_buf_size = UDSL_DEFAULT_RCV_BUF_SIZE; +static unsigned int snd_buf_size = UDSL_DEFAULT_SND_BUF_SIZE; + +module_param(num_rcv_urbs, uint, S_IRUGO); +MODULE_PARM_DESC(num_rcv_urbs, + "Number of urbs used for reception (range: 0-" + __MODULE_STRING(UDSL_MAX_RCV_URBS) ", default: " + __MODULE_STRING(UDSL_DEFAULT_RCV_URBS) ")"); + +module_param(num_snd_urbs, uint, S_IRUGO); +MODULE_PARM_DESC(num_snd_urbs, + "Number of urbs used for transmission (range: 0-" + __MODULE_STRING(UDSL_MAX_SND_URBS) ", default: " + __MODULE_STRING(UDSL_DEFAULT_SND_URBS) ")"); + +module_param(rcv_buf_size, uint, S_IRUGO); +MODULE_PARM_DESC(rcv_buf_size, + "Size of the buffers used for reception in ATM cells (range: 1-" + __MODULE_STRING(UDSL_MAX_RCV_BUF_SIZE) ", default: " + __MODULE_STRING(UDSL_DEFAULT_RCV_BUF_SIZE) ")"); + +module_param(snd_buf_size, uint, S_IRUGO); +MODULE_PARM_DESC(snd_buf_size, + "Size of the buffers used for transmission in ATM cells (range: 1-" + __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: " + __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")"); + + +/* receive */ + +struct usbatm_vcc_data { + /* vpi/vci lookup */ + struct list_head list; + short vpi; + int vci; + struct atm_vcc *vcc; + + /* raw cell reassembly */ + struct sk_buff *sarb; +}; + + +/* send */ + +struct usbatm_control { + struct atm_skb_data atm; + u32 len; + u32 crc; +}; + +#define UDSL_SKB(x) ((struct usbatm_control *)(x)->cb) + + +/* ATM */ + +static void usbatm_atm_dev_close(struct atm_dev *dev); +static int usbatm_atm_open(struct atm_vcc *vcc); +static void usbatm_atm_close(struct atm_vcc *vcc); +static int usbatm_atm_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg); +static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb); +static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page); + +static struct atmdev_ops usbatm_atm_devops = { + .dev_close = usbatm_atm_dev_close, + .open = usbatm_atm_open, + .close = usbatm_atm_close, + .ioctl = usbatm_atm_ioctl, + .send = usbatm_atm_send, + .proc_read = usbatm_atm_proc_read, + .owner = THIS_MODULE, +}; + + +/*********** +** misc ** +***********/ + +static inline unsigned int usbatm_pdu_length(unsigned int length) +{ + length += ATM_CELL_PAYLOAD - 1 + ATM_AAL5_TRAILER; + return length - length % ATM_CELL_PAYLOAD; +} + +static inline void usbatm_pop(struct atm_vcc *vcc, struct sk_buff *skb) +{ + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); +} + + +/*********** +** urbs ** +************/ + +static inline struct urb *usbatm_pop_urb(struct usbatm_channel *channel) +{ + struct urb *urb; + + spin_lock_irq(&channel->lock); + if (list_empty(&channel->list)) { + spin_unlock_irq(&channel->lock); + return NULL; + } + + urb = list_entry(channel->list.next, struct urb, urb_list); + list_del(&urb->urb_list); + spin_unlock_irq(&channel->lock); + + return urb; +} + +static inline int usbatm_submit_urb(struct urb *urb) +{ + struct usbatm_channel *channel = urb->context; + int ret; + + vdbg("%s: submitting urb 0x%p, size %u", + __func__, urb, urb->transfer_buffer_length); + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + atm_dbg(channel->usbatm, "%s: urb 0x%p submission failed (%d)!\n", + __func__, urb, ret); + + /* consider all errors transient and return the buffer back to the queue */ + urb->status = -EAGAIN; + spin_lock_irq(&channel->lock); + + /* must add to the front when sending; doesn't matter when receiving */ + list_add(&urb->urb_list, &channel->list); + + spin_unlock_irq(&channel->lock); + + /* make sure the channel doesn't stall */ + mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS)); + } + + return ret; +} + +static void usbatm_complete(struct urb *urb, struct pt_regs *regs) +{ + struct usbatm_channel *channel = urb->context; + unsigned long flags; + + vdbg("%s: urb 0x%p, status %d, actual_length %d", + __func__, urb, urb->status, urb->actual_length); + + /* usually in_interrupt(), but not always */ + spin_lock_irqsave(&channel->lock, flags); + + /* must add to the back when receiving; doesn't matter when sending */ + list_add_tail(&urb->urb_list, &channel->list); + + spin_unlock_irqrestore(&channel->lock, flags); + + if (unlikely(urb->status)) + /* throttle processing in case of an error */ + mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS)); + else + tasklet_schedule(&channel->tasklet); +} + + +/************* +** decode ** +*************/ + +static inline struct usbatm_vcc_data *usbatm_find_vcc(struct usbatm_data *instance, + short vpi, int vci) +{ + struct usbatm_vcc_data *vcc; + + list_for_each_entry(vcc, &instance->vcc_list, list) + if ((vcc->vci == vci) && (vcc->vpi == vpi)) + return vcc; + return NULL; +} + +static void usbatm_extract_cells(struct usbatm_data *instance, + unsigned char *source, unsigned int avail_data) +{ + struct usbatm_vcc_data *cached_vcc = NULL; + struct atm_vcc *vcc; + struct sk_buff *sarb; + struct usbatm_vcc_data *vcc_data; + unsigned int stride = instance->rx_channel.stride; + int vci, cached_vci = 0; + short vpi, cached_vpi = 0; + u8 pti; + + for (; avail_data >= stride; avail_data -= stride, source += stride) { + vpi = ((source[0] & 0x0f) << 4) | (source[1] >> 4); + vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4); + pti = ((source[3] & 0xe) >> 1); + + vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti); + + if (cached_vcc && (vci == cached_vci) && (vpi == cached_vpi)) + vcc_data = cached_vcc; + else if ((vcc_data = usbatm_find_vcc(instance, vpi, vci))) { + cached_vcc = vcc_data; + cached_vpi = vpi; + cached_vci = vci; + } else { + atm_dbg(instance, "%s: unknown vpi/vci (%hd/%d)!\n", __func__, vpi, vci); + continue; + } + + vcc = vcc_data->vcc; + + /* OAM F5 end-to-end */ + if (pti == ATM_PTI_E2EF5) { + atm_warn(instance, "%s: OAM not supported (vpi %d, vci %d)!\n", __func__, vpi, vci); + atomic_inc(&vcc->stats->rx_err); + continue; + } + + sarb = vcc_data->sarb; + + if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) { + atm_dbg(instance, "%s: buffer overrun (sarb->len %u, vcc: 0x%p)!\n", + __func__, sarb->len, vcc); + /* discard cells already received */ + skb_trim(sarb, 0); + UDSL_ASSERT(sarb->tail + ATM_CELL_PAYLOAD <= sarb->end); + } + + memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD); + __skb_put(sarb, ATM_CELL_PAYLOAD); + + if (pti & 1) { + struct sk_buff *skb; + unsigned int length; + unsigned int pdu_length; + + length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5]; + + /* guard against overflow */ + if (length > ATM_MAX_AAL5_PDU) { + atm_dbg(instance, "%s: bogus length %u (vcc: 0x%p)!\n", + __func__, length, vcc); + atomic_inc(&vcc->stats->rx_err); + goto out; + } + + pdu_length = usbatm_pdu_length(length); + + if (sarb->len < pdu_length) { + atm_dbg(instance, "%s: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!\n", + __func__, pdu_length, sarb->len, vcc); + atomic_inc(&vcc->stats->rx_err); + goto out; + } + + if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) { + atm_dbg(instance, "%s: packet failed crc check (vcc: 0x%p)!\n", + __func__, vcc); + atomic_inc(&vcc->stats->rx_err); + goto out; + } + + vdbg("%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", __func__, length, pdu_length, vcc); + + if (!(skb = dev_alloc_skb(length))) { + atm_dbg(instance, "%s: no memory for skb (length: %u)!\n", __func__, length); + atomic_inc(&vcc->stats->rx_drop); + goto out; + } + + vdbg("%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", __func__, skb, skb->truesize); + + if (!atm_charge(vcc, skb->truesize)) { + atm_dbg(instance, "%s: failed atm_charge (skb->truesize: %u)!\n", __func__, skb->truesize); + dev_kfree_skb(skb); + goto out; /* atm_charge increments rx_drop */ + } + + memcpy(skb->data, sarb->tail - pdu_length, length); + __skb_put(skb, length); + + vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u", + __func__, skb, skb->len, skb->truesize); + + PACKETDEBUG(skb->data, skb->len); + + vcc->push(vcc, skb); + + atomic_inc(&vcc->stats->rx); + out: + skb_trim(sarb, 0); + } + } +} + + +/************* +** encode ** +*************/ + +static unsigned int usbatm_write_cells(struct usbatm_data *instance, + struct sk_buff *skb, + u8 *target, unsigned int avail_space) +{ + struct usbatm_control *ctrl = UDSL_SKB(skb); + struct atm_vcc *vcc = ctrl->atm.vcc; + unsigned int num_written; + unsigned int stride = instance->tx_channel.stride; + + vdbg("%s: skb->len=%d, avail_space=%u", __func__, skb->len, avail_space); + UDSL_ASSERT(!(avail_space % stride)); + + for (num_written = 0; num_written < avail_space && ctrl->len; + num_written += stride, target += stride) { + unsigned int data_len = min_t(unsigned int, skb->len, ATM_CELL_PAYLOAD); + unsigned int left = ATM_CELL_PAYLOAD - data_len; + u8 *ptr = target; + + ptr[0] = vcc->vpi >> 4; + ptr[1] = (vcc->vpi << 4) | (vcc->vci >> 12); + ptr[2] = vcc->vci >> 4; + ptr[3] = vcc->vci << 4; + ptr[4] = 0xec; + ptr += ATM_CELL_HEADER; + + memcpy(ptr, skb->data, data_len); + ptr += data_len; + __skb_pull(skb, data_len); + + if(!left) + continue; + + memset(ptr, 0, left); + + if (left >= ATM_AAL5_TRAILER) { /* trailer will go in this cell */ + u8 *trailer = target + ATM_CELL_SIZE - ATM_AAL5_TRAILER; + /* trailer[0] = 0; UU = 0 */ + /* trailer[1] = 0; CPI = 0 */ + trailer[2] = ctrl->len >> 8; + trailer[3] = ctrl->len; + + ctrl->crc = ~ crc32_be(ctrl->crc, ptr, left - 4); + + trailer[4] = ctrl->crc >> 24; + trailer[5] = ctrl->crc >> 16; + trailer[6] = ctrl->crc >> 8; + trailer[7] = ctrl->crc; + + target[3] |= 0x2; /* adjust PTI */ + + ctrl->len = 0; /* tag this skb finished */ + } + else + ctrl->crc = crc32_be(ctrl->crc, ptr, left); + } + + return num_written; +} + + +/************** +** receive ** +**************/ + +static void usbatm_rx_process(unsigned long data) +{ + struct usbatm_data *instance = (struct usbatm_data *)data; + struct urb *urb; + + while ((urb = usbatm_pop_urb(&instance->rx_channel))) { + vdbg("%s: processing urb 0x%p", __func__, urb); + + if (usb_pipeisoc(urb->pipe)) { + int i; + for (i = 0; i < urb->number_of_packets; i++) + if (!urb->iso_frame_desc[i].status) + usbatm_extract_cells(instance, + (u8 *)urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + } + else + if (!urb->status) + usbatm_extract_cells(instance, urb->transfer_buffer, urb->actual_length); + + if (usbatm_submit_urb(urb)) + return; + } +} + + +/*********** +** send ** +***********/ + +static void usbatm_tx_process(unsigned long data) +{ + struct usbatm_data *instance = (struct usbatm_data *)data; + struct sk_buff *skb = instance->current_skb; + struct urb *urb = NULL; + const unsigned int buf_size = instance->tx_channel.buf_size; + unsigned int num_written = 0; + u8 *buffer = NULL; + + if (!skb) + skb = skb_dequeue(&instance->sndqueue); + + while (skb) { + if (!urb) { + urb = usbatm_pop_urb(&instance->tx_channel); + if (!urb) + break; /* no more senders */ + buffer = urb->transfer_buffer; + num_written = (urb->status == -EAGAIN) ? + urb->transfer_buffer_length : 0; + } + + num_written += usbatm_write_cells(instance, skb, + buffer + num_written, + buf_size - num_written); + + vdbg("%s: wrote %u bytes from skb 0x%p to urb 0x%p", + __func__, num_written, skb, urb); + + if (!UDSL_SKB(skb)->len) { + struct atm_vcc *vcc = UDSL_SKB(skb)->atm.vcc; + + usbatm_pop(vcc, skb); + atomic_inc(&vcc->stats->tx); + + skb = skb_dequeue(&instance->sndqueue); + } + + if (num_written == buf_size || (!skb && num_written)) { + urb->transfer_buffer_length = num_written; + + if (usbatm_submit_urb(urb)) + break; + urb = NULL; + } + } + + instance->current_skb = skb; +} + +static void usbatm_cancel_send(struct usbatm_data *instance, + struct atm_vcc *vcc) +{ + struct sk_buff *skb, *n; + + atm_dbg(instance, "%s entered\n", __func__); + spin_lock_irq(&instance->sndqueue.lock); + for (skb = instance->sndqueue.next, n = skb->next; + skb != (struct sk_buff *)&instance->sndqueue; + skb = n, n = skb->next) + if (UDSL_SKB(skb)->atm.vcc == vcc) { + atm_dbg(instance, "%s: popping skb 0x%p\n", __func__, skb); + __skb_unlink(skb, &instance->sndqueue); + usbatm_pop(vcc, skb); + } + spin_unlock_irq(&instance->sndqueue.lock); + + tasklet_disable(&instance->tx_channel.tasklet); + if ((skb = instance->current_skb) && (UDSL_SKB(skb)->atm.vcc == vcc)) { + atm_dbg(instance, "%s: popping current skb (0x%p)\n", __func__, skb); + instance->current_skb = NULL; + usbatm_pop(vcc, skb); + } + tasklet_enable(&instance->tx_channel.tasklet); + atm_dbg(instance, "%s done\n", __func__); +} + +static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct usbatm_data *instance = vcc->dev->dev_data; + struct usbatm_control *ctrl = UDSL_SKB(skb); + int err; + + vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len); + + if (!instance) { + dbg("%s: NULL data!", __func__); + err = -ENODEV; + goto fail; + } + + if (vcc->qos.aal != ATM_AAL5) { + atm_dbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal); + err = -EINVAL; + goto fail; + } + + if (skb->len > ATM_MAX_AAL5_PDU) { + atm_dbg(instance, "%s: packet too long (%d vs %d)!\n", + __func__, skb->len, ATM_MAX_AAL5_PDU); + err = -EINVAL; + goto fail; + } + + PACKETDEBUG(skb->data, skb->len); + + /* initialize the control block */ + ctrl->atm.vcc = vcc; + ctrl->len = skb->len; + ctrl->crc = crc32_be(~0, skb->data, skb->len); + + skb_queue_tail(&instance->sndqueue, skb); + tasklet_schedule(&instance->tx_channel.tasklet); + + return 0; + + fail: + usbatm_pop(vcc, skb); + return err; +} + + +/******************** +** bean counting ** +********************/ + +static void usbatm_destroy_instance(struct kref *kref) +{ + struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount); + + dbg("%s", __func__); + + tasklet_kill(&instance->rx_channel.tasklet); + tasklet_kill(&instance->tx_channel.tasklet); + usb_put_dev(instance->usb_dev); + kfree(instance); +} + +void usbatm_get_instance(struct usbatm_data *instance) +{ + dbg("%s", __func__); + + kref_get(&instance->refcount); +} + +void usbatm_put_instance(struct usbatm_data *instance) +{ + dbg("%s", __func__); + + kref_put(&instance->refcount, usbatm_destroy_instance); +} + + +/********** +** ATM ** +**********/ + +static void usbatm_atm_dev_close(struct atm_dev *dev) +{ + struct usbatm_data *instance = dev->dev_data; + + dbg("%s", __func__); + + if (!instance) + return; + + dev->dev_data = NULL; + usbatm_put_instance(instance); /* taken in usbatm_atm_init */ +} + +static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page) +{ + struct usbatm_data *instance = atm_dev->dev_data; + int left = *pos; + + if (!instance) { + dbg("%s: NULL instance!", __func__); + return -ENODEV; + } + + if (!left--) + return sprintf(page, "%s\n", instance->description); + + if (!left--) + return sprintf(page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", + atm_dev->esi[0], atm_dev->esi[1], + atm_dev->esi[2], atm_dev->esi[3], + atm_dev->esi[4], atm_dev->esi[5]); + + if (!left--) + return sprintf(page, + "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n", + atomic_read(&atm_dev->stats.aal5.tx), + atomic_read(&atm_dev->stats.aal5.tx_err), + atomic_read(&atm_dev->stats.aal5.rx), + atomic_read(&atm_dev->stats.aal5.rx_err), + atomic_read(&atm_dev->stats.aal5.rx_drop)); + + if (!left--) + switch (atm_dev->signal) { + case ATM_PHY_SIG_FOUND: + return sprintf(page, "Line up\n"); + case ATM_PHY_SIG_LOST: + return sprintf(page, "Line down\n"); + default: + return sprintf(page, "Line state unknown\n"); + } + + return 0; +} + +static int usbatm_atm_open(struct atm_vcc *vcc) +{ + struct usbatm_data *instance = vcc->dev->dev_data; + struct usbatm_vcc_data *new = NULL; + int ret; + int vci = vcc->vci; + short vpi = vcc->vpi; + + if (!instance) { + dbg("%s: NULL data!", __func__); + return -ENODEV; + } + + atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci); + + /* only support AAL5 */ + if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0) + || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) { + atm_dbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal); + return -EINVAL; + } + + down(&instance->serialize); /* vs self, usbatm_atm_close */ + + if (usbatm_find_vcc(instance, vpi, vci)) { + atm_dbg(instance, "%s: %hd/%d already in use!\n", __func__, vpi, vci); + ret = -EADDRINUSE; + goto fail; + } + + if (!(new = kmalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL))) { + atm_dbg(instance, "%s: no memory for vcc_data!\n", __func__); + ret = -ENOMEM; + goto fail; + } + + memset(new, 0, sizeof(struct usbatm_vcc_data)); + new->vcc = vcc; + new->vpi = vpi; + new->vci = vci; + + new->sarb = alloc_skb(usbatm_pdu_length(vcc->qos.rxtp.max_sdu), GFP_KERNEL); + if (!new->sarb) { + atm_dbg(instance, "%s: no memory for SAR buffer!\n", __func__); + ret = -ENOMEM; + goto fail; + } + + vcc->dev_data = new; + + tasklet_disable(&instance->rx_channel.tasklet); + list_add(&new->list, &instance->vcc_list); + tasklet_enable(&instance->rx_channel.tasklet); + + set_bit(ATM_VF_ADDR, &vcc->flags); + set_bit(ATM_VF_PARTIAL, &vcc->flags); + set_bit(ATM_VF_READY, &vcc->flags); + + up(&instance->serialize); + + atm_dbg(instance, "%s: allocated vcc data 0x%p\n", __func__, new); + + return 0; + +fail: + kfree(new); + up(&instance->serialize); + return ret; +} + +static void usbatm_atm_close(struct atm_vcc *vcc) +{ + struct usbatm_data *instance = vcc->dev->dev_data; + struct usbatm_vcc_data *vcc_data = vcc->dev_data; + + if (!instance || !vcc_data) { + dbg("%s: NULL data!", __func__); + return; + } + + atm_dbg(instance, "%s entered\n", __func__); + + atm_dbg(instance, "%s: deallocating vcc 0x%p with vpi %d vci %d\n", + __func__, vcc_data, vcc_data->vpi, vcc_data->vci); + + usbatm_cancel_send(instance, vcc); + + down(&instance->serialize); /* vs self, usbatm_atm_open */ + + tasklet_disable(&instance->rx_channel.tasklet); + list_del(&vcc_data->list); + tasklet_enable(&instance->rx_channel.tasklet); + + kfree_skb(vcc_data->sarb); + vcc_data->sarb = NULL; + + kfree(vcc_data); + vcc->dev_data = NULL; + + vcc->vpi = ATM_VPI_UNSPEC; + vcc->vci = ATM_VCI_UNSPEC; + clear_bit(ATM_VF_READY, &vcc->flags); + clear_bit(ATM_VF_PARTIAL, &vcc->flags); + clear_bit(ATM_VF_ADDR, &vcc->flags); + + up(&instance->serialize); + + atm_dbg(instance, "%s successful\n", __func__); +} + +static int usbatm_atm_ioctl(struct atm_dev *dev, unsigned int cmd, + void __user * arg) +{ + switch (cmd) { + case ATM_QUERYLOOP: + return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0; + default: + return -ENOIOCTLCMD; + } +} + +static int usbatm_atm_init(struct usbatm_data *instance) +{ + struct atm_dev *atm_dev; + int ret, i; + + /* ATM init */ + atm_dev = atm_dev_register(instance->driver_name, &usbatm_atm_devops, -1, NULL); + if (!atm_dev) { + usb_dbg(instance, "%s: failed to register ATM device!\n", __func__); + return -1; + } + + instance->atm_dev = atm_dev; + + atm_dev->ci_range.vpi_bits = ATM_CI_MAX; + atm_dev->ci_range.vci_bits = ATM_CI_MAX; + atm_dev->signal = ATM_PHY_SIG_UNKNOWN; + + /* temp init ATM device, set to 128kbit */ + atm_dev->link_rate = 128 * 1000 / 424; + + if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) { + atm_dbg(instance, "%s: atm_start failed: %d!\n", __func__, ret); + goto fail; + } + + /* ready for ATM callbacks */ + usbatm_get_instance(instance); /* dropped in usbatm_atm_dev_close */ + mb(); + atm_dev->dev_data = instance; + + /* submit all rx URBs */ + for (i = 0; i < num_rcv_urbs; i++) + usbatm_submit_urb(instance->urbs[i]); + + return 0; + + fail: + instance->atm_dev = NULL; + shutdown_atm_dev(atm_dev); /* usbatm_atm_dev_close will eventually be called */ + return ret; +} + + +/********** +** USB ** +**********/ + +static int usbatm_do_heavy_init(void *arg) +{ + struct usbatm_data *instance = arg; + int ret; + + daemonize(instance->driver->driver_name); + allow_signal(SIGTERM); + + complete(&instance->thread_started); + + ret = instance->driver->heavy_init(instance, instance->usb_intf); + + if (!ret) + ret = usbatm_atm_init(instance); + + down(&instance->serialize); + instance->thread_pid = -1; + up(&instance->serialize); + + complete_and_exit(&instance->thread_exited, ret); +} + +static int usbatm_heavy_init(struct usbatm_data *instance) +{ + int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_KERNEL); + + if (ret < 0) { + usb_dbg(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret); + return ret; + } + + down(&instance->serialize); + instance->thread_pid = ret; + up(&instance->serialize); + + wait_for_completion(&instance->thread_started); + + return 0; +} + +static void usbatm_tasklet_schedule(unsigned long data) +{ + tasklet_schedule((struct tasklet_struct *) data); +} + +static inline void usbatm_init_channel(struct usbatm_channel *channel) +{ + spin_lock_init(&channel->lock); + INIT_LIST_HEAD(&channel->list); + channel->delay.function = usbatm_tasklet_schedule; + channel->delay.data = (unsigned long) &channel->tasklet; + init_timer(&channel->delay); +} + +int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, + struct usbatm_driver *driver) +{ + struct device *dev = &intf->dev; + struct usb_device *usb_dev = interface_to_usbdev(intf); + struct usbatm_data *instance; + char *buf; + int error = -ENOMEM; + int i, length; + int need_heavy; + + dev_dbg(dev, "%s: trying driver %s with vendor=0x%x, product=0x%x, ifnum %d\n", + __func__, driver->driver_name, + le16_to_cpu(usb_dev->descriptor.idVendor), + le16_to_cpu(usb_dev->descriptor.idProduct), + intf->altsetting->desc.bInterfaceNumber); + + /* instance init */ + instance = kmalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), + GFP_KERNEL); + if (!instance) { + dev_dbg(dev, "%s: no memory for instance data!\n", __func__); + return -ENOMEM; + } + + memset(instance, 0, sizeof(*instance)); + + /* public fields */ + + instance->driver = driver; + snprintf(instance->driver_name, sizeof(instance->driver_name), driver->driver_name); + + instance->usb_dev = usb_dev; + instance->usb_intf = intf; + + buf = instance->description; + length = sizeof(instance->description); + + if ((i = usb_string(usb_dev, usb_dev->descriptor.iProduct, buf, length)) < 0) + goto bind; + + buf += i; + length -= i; + + i = scnprintf(buf, length, " ("); + buf += i; + length -= i; + + if (length <= 0 || (i = usb_make_path(usb_dev, buf, length)) < 0) + goto bind; + + buf += i; + length -= i; + + snprintf(buf, length, ")"); + + bind: + need_heavy = 1; + if (driver->bind && (error = driver->bind(instance, intf, id, &need_heavy)) < 0) { + dev_dbg(dev, "%s: bind failed: %d!\n", __func__, error); + goto fail_free; + } + + /* private fields */ + + kref_init(&instance->refcount); /* dropped in usbatm_usb_disconnect */ + init_MUTEX(&instance->serialize); + + instance->thread_pid = -1; + init_completion(&instance->thread_started); + init_completion(&instance->thread_exited); + + INIT_LIST_HEAD(&instance->vcc_list); + + usbatm_init_channel(&instance->rx_channel); + usbatm_init_channel(&instance->tx_channel); + tasklet_init(&instance->rx_channel.tasklet, usbatm_rx_process, (unsigned long)instance); + tasklet_init(&instance->tx_channel.tasklet, usbatm_tx_process, (unsigned long)instance); + instance->rx_channel.endpoint = usb_rcvbulkpipe(usb_dev, driver->in); + instance->tx_channel.endpoint = usb_sndbulkpipe(usb_dev, driver->out); + instance->rx_channel.stride = ATM_CELL_SIZE + driver->rx_padding; + instance->tx_channel.stride = ATM_CELL_SIZE + driver->tx_padding; + instance->rx_channel.buf_size = rcv_buf_size * instance->rx_channel.stride; + instance->tx_channel.buf_size = snd_buf_size * instance->tx_channel.stride; + instance->rx_channel.usbatm = instance->tx_channel.usbatm = instance; + + skb_queue_head_init(&instance->sndqueue); + + for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { + struct urb *urb; + u8 *buffer; + unsigned int iso_packets = 0, iso_size = 0; + struct usbatm_channel *channel = i < num_rcv_urbs ? + &instance->rx_channel : &instance->tx_channel; + + if (usb_pipeisoc(channel->endpoint)) { + /* don't expect iso out endpoints */ + iso_size = usb_maxpacket(instance->usb_dev, channel->endpoint, 0); + iso_size -= iso_size % channel->stride; /* alignment */ + BUG_ON(!iso_size); + iso_packets = (channel->buf_size - 1) / iso_size + 1; + } + + urb = usb_alloc_urb(iso_packets, GFP_KERNEL); + if (!urb) { + dev_dbg(dev, "%s: no memory for urb %d!\n", __func__, i); + goto fail_unbind; + } + + buffer = kmalloc(channel->buf_size, GFP_KERNEL); + if (!buffer) { + dev_dbg(dev, "%s: no memory for buffer %d!\n", __func__, i); + goto fail_unbind; + } + memset(buffer, 0, channel->buf_size); + + usb_fill_bulk_urb(urb, instance->usb_dev, channel->endpoint, + buffer, channel->buf_size, usbatm_complete, channel); + if (iso_packets) { + int j; + urb->interval = 1; + urb->transfer_flags = URB_ISO_ASAP; + urb->number_of_packets = iso_packets; + for (j = 0; j < iso_packets; j++) { + urb->iso_frame_desc[j].offset = iso_size * j; + urb->iso_frame_desc[j].length = min_t(int, iso_size, + channel->buf_size - urb->iso_frame_desc[j].offset); + } + } + + /* put all tx URBs on the list of spares */ + if (i >= num_rcv_urbs) + list_add_tail(&urb->urb_list, &channel->list); + + vdbg("%s: alloced buffer 0x%p buf size %u urb 0x%p", + __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb); + instance->urbs[i] = urb; + } + + if (need_heavy && driver->heavy_init) { + error = usbatm_heavy_init(instance); + } else { + complete(&instance->thread_exited); /* pretend that heavy_init was run */ + error = usbatm_atm_init(instance); + } + + if (error < 0) + goto fail_unbind; + + usb_get_dev(usb_dev); + usb_set_intfdata(intf, instance); + + return 0; + + fail_unbind: + if (instance->driver->unbind) + instance->driver->unbind(instance, intf); + fail_free: + for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { + if (instance->urbs[i]) + kfree(instance->urbs[i]->transfer_buffer); + usb_free_urb(instance->urbs[i]); + } + + kfree (instance); + + return error; +} +EXPORT_SYMBOL_GPL(usbatm_usb_probe); + +void usbatm_usb_disconnect(struct usb_interface *intf) +{ + struct device *dev = &intf->dev; + struct usbatm_data *instance = usb_get_intfdata(intf); + int i; + + dev_dbg(dev, "%s entered\n", __func__); + + if (!instance) { + dev_dbg(dev, "%s: NULL instance!\n", __func__); + return; + } + + usb_set_intfdata(intf, NULL); + + down(&instance->serialize); + if (instance->thread_pid >= 0) + kill_proc(instance->thread_pid, SIGTERM, 1); + up(&instance->serialize); + + wait_for_completion(&instance->thread_exited); + + tasklet_disable(&instance->rx_channel.tasklet); + tasklet_disable(&instance->tx_channel.tasklet); + + for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) + usb_kill_urb(instance->urbs[i]); + + del_timer_sync(&instance->rx_channel.delay); + del_timer_sync(&instance->tx_channel.delay); + + if (instance->atm_dev && instance->driver->atm_stop) + instance->driver->atm_stop(instance, instance->atm_dev); + + if (instance->driver->unbind) + instance->driver->unbind(instance, intf); + + instance->driver_data = NULL; + + /* turn usbatm_[rt]x_process into noop */ + /* no need to take the spinlock */ + INIT_LIST_HEAD(&instance->rx_channel.list); + INIT_LIST_HEAD(&instance->tx_channel.list); + + tasklet_enable(&instance->rx_channel.tasklet); + tasklet_enable(&instance->tx_channel.tasklet); + + for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { + kfree(instance->urbs[i]->transfer_buffer); + usb_free_urb(instance->urbs[i]); + } + + /* ATM finalize */ + if (instance->atm_dev) + shutdown_atm_dev(instance->atm_dev); + + usbatm_put_instance(instance); /* taken in usbatm_usb_probe */ +} +EXPORT_SYMBOL_GPL(usbatm_usb_disconnect); + + +/*********** +** init ** +***********/ + +static int __init usbatm_usb_init(void) +{ + dbg("%s: driver version %s", __func__, DRIVER_VERSION); + + if (sizeof(struct usbatm_control) > sizeof(((struct sk_buff *) 0)->cb)) { + printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name); + return -EIO; + } + + if ((num_rcv_urbs > UDSL_MAX_RCV_URBS) + || (num_snd_urbs > UDSL_MAX_SND_URBS) + || (rcv_buf_size < 1) + || (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE) + || (snd_buf_size < 1) + || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE)) + return -EINVAL; + + return 0; +} +module_init(usbatm_usb_init); + +static void __exit usbatm_usb_exit(void) +{ + dbg("%s", __func__); +} +module_exit(usbatm_usb_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); + +/************ +** debug ** +************/ + +#ifdef VERBOSE_DEBUG +static int usbatm_print_packet(const unsigned char *data, int len) +{ + unsigned char buffer[256]; + int i = 0, j = 0; + + for (i = 0; i < len;) { + buffer[0] = '\0'; + sprintf(buffer, "%.3d :", i); + for (j = 0; (j < 16) && (i < len); j++, i++) { + sprintf(buffer, "%s %2.2x", buffer, data[i]); + } + dbg("%s", buffer); + } + return i; +} +#endif diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h new file mode 100644 index 000000000000..2239804453cf --- /dev/null +++ b/drivers/usb/atm/usbatm.h @@ -0,0 +1,183 @@ +/****************************************************************************** + * usbatm.h - Generic USB xDSL driver core + * + * Copyright (C) 2001, Alcatel + * Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas + * Copyright (C) 2004, David Woodhouse + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ******************************************************************************/ + +#ifndef _USBATM_H_ +#define _USBATM_H_ + +#include + +/* +#define DEBUG +#define VERBOSE_DEBUG +*/ + +#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG) +# define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define UDSL_ASSERT(x) BUG_ON(!(x)) +#else +#define UDSL_ASSERT(x) do { if (!(x)) warn("failed assertion '%s' at line %d", __stringify(x), __LINE__); } while(0) +#endif + +#define usb_err(instance, format, arg...) \ + dev_err(&(instance)->usb_intf->dev , format , ## arg) +#define usb_info(instance, format, arg...) \ + dev_info(&(instance)->usb_intf->dev , format , ## arg) +#define usb_warn(instance, format, arg...) \ + dev_warn(&(instance)->usb_intf->dev , format , ## arg) +#define usb_dbg(instance, format, arg...) \ + dev_dbg(&(instance)->usb_intf->dev , format , ## arg) + +/* FIXME: move to dev_* once ATM is driver model aware */ +#define atm_printk(level, instance, format, arg...) \ + printk(level "ATM dev %d: " format , (instance)->atm_dev->number, ## arg) + +#define atm_err(instance, format, arg...) \ + atm_printk(KERN_ERR, instance , format , ## arg) +#define atm_info(instance, format, arg...) \ + atm_printk(KERN_INFO, instance , format , ## arg) +#define atm_warn(instance, format, arg...) \ + atm_printk(KERN_WARNING, instance , format , ## arg) +#ifdef DEBUG +#define atm_dbg(instance, format, arg...) \ + atm_printk(KERN_DEBUG, instance , format , ## arg) +#else +#define atm_dbg(instance, format, arg...) \ + do {} while (0) +#endif + + +/* mini driver */ + +struct usbatm_data; + +/* +* Assuming all methods exist and succeed, they are called in this order: +* +* bind, heavy_init, atm_start, ..., atm_stop, unbind +*/ + +struct usbatm_driver { + struct module *owner; + + const char *driver_name; + + /* + * init device ... can sleep, or cause probe() failure. Drivers with a heavy_init + * method can avoid having it called by setting need_heavy_init to zero. + */ + int (*bind) (struct usbatm_data *, struct usb_interface *, + const struct usb_device_id *id, int *need_heavy_init); + + /* additional device initialization that is too slow to be done in probe() */ + int (*heavy_init) (struct usbatm_data *, struct usb_interface *); + + /* cleanup device ... can sleep, but can't fail */ + void (*unbind) (struct usbatm_data *, struct usb_interface *); + + /* init ATM device ... can sleep, or cause ATM initialization failure */ + int (*atm_start) (struct usbatm_data *, struct atm_dev *); + + /* cleanup ATM device ... can sleep, but can't fail */ + void (*atm_stop) (struct usbatm_data *, struct atm_dev *); + + int in; /* rx endpoint */ + int out; /* tx endpoint */ + + unsigned rx_padding; + unsigned tx_padding; +}; + +extern int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, + struct usbatm_driver *driver); +extern void usbatm_usb_disconnect(struct usb_interface *intf); + + +struct usbatm_channel { + int endpoint; /* usb pipe */ + unsigned int stride; /* ATM cell size + padding */ + unsigned int buf_size; /* urb buffer size */ + spinlock_t lock; + struct list_head list; + struct tasklet_struct tasklet; + struct timer_list delay; + struct usbatm_data *usbatm; +}; + +/* main driver data */ + +struct usbatm_data { + /****************** + * public fields * + ******************/ + + /* mini driver */ + struct usbatm_driver *driver; + void *driver_data; + char driver_name[16]; + + /* USB device */ + struct usb_device *usb_dev; + struct usb_interface *usb_intf; + char description[64]; + + /* ATM device */ + struct atm_dev *atm_dev; + + /******************************** + * private fields - do not use * + ********************************/ + + struct kref refcount; + struct semaphore serialize; + + /* heavy init */ + int thread_pid; + struct completion thread_started; + struct completion thread_exited; + + /* ATM device */ + struct list_head vcc_list; + + struct usbatm_channel rx_channel; + struct usbatm_channel tx_channel; + + struct sk_buff_head sndqueue; + struct sk_buff *current_skb; /* being emptied */ + + struct urb *urbs[0]; +}; + +#endif /* _USBATM_H_ */ -- cgit v1.2.3 From 9574507c98087951866ef30c8bf876e23ca4b99e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 11 May 2005 20:24:03 +0200 Subject: [PATCH] USB: fix speedtch.c merge with next patch. Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 2a1697bfd695..233f9229badb 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -386,8 +386,6 @@ static void speedtch_poll_status(struct speedtch_instance_data *instance) if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) { instance->u.atm_dev->signal = ATM_PHY_SIG_LOST; printk(KERN_NOTICE "ADSL line is down\n"); - /* It'll never resync again unless we ask it to... */ - speedtch_start_synchro(instance); } break; -- cgit v1.2.3 From 48da7267ff1631b0bff1eab15db86adace11ea91 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Wed, 11 May 2005 20:20:40 +0200 Subject: [PATCH] USB ATM: port speedtch to new usbatm core Port the speedtch driver to the new usbatm core. The code is much the same as before, just reorganized, though I threw in some minor improvements (a new module parameter for choosing the altsetting, more robust urb failure handling, ...) while I was there. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 1085 ++++++++++++++++++++++---------------------- 1 file changed, 533 insertions(+), 552 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 233f9229badb..6a6eaa2a3b1c 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -5,6 +5,8 @@ * Copyright (C) 2003, Duncan Sands * Copyright (C) 2004, David Woodhouse * + * Based on "modem_run.c", copyright (C) 2001, Benoit Papillault + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) @@ -21,819 +23,798 @@ * ******************************************************************************/ -#include -#include +#include +#include +#include +#include #include +#include #include -#include -#include -#include -#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "usb_atm.h" +#include +#include +#include -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -# define USE_FW_LOADER -#endif +#include "usbatm.h" #define DRIVER_AUTHOR "Johan Verrept, Duncan Sands " -#define DRIVER_VERSION "1.8" +#define DRIVER_VERSION "1.9" #define DRIVER_DESC "Alcatel SpeedTouch USB driver version " DRIVER_VERSION static const char speedtch_driver_name[] = "speedtch"; -#define SPEEDTOUCH_VENDORID 0x06b9 -#define SPEEDTOUCH_PRODUCTID 0x4061 +#define CTRL_TIMEOUT 2000 /* milliseconds */ +#define DATA_TIMEOUT 2000 /* milliseconds */ -/* Timeout in jiffies */ -#define CTRL_TIMEOUT 2000 -#define DATA_TIMEOUT 2000 +#define OFFSET_7 0 /* size 1 */ +#define OFFSET_b 1 /* size 8 */ +#define OFFSET_d 9 /* size 4 */ +#define OFFSET_e 13 /* size 1 */ +#define OFFSET_f 14 /* size 1 */ +#define TOTAL 15 -#define OFFSET_7 0 /* size 1 */ -#define OFFSET_b 1 /* size 8 */ -#define OFFSET_d 9 /* size 4 */ -#define OFFSET_e 13 /* size 1 */ -#define OFFSET_f 14 /* size 1 */ -#define TOTAL 15 +#define SIZE_7 1 +#define SIZE_b 8 +#define SIZE_d 4 +#define SIZE_e 1 +#define SIZE_f 1 -#define SIZE_7 1 -#define SIZE_b 8 -#define SIZE_d 4 -#define SIZE_e 1 -#define SIZE_f 1 +#define MIN_POLL_DELAY 5000 /* milliseconds */ +#define MAX_POLL_DELAY 60000 /* milliseconds */ -static int dl_512_first = 0; -static int sw_buffering = 0; +#define RESUBMIT_DELAY 1000 /* milliseconds */ -module_param(dl_512_first, bool, 0444); -MODULE_PARM_DESC(dl_512_first, "Read 512 bytes before sending firmware"); +#define DEFAULT_ALTSETTING 1 +#define DEFAULT_DL_512_FIRST 0 +#define DEFAULT_SW_BUFFERING 0 -module_param(sw_buffering, uint, 0444); -MODULE_PARM_DESC(sw_buffering, "Enable software buffering"); +static int altsetting = DEFAULT_ALTSETTING; +static int dl_512_first = DEFAULT_DL_512_FIRST; +static int sw_buffering = DEFAULT_SW_BUFFERING; -#define UDSL_IOCTL_LINE_UP 1 -#define UDSL_IOCTL_LINE_DOWN 2 +module_param(altsetting, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(altsetting, + "Alternative setting for data interface (default: " + __MODULE_STRING(DEFAULT_ALTSETTING) ")"); -#define SPEEDTCH_ENDPOINT_INT 0x81 -#define SPEEDTCH_ENDPOINT_DATA 0x07 -#define SPEEDTCH_ENDPOINT_FIRMWARE 0x05 +module_param(dl_512_first, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dl_512_first, + "Read 512 bytes before sending firmware (default: " + __MODULE_STRING(DEFAULT_DL_512_FIRST) ")"); -#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) ) +module_param(sw_buffering, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(sw_buffering, + "Enable software buffering (default: " + __MODULE_STRING(DEFAULT_SW_BUFFERING) ")"); -static struct usb_device_id speedtch_usb_ids[] = { - {USB_DEVICE(SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID)}, - {} -}; +#define ENDPOINT_INT 0x81 +#define ENDPOINT_DATA 0x07 +#define ENDPOINT_FIRMWARE 0x05 -MODULE_DEVICE_TABLE(usb, speedtch_usb_ids); +#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) ) struct speedtch_instance_data { - struct udsl_instance_data u; + struct usbatm_data *usbatm; + + struct work_struct status_checker; - /* Status */ + int poll_delay; /* milliseconds */ + + struct timer_list resubmit_timer; struct urb *int_urb; unsigned char int_data[16]; - struct work_struct poll_work; - struct timer_list poll_timer; -}; -/* USB */ - -static int speedtch_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id); -static void speedtch_usb_disconnect(struct usb_interface *intf); -static int speedtch_usb_ioctl(struct usb_interface *intf, unsigned int code, - void *user_data); -static void speedtch_handle_int(struct urb *urb, struct pt_regs *regs); -static void speedtch_poll_status(struct speedtch_instance_data *instance); -static struct usb_driver speedtch_usb_driver = { - .owner = THIS_MODULE, - .name = speedtch_driver_name, - .probe = speedtch_usb_probe, - .disconnect = speedtch_usb_disconnect, - .ioctl = speedtch_usb_ioctl, - .id_table = speedtch_usb_ids, + unsigned char scratch_buffer[TOTAL]; }; /*************** ** firmware ** ***************/ -static void speedtch_got_firmware(struct speedtch_instance_data *instance, - int got_it) +static void speedtch_set_swbuff(struct speedtch_instance_data *instance, int state) { - int err; - struct usb_interface *intf; - - down(&instance->u.serialize); /* vs self, speedtch_firmware_start */ - if (instance->u.status == UDSL_LOADED_FIRMWARE) - goto out; - if (!got_it) { - instance->u.status = UDSL_NO_FIRMWARE; - goto out; - } - if ((err = usb_set_interface(instance->u.usb_dev, 1, 1)) < 0) { - dbg("speedtch_got_firmware: usb_set_interface returned %d!", err); - instance->u.status = UDSL_NO_FIRMWARE; - goto out; - } - - /* Set up interrupt endpoint */ - intf = usb_ifnum_to_if(instance->u.usb_dev, 0); - if (intf && !usb_driver_claim_interface(&speedtch_usb_driver, intf, NULL)) { - - instance->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (instance->int_urb) { - - usb_fill_int_urb(instance->int_urb, instance->u.usb_dev, - usb_rcvintpipe(instance->u.usb_dev, SPEEDTCH_ENDPOINT_INT), - instance->int_data, - sizeof(instance->int_data), - speedtch_handle_int, instance, 50); - err = usb_submit_urb(instance->int_urb, GFP_KERNEL); - if (err) { - /* Doesn't matter; we'll poll anyway */ - dbg("speedtch_got_firmware: Submission of interrupt URB failed %d", err); - usb_free_urb(instance->int_urb); - instance->int_urb = NULL; - usb_driver_release_interface(&speedtch_usb_driver, intf); - } - } - } - /* Start status polling */ - mod_timer(&instance->poll_timer, jiffies + (1 * HZ)); - - instance->u.status = UDSL_LOADED_FIRMWARE; - tasklet_schedule(&instance->u.receive_tasklet); - out: - up(&instance->u.serialize); - wake_up_interruptible(&instance->u.firmware_waiters); -} - -static int speedtch_set_swbuff(struct speedtch_instance_data *instance, - int state) -{ - struct usb_device *dev = instance->u.usb_dev; + struct usbatm_data *usbatm = instance->usbatm; + struct usb_device *usb_dev = usbatm->usb_dev; int ret; - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x32, 0x40, state ? 0x01 : 0x00, - 0x00, NULL, 0, 100); - if (ret < 0) { - printk("Warning: %sabling SW buffering: usb_control_msg returned %d\n", - state ? "En" : "Dis", ret); - return ret; - } - - dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis"); - return 0; + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x32, 0x40, state ? 0x01 : 0x00, 0x00, NULL, 0, CTRL_TIMEOUT); + if (ret < 0) + usb_warn(usbatm, + "%sabling SW buffering: usb_control_msg returned %d\n", + state ? "En" : "Dis", ret); + else + dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis"); } static void speedtch_test_sequence(struct speedtch_instance_data *instance) { - struct usb_device *dev = instance->u.usb_dev; - unsigned char buf[10]; + struct usbatm_data *usbatm = instance->usbatm; + struct usb_device *usb_dev = usbatm->usb_dev; + unsigned char *buf = instance->scratch_buffer; int ret; /* URB 147 */ buf[0] = 0x1c; buf[1] = 0x50; - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x01, 0x40, 0x0b, 0x00, buf, 2, 100); + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x0b, 0x00, buf, 2, CTRL_TIMEOUT); if (ret < 0) - printk(KERN_WARNING "%s failed on URB147: %d\n", __func__, ret); + usb_warn(usbatm, "%s failed on URB147: %d\n", __func__, ret); /* URB 148 */ buf[0] = 0x32; buf[1] = 0x00; - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x01, 0x40, 0x02, 0x00, buf, 2, 100); + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x02, 0x00, buf, 2, CTRL_TIMEOUT); if (ret < 0) - printk(KERN_WARNING "%s failed on URB148: %d\n", __func__, ret); + usb_warn(usbatm, "%s failed on URB148: %d\n", __func__, ret); /* URB 149 */ buf[0] = 0x01; buf[1] = 0x00; buf[2] = 0x01; - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x01, 0x40, 0x03, 0x00, buf, 3, 100); + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x03, 0x00, buf, 3, CTRL_TIMEOUT); if (ret < 0) - printk(KERN_WARNING "%s failed on URB149: %d\n", __func__, ret); + usb_warn(usbatm, "%s failed on URB149: %d\n", __func__, ret); /* URB 150 */ buf[0] = 0x01; buf[1] = 0x00; buf[2] = 0x01; - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x01, 0x40, 0x04, 0x00, buf, 3, 100); + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT); if (ret < 0) - printk(KERN_WARNING "%s failed on URB150: %d\n", __func__, ret); + usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret); } -static int speedtch_start_synchro(struct speedtch_instance_data *instance) +static int speedtch_upload_firmware(struct speedtch_instance_data *instance, + const struct firmware *fw1, + const struct firmware *fw2) { - struct usb_device *dev = instance->u.usb_dev; - unsigned char buf[2]; - int ret; + unsigned char *buffer; + struct usbatm_data *usbatm = instance->usbatm; + struct usb_interface *intf; + struct usb_device *usb_dev = usbatm->usb_dev; + int actual_length; + int ret = 0; + int offset; + + usb_dbg(usbatm, "%s entered\n", __func__); + + if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) { + ret = -ENOMEM; + usb_dbg(usbatm, "%s: no memory for buffer!\n", __func__); + goto out; + } + + if (!(intf = usb_ifnum_to_if(usb_dev, 2))) { + ret = -ENODEV; + usb_dbg(usbatm, "%s: interface not found!\n", __func__); + goto out_free; + } + + /* 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, ENDPOINT_FIRMWARE), + buffer, 0x200, &actual_length, 2000); + + if (ret < 0 && ret != -ETIMEDOUT) + usb_dbg(usbatm, "%s: read BLOCK0 from modem failed (%d)!\n", __func__, ret); + else + usb_dbg(usbatm, "%s: BLOCK0 downloaded (%d bytes)\n", __func__, ret); + } + + /* URB 8 : both leds are static green */ + for (offset = 0; offset < fw1->size; offset += PAGE_SIZE) { + int thislen = min_t(int, PAGE_SIZE, fw1->size - offset); + memcpy(buffer, fw1->data + offset, thislen); + + ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE), + buffer, thislen, &actual_length, DATA_TIMEOUT); + + if (ret < 0) { + usb_dbg(usbatm, "%s: write BLOCK1 to modem failed (%d)!\n", __func__, ret); + goto out_free; + } + usb_dbg(usbatm, "%s: BLOCK1 uploaded (%zu bytes)\n", __func__, fw1->size); + } + + /* USB led blinking green, ADSL led off */ + + /* URB 11 */ + ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE), + buffer, 0x200, &actual_length, DATA_TIMEOUT); - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - 0x12, 0xc0, 0x04, 0x00, - buf, sizeof(buf), CTRL_TIMEOUT); if (ret < 0) { - printk(KERN_WARNING "SpeedTouch: Failed to start ADSL synchronisation: %d\n", ret); - return ret; + usb_dbg(usbatm, "%s: read BLOCK2 from modem failed (%d)!\n", __func__, ret); + goto out_free; } + usb_dbg(usbatm, "%s: BLOCK2 downloaded (%d bytes)\n", __func__, actual_length); - dbg("speedtch_start_synchro: modem prodded. %d Bytes returned: %02x %02x", ret, buf[0], buf[1]); - return 0; + /* URBs 12 to 139 - USB led blinking green, ADSL led off */ + for (offset = 0; offset < fw2->size; offset += PAGE_SIZE) { + int thislen = min_t(int, PAGE_SIZE, fw2->size - offset); + memcpy(buffer, fw2->data + offset, thislen); + + ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE), + buffer, thislen, &actual_length, DATA_TIMEOUT); + + if (ret < 0) { + usb_dbg(usbatm, "%s: write BLOCK3 to modem failed (%d)!\n", __func__, ret); + goto out_free; + } + } + usb_dbg(usbatm, "%s: BLOCK3 uploaded (%zu bytes)\n", __func__, fw2->size); + + /* USB led static green, ADSL led static red */ + + /* URB 142 */ + ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE), + buffer, 0x200, &actual_length, DATA_TIMEOUT); + + if (ret < 0) { + usb_dbg(usbatm, "%s: read BLOCK4 from modem failed (%d)!\n", __func__, ret); + goto out_free; + } + + /* success */ + usb_dbg(usbatm, "%s: BLOCK4 downloaded (%d bytes)\n", __func__, actual_length); + + /* Delay to allow firmware to start up. We can do this here + because we're in our own kernel thread anyway. */ + msleep_interruptible(1000); + + /* Enable software buffering, if requested */ + if (sw_buffering) + speedtch_set_swbuff(instance, 1); + + /* Magic spell; don't ask us what this does */ + speedtch_test_sequence(instance); + + ret = 0; + +out_free: + free_page((unsigned long)buffer); +out: + return ret; } -static void speedtch_handle_int(struct urb *urb, struct pt_regs *regs) +static int speedtch_find_firmware(struct usb_interface *intf, int phase, + const struct firmware **fw_p) { - struct speedtch_instance_data *instance = urb->context; - unsigned int count = urb->actual_length; - int ret; + struct device *dev = &intf->dev; + const u16 bcdDevice = le16_to_cpu(interface_to_usbdev(intf)->descriptor.bcdDevice); + const u8 major_revision = bcdDevice >> 8; + const u8 minor_revision = bcdDevice & 0xff; + char buf[24]; - /* The magic interrupt for "up state" */ - const static unsigned char up_int[6] = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 }; - /* The magic interrupt for "down state" */ - const static unsigned char down_int[6] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00 }; + sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision); + dev_dbg(dev, "%s: looking for %s\n", __func__, buf); - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated; clean up */ - dbg("%s - urb shutting down with status: %d", __func__, urb->status); - return; - default: - dbg("%s - nonzero urb status received: %d", __func__, urb->status); - goto exit; - } + if (request_firmware(fw_p, buf, dev)) { + sprintf(buf, "speedtch-%d.bin.%x", phase, major_revision); + dev_dbg(dev, "%s: looking for %s\n", __func__, buf); - if (count < 6) { - dbg("%s - int packet too short", __func__); - goto exit; + if (request_firmware(fw_p, buf, dev)) { + sprintf(buf, "speedtch-%d.bin", phase); + dev_dbg(dev, "%s: looking for %s\n", __func__, buf); + + if (request_firmware(fw_p, buf, dev)) { + dev_warn(dev, "no stage %d firmware found!\n", phase); + return -ENOENT; + } + } } - if (!memcmp(up_int, instance->int_data, 6)) { - del_timer(&instance->poll_timer); - printk(KERN_NOTICE "DSL line goes up\n"); - } else if (!memcmp(down_int, instance->int_data, 6)) { - printk(KERN_NOTICE "DSL line goes down\n"); - } else { - int i; + dev_info(dev, "found stage %d firmware %s\n", phase, buf); - printk(KERN_DEBUG "Unknown interrupt packet of %d bytes:", count); - for (i = 0; i < count; i++) - printk(" %02x", instance->int_data[i]); - printk("\n"); + return 0; +} + +static int speedtch_heavy_init(struct usbatm_data *usbatm, struct usb_interface *intf) +{ + const struct firmware *fw1, *fw2; + struct speedtch_instance_data *instance = usbatm->driver_data; + int ret; + + if ((ret = speedtch_find_firmware(intf, 1, &fw1)) < 0) + return ret; + + if ((ret = speedtch_find_firmware(intf, 2, &fw2)) < 0) { + release_firmware(fw1); + return ret; } - schedule_work(&instance->poll_work); - exit: - rmb(); - if (!instance->int_urb) - return; + ret = speedtch_upload_firmware(instance, fw1, fw2); + + release_firmware(fw2); + release_firmware(fw1); - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) - err("%s - usb_submit_urb failed with result %d", __func__, ret); + return ret; } -static int speedtch_get_status(struct speedtch_instance_data *instance, - unsigned char *buf) + +/********** +** ATM ** +**********/ + +static int speedtch_read_status(struct speedtch_instance_data *instance) { - struct usb_device *dev = instance->u.usb_dev; + struct usbatm_data *usbatm = instance->usbatm; + struct usb_device *usb_dev = usbatm->usb_dev; + unsigned char *buf = instance->scratch_buffer; int ret; memset(buf, 0, TOTAL); - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7, CTRL_TIMEOUT); if (ret < 0) { - dbg("MSG 7 failed"); + atm_dbg(usbatm, "%s: MSG 7 failed\n", __func__); return ret; } - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 0x12, 0xc0, 0x0b, 0x00, buf + OFFSET_b, SIZE_b, CTRL_TIMEOUT); if (ret < 0) { - dbg("MSG B failed"); + atm_dbg(usbatm, "%s: MSG B failed\n", __func__); return ret; } - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 0x12, 0xc0, 0x0d, 0x00, buf + OFFSET_d, SIZE_d, CTRL_TIMEOUT); if (ret < 0) { - dbg("MSG D failed"); + atm_dbg(usbatm, "%s: MSG D failed\n", __func__); return ret; } - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 0x01, 0xc0, 0x0e, 0x00, buf + OFFSET_e, SIZE_e, CTRL_TIMEOUT); if (ret < 0) { - dbg("MSG E failed"); + atm_dbg(usbatm, "%s: MSG E failed\n", __func__); return ret; } - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 0x01, 0xc0, 0x0f, 0x00, buf + OFFSET_f, SIZE_f, CTRL_TIMEOUT); if (ret < 0) { - dbg("MSG F failed"); + atm_dbg(usbatm, "%s: MSG F failed\n", __func__); return ret; } return 0; } -static void speedtch_poll_status(struct speedtch_instance_data *instance) +static int speedtch_start_synchro(struct speedtch_instance_data *instance) { - unsigned char buf[TOTAL]; + struct usbatm_data *usbatm = instance->usbatm; + struct usb_device *usb_dev = usbatm->usb_dev; + unsigned char *buf = instance->scratch_buffer; int ret; - ret = speedtch_get_status(instance, buf); - if (ret) { - printk(KERN_WARNING - "SpeedTouch: Error %d fetching device status\n", ret); + atm_dbg(usbatm, "%s entered\n", __func__); + + memset(buf, 0, 2); + + ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), + 0x12, 0xc0, 0x04, 0x00, + buf, 2, CTRL_TIMEOUT); + + if (ret < 0) + atm_warn(usbatm, "failed to start ADSL synchronisation: %d\n", ret); + else + atm_dbg(usbatm, "%s: modem prodded. %d bytes returned: %02x %02x\n", + __func__, ret, buf[0], buf[1]); + + return ret; +} + +static void speedtch_check_status(struct speedtch_instance_data *instance) +{ + struct usbatm_data *usbatm = instance->usbatm; + struct atm_dev *atm_dev = usbatm->atm_dev; + unsigned char *buf = instance->scratch_buffer; + int ret; + + atm_dbg(usbatm, "%s entered\n", __func__); + + ret = speedtch_read_status(instance); + if (ret < 0) { + atm_warn(usbatm, "error %d fetching device status\n", ret); + if (instance->poll_delay < MAX_POLL_DELAY) + instance->poll_delay *= 2; return; } - dbg("Line state %02x", buf[OFFSET_7]); + if (instance->poll_delay > MIN_POLL_DELAY) + instance->poll_delay /= 2; + + atm_dbg(usbatm, "%s: line state %02x\n", __func__, buf[OFFSET_7]); switch (buf[OFFSET_7]) { case 0: - if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) { - instance->u.atm_dev->signal = ATM_PHY_SIG_LOST; - printk(KERN_NOTICE "ADSL line is down\n"); + if (atm_dev->signal != ATM_PHY_SIG_LOST) { + atm_dev->signal = ATM_PHY_SIG_LOST; + atm_info(usbatm, "ADSL line is down\n"); + /* It'll never resync again unless we ask it to... */ + ret = speedtch_start_synchro(instance); } break; case 0x08: - if (instance->u.atm_dev->signal != ATM_PHY_SIG_UNKNOWN) { - instance->u.atm_dev->signal = ATM_PHY_SIG_UNKNOWN; - printk(KERN_NOTICE "ADSL line is blocked?\n"); + if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) { + atm_dev->signal = ATM_PHY_SIG_UNKNOWN; + atm_info(usbatm, "ADSL line is blocked?\n"); } break; case 0x10: - if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) { - instance->u.atm_dev->signal = ATM_PHY_SIG_LOST; - printk(KERN_NOTICE "ADSL line is synchronising\n"); + if (atm_dev->signal != ATM_PHY_SIG_LOST) { + atm_dev->signal = ATM_PHY_SIG_LOST; + atm_info(usbatm, "ADSL line is synchronising\n"); } break; case 0x20: - if (instance->u.atm_dev->signal != ATM_PHY_SIG_FOUND) { + if (atm_dev->signal != ATM_PHY_SIG_FOUND) { int down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8) | (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24); int up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8) | (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24); - if (!(down_speed & 0x0000ffff) && - !(up_speed & 0x0000ffff)) { + if (!(down_speed & 0x0000ffff) && !(up_speed & 0x0000ffff)) { down_speed >>= 16; up_speed >>= 16; } - instance->u.atm_dev->link_rate = down_speed * 1000 / 424; - instance->u.atm_dev->signal = ATM_PHY_SIG_FOUND; - printk(KERN_NOTICE - "ADSL line is up (%d Kib/s down | %d Kib/s up)\n", - down_speed, up_speed); + atm_dev->link_rate = down_speed * 1000 / 424; + atm_dev->signal = ATM_PHY_SIG_FOUND; + + atm_info(usbatm, + "ADSL line is up (%d Kib/s down | %d Kib/s up)\n", + down_speed, up_speed); } break; default: - if (instance->u.atm_dev->signal != ATM_PHY_SIG_UNKNOWN) { - instance->u.atm_dev->signal = ATM_PHY_SIG_UNKNOWN; - printk(KERN_NOTICE "Unknown line state %02x\n", buf[OFFSET_7]); + if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) { + atm_dev->signal = ATM_PHY_SIG_UNKNOWN; + atm_info(usbatm, "Unknown line state %02x\n", buf[OFFSET_7]); } break; } } -static void speedtch_timer_poll(unsigned long data) +static void speedtch_status_poll(unsigned long data) { struct speedtch_instance_data *instance = (void *)data; - schedule_work(&instance->poll_work); - mod_timer(&instance->poll_timer, jiffies + (5 * HZ)); + schedule_work(&instance->status_checker); + + /* The following check is racy, but the race is harmless */ + if (instance->poll_delay < MAX_POLL_DELAY) + mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(instance->poll_delay)); + else + atm_warn(instance->usbatm, "Too many failures - disabling line status polling\n"); } -#ifdef USE_FW_LOADER -static void speedtch_upload_firmware(struct speedtch_instance_data *instance, - const struct firmware *fw1, - const struct firmware *fw2) +static void speedtch_resubmit_int(unsigned long data) { - unsigned char *buffer; - struct usb_device *usb_dev = instance->u.usb_dev; - struct usb_interface *intf; - int actual_length, ret; - int offset; - - dbg("speedtch_upload_firmware"); - - if (!(intf = usb_ifnum_to_if(usb_dev, 2))) { - dbg("speedtch_upload_firmware: interface not found!"); - goto fail; - } - - if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) { - dbg("speedtch_upload_firmware: no memory for buffer!"); - goto fail; - } - - /* A user-space firmware loader may already have claimed interface #2 */ - if ((ret = - usb_driver_claim_interface(&speedtch_usb_driver, intf, NULL)) < 0) { - dbg("speedtch_upload_firmware: interface in use (%d)!", ret); - goto fail_free; - } - - /* 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, 2000); - - if (ret < 0 && ret != -ETIMEDOUT) - dbg("speedtch_upload_firmware: read BLOCK0 from modem failed (%d)!", ret); - else - dbg("speedtch_upload_firmware: BLOCK0 downloaded (%d bytes)", ret); - } - - /* URB 8 : both leds are static green */ - for (offset = 0; offset < fw1->size; offset += PAGE_SIZE) { - int thislen = min_t(int, PAGE_SIZE, fw1->size - offset); - memcpy(buffer, fw1->data + offset, thislen); + struct speedtch_instance_data *instance = (void *)data; + struct urb *int_urb = instance->int_urb; + int ret; - ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE), - buffer, thislen, &actual_length, DATA_TIMEOUT); + atm_dbg(instance->usbatm, "%s entered\n", __func__); - if (ret < 0) { - dbg("speedtch_upload_firmware: write BLOCK1 to modem failed (%d)!", ret); - goto fail_release; + if (int_urb) { + ret = usb_submit_urb(int_urb, GFP_ATOMIC); + if (!ret) + schedule_work(&instance->status_checker); + else { + atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret); + mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY)); } - dbg("speedtch_upload_firmware: BLOCK1 uploaded (%zu bytes)", fw1->size); } +} - /* USB led blinking green, ADSL led off */ +static void speedtch_handle_int(struct urb *int_urb, struct pt_regs *regs) +{ + struct speedtch_instance_data *instance = int_urb->context; + struct usbatm_data *usbatm = instance->usbatm; + unsigned int count = int_urb->actual_length; + int ret = int_urb->status; - /* URB 11 */ - ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE), - buffer, 0x200, &actual_length, DATA_TIMEOUT); + /* The magic interrupt for "up state" */ + const static unsigned char up_int[6] = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 }; + /* The magic interrupt for "down state" */ + const static unsigned char down_int[6] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + atm_dbg(usbatm, "%s entered\n", __func__); if (ret < 0) { - dbg("speedtch_upload_firmware: read BLOCK2 from modem failed (%d)!", ret); - goto fail_release; + atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret); + goto fail; } - dbg("speedtch_upload_firmware: BLOCK2 downloaded (%d bytes)", actual_length); - /* URBs 12 to 139 - USB led blinking green, ADSL led off */ - for (offset = 0; offset < fw2->size; offset += PAGE_SIZE) { - int thislen = min_t(int, PAGE_SIZE, fw2->size - offset); - memcpy(buffer, fw2->data + offset, thislen); + if ((count == 6) && !memcmp(up_int, instance->int_data, 6)) { + del_timer(&instance->status_checker.timer); + atm_info(usbatm, "DSL line goes up\n"); + } else if ((count == 6) && !memcmp(down_int, instance->int_data, 6)) { + atm_info(usbatm, "DSL line goes down\n"); + } else { + int i; - ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE), - buffer, thislen, &actual_length, DATA_TIMEOUT); + atm_dbg(usbatm, "%s: unknown interrupt packet of length %d:", __func__, count); + for (i = 0; i < count; i++) + printk(" %02x", instance->int_data[i]); + printk("\n"); + goto fail; + } + if ((int_urb = instance->int_urb)) { + ret = usb_submit_urb(int_urb, GFP_ATOMIC); + schedule_work(&instance->status_checker); if (ret < 0) { - dbg("speedtch_upload_firmware: write BLOCK3 to modem failed (%d)!", ret); - goto fail_release; + atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret); + goto fail; } } - dbg("speedtch_upload_firmware: BLOCK3 uploaded (%zu bytes)", fw2->size); - - /* USB led static green, ADSL led static red */ - - /* URB 142 */ - ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE), - buffer, 0x200, &actual_length, DATA_TIMEOUT); - - if (ret < 0) { - dbg("speedtch_upload_firmware: read BLOCK4 from modem failed (%d)!", ret); - goto fail_release; - } - - /* success */ - dbg("speedtch_upload_firmware: BLOCK4 downloaded (%d bytes)", actual_length); - - /* Delay to allow firmware to start up. We can do this here - because we're in our own kernel thread anyway. */ - msleep(1000); - - /* Enable software buffering, if requested */ - if (sw_buffering) - speedtch_set_swbuff(instance, 1); - - /* Magic spell; don't ask us what this does */ - speedtch_test_sequence(instance); - - /* Start modem synchronisation */ - if (speedtch_start_synchro(instance)) - dbg("speedtch_start_synchro: failed"); - - speedtch_got_firmware(instance, 1); - free_page((unsigned long)buffer); return; - fail_release: - /* Only release interface #2 if uploading failed; we don't release it - we succeeded. This prevents the userspace tools from trying to load - the firmware themselves */ - usb_driver_release_interface(&speedtch_usb_driver, intf); - fail_free: - free_page((unsigned long)buffer); - fail: - speedtch_got_firmware(instance, 0); +fail: + if ((int_urb = instance->int_urb)) + mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY)); } -static int speedtch_find_firmware(struct speedtch_instance_data - *instance, int phase, - const struct firmware **fw_p) +static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_dev) { - char buf[24]; - const u16 bcdDevice = le16_to_cpu(instance->u.usb_dev->descriptor.bcdDevice); - const u8 major_revision = bcdDevice >> 8; - const u8 minor_revision = bcdDevice & 0xff; - - sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision); - dbg("speedtch_find_firmware: looking for %s", buf); - - if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) { - sprintf(buf, "speedtch-%d.bin.%x", phase, major_revision); - dbg("speedtch_find_firmware: looking for %s", buf); + struct usb_device *usb_dev = usbatm->usb_dev; + struct speedtch_instance_data *instance = usbatm->driver_data; + int i, ret; + unsigned char mac_str[13]; - if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) { - sprintf(buf, "speedtch-%d.bin", phase); - dbg("speedtch_find_firmware: looking for %s", buf); + atm_dbg(usbatm, "%s entered\n", __func__); - if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) { - dev_warn(&instance->u.usb_dev->dev, "no stage %d firmware found!", phase); - return -ENOENT; - } - } + if ((ret = usb_set_interface(usb_dev, 1, altsetting)) < 0) { + atm_dbg(usbatm, "%s: usb_set_interface returned %d!\n", __func__, ret); + return ret; } - dev_info(&instance->u.usb_dev->dev, "found stage %d firmware %s\n", phase, buf); - - return 0; -} - -static int speedtch_load_firmware(void *arg) -{ - const struct firmware *fw1, *fw2; - struct speedtch_instance_data *instance = arg; - - BUG_ON(!instance); + /* Set MAC address, it is stored in the serial number */ + memset(atm_dev->esi, 0, sizeof(atm_dev->esi)); + if (usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) { + for (i = 0; i < 6; i++) + atm_dev->esi[i] = (hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1])); + } - daemonize("firmware/speedtch"); + /* Start modem synchronisation */ + ret = speedtch_start_synchro(instance); - if (!speedtch_find_firmware(instance, 1, &fw1)) { - if (!speedtch_find_firmware(instance, 2, &fw2)) { - speedtch_upload_firmware(instance, fw1, fw2); - release_firmware(fw2); + /* Set up interrupt endpoint */ + if (instance->int_urb) { + ret = usb_submit_urb(instance->int_urb, GFP_KERNEL); + if (ret < 0) { + /* Doesn't matter; we'll poll anyway */ + atm_dbg(usbatm, "%s: submission of interrupt URB failed (%d)!\n", __func__, ret); + usb_free_urb(instance->int_urb); + instance->int_urb = NULL; } - release_firmware(fw1); } - /* In case we failed, set state back to NO_FIRMWARE so that - another later attempt may work. Otherwise, we never actually - manage to recover if, for example, the firmware is on /usr and - we look for it too early. */ - speedtch_got_firmware(instance, 0); + /* Start status polling */ + mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(1000)); - module_put(THIS_MODULE); - udsl_put_instance(&instance->u); return 0; } -#endif /* USE_FW_LOADER */ -static void speedtch_firmware_start(struct speedtch_instance_data *instance) +static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_dev) { -#ifdef USE_FW_LOADER - int ret; -#endif - - dbg("speedtch_firmware_start"); - - down(&instance->u.serialize); /* vs self, speedtch_got_firmware */ - - if (instance->u.status >= UDSL_LOADING_FIRMWARE) { - up(&instance->u.serialize); - return; - } + struct speedtch_instance_data *instance = usbatm->driver_data; + struct urb *int_urb = instance->int_urb; + + atm_dbg(usbatm, "%s entered\n", __func__); + + del_timer_sync(&instance->status_checker.timer); + + /* + * Since resubmit_timer and int_urb can schedule themselves and + * each other, shutting them down correctly takes some care + */ + instance->int_urb = NULL; /* signal shutdown */ + mb(); + usb_kill_urb(int_urb); + del_timer_sync(&instance->resubmit_timer); + /* + * At this point, speedtch_handle_int and speedtch_resubmit_int + * can run or be running, but instance->int_urb == NULL means that + * they will not reschedule + */ + usb_kill_urb(int_urb); + del_timer_sync(&instance->resubmit_timer); + usb_free_urb(int_urb); - instance->u.status = UDSL_LOADING_FIRMWARE; - up(&instance->u.serialize); + flush_scheduled_work(); +} -#ifdef USE_FW_LOADER - udsl_get_instance(&instance->u); - try_module_get(THIS_MODULE); - ret = kernel_thread(speedtch_load_firmware, instance, - CLONE_FS | CLONE_FILES); +/********** +** USB ** +**********/ - if (ret >= 0) - return; /* OK */ +static struct usb_device_id speedtch_usb_ids[] = { + {USB_DEVICE(0x06b9, 0x4061)}, + {} +}; - dbg("speedtch_firmware_start: kernel_thread failed (%d)!", ret); +MODULE_DEVICE_TABLE(usb, speedtch_usb_ids); - module_put(THIS_MODULE); - udsl_put_instance(&instance->u); - /* Just pretend it never happened... hope modem_run happens */ -#endif /* USE_FW_LOADER */ +static int speedtch_usb_probe(struct usb_interface *, const struct usb_device_id *); - speedtch_got_firmware(instance, 0); -} - -static int speedtch_firmware_wait(struct udsl_instance_data *instance) -{ - speedtch_firmware_start((void *)instance); +static struct usb_driver speedtch_usb_driver = { + .owner = THIS_MODULE, + .name = speedtch_driver_name, + .probe = speedtch_usb_probe, + .disconnect = usbatm_usb_disconnect, + .id_table = speedtch_usb_ids +}; - if (wait_event_interruptible(instance->firmware_waiters, instance->status != UDSL_LOADING_FIRMWARE) < 0) - return -ERESTARTSYS; +static void speedtch_release_interfaces(struct usb_device *usb_dev, int num_interfaces) { + struct usb_interface *cur_intf; + int i; - return (instance->status == UDSL_LOADED_FIRMWARE) ? 0 : -EAGAIN; + for(i = 0; i < num_interfaces; i++) + if ((cur_intf = usb_ifnum_to_if(usb_dev, i))) { + usb_set_intfdata(cur_intf, NULL); + usb_driver_release_interface(&speedtch_usb_driver, cur_intf); + } } -/********** -** USB ** -**********/ - -static int speedtch_usb_ioctl(struct usb_interface *intf, unsigned int code, - void *user_data) +static int speedtch_bind(struct usbatm_data *usbatm, + struct usb_interface *intf, + const struct usb_device_id *id, + int *need_heavy_init) { - struct speedtch_instance_data *instance = usb_get_intfdata(intf); + struct usb_device *usb_dev = interface_to_usbdev(intf); + struct usb_interface *cur_intf; + struct speedtch_instance_data *instance; + int ifnum = intf->altsetting->desc.bInterfaceNumber; + int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces; + int i, ret; - dbg("speedtch_usb_ioctl entered"); + usb_dbg(usbatm, "%s entered\n", __func__); - if (!instance) { - dbg("speedtch_usb_ioctl: NULL instance!"); + if (usb_dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) { + usb_dbg(usbatm, "%s: wrong device class %d\n", __func__, usb_dev->descriptor.bDeviceClass); return -ENODEV; } - switch (code) { - case UDSL_IOCTL_LINE_UP: - instance->u.atm_dev->signal = ATM_PHY_SIG_FOUND; - speedtch_got_firmware(instance, 1); - return (instance->u.status == UDSL_LOADED_FIRMWARE) ? 0 : -EIO; - case UDSL_IOCTL_LINE_DOWN: - instance->u.atm_dev->signal = ATM_PHY_SIG_LOST; - return 0; - default: - return -ENOTTY; - } -} + /* claim all interfaces */ -static int speedtch_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - int ifnum = intf->altsetting->desc.bInterfaceNumber; - struct speedtch_instance_data *instance; - unsigned char mac_str[13]; - int ret, i; - char buf7[SIZE_7]; + for (i=0; i < num_interfaces; i++) { + cur_intf = usb_ifnum_to_if(usb_dev, i); - dbg("speedtch_usb_probe: trying device with vendor=0x%x, product=0x%x, ifnum %d", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct), ifnum); + if ((i != ifnum) && cur_intf) { + ret = usb_driver_claim_interface(&speedtch_usb_driver, cur_intf, usbatm); - if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) || - (ifnum != 1)) - return -ENODEV; - - dbg("speedtch_usb_probe: device accepted"); + if (ret < 0) { + usb_dbg(usbatm, "%s: failed to claim interface %d (%d)\n", __func__, i, ret); + speedtch_release_interfaces(usb_dev, i); + return ret; + } + } + } - /* instance init */ instance = kmalloc(sizeof(*instance), GFP_KERNEL); + if (!instance) { - dbg("speedtch_usb_probe: no memory for instance data!"); - return -ENOMEM; + usb_dbg(usbatm, "%s: no memory for instance data!\n", __func__); + ret = -ENOMEM; + goto fail_release; } memset(instance, 0, sizeof(struct speedtch_instance_data)); - if ((ret = usb_set_interface(dev, 0, 0)) < 0) - goto fail; + instance->usbatm = usbatm; - if ((ret = usb_set_interface(dev, 2, 0)) < 0) - goto fail; + INIT_WORK(&instance->status_checker, (void *)speedtch_check_status, instance); - instance->u.data_endpoint = SPEEDTCH_ENDPOINT_DATA; - instance->u.firmware_wait = speedtch_firmware_wait; - instance->u.driver_name = speedtch_driver_name; + instance->status_checker.timer.function = speedtch_status_poll; + instance->status_checker.timer.data = (unsigned long)instance; + instance->poll_delay = MIN_POLL_DELAY; - ret = udsl_instance_setup(dev, &instance->u); - if (ret) - goto fail; + init_timer(&instance->resubmit_timer); + instance->resubmit_timer.function = speedtch_resubmit_int; + instance->resubmit_timer.data = (unsigned long)instance; - init_timer(&instance->poll_timer); - instance->poll_timer.function = speedtch_timer_poll; - instance->poll_timer.data = (unsigned long)instance; + instance->int_urb = usb_alloc_urb(0, GFP_KERNEL); - INIT_WORK(&instance->poll_work, (void *)speedtch_poll_status, instance); + if (instance->int_urb) + usb_fill_int_urb(instance->int_urb, usb_dev, + usb_rcvintpipe(usb_dev, ENDPOINT_INT), + instance->int_data, sizeof(instance->int_data), + speedtch_handle_int, instance, 50); + else + usb_dbg(usbatm, "%s: no memory for interrupt urb!\n", __func__); - /* set MAC address, it is stored in the serial number */ - memset(instance->u.atm_dev->esi, 0, sizeof(instance->u.atm_dev->esi)); - if (usb_string(dev, dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) { - for (i = 0; i < 6; i++) - instance->u.atm_dev->esi[i] = - (hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1])); - } + /* check whether the modem already seems to be alive */ + ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), + 0x12, 0xc0, 0x07, 0x00, + instance->scratch_buffer + OFFSET_7, SIZE_7, 500); - /* 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, 500); + *need_heavy_init = (ret != SIZE_7); - if (ret == SIZE_7) { - dbg("firmware appears to be already loaded"); - speedtch_got_firmware(instance, 1); - speedtch_poll_status(instance); - } else { - speedtch_firmware_start(instance); - } + usb_dbg(usbatm, "%s: firmware %s loaded\n", __func__, need_heavy_init ? "not" : "already"); + + if (*need_heavy_init) + if ((ret = usb_reset_device(usb_dev)) < 0) + goto fail_free; - usb_set_intfdata(intf, instance); + usbatm->driver_data = instance; return 0; - fail: +fail_free: + usb_free_urb(instance->int_urb); kfree(instance); - - return -ENOMEM; +fail_release: + speedtch_release_interfaces(usb_dev, num_interfaces); + return ret; } -static void speedtch_usb_disconnect(struct usb_interface *intf) +static void speedtch_unbind(struct usbatm_data *usbatm, struct usb_interface *intf) { - struct speedtch_instance_data *instance = usb_get_intfdata(intf); - - dbg("speedtch_usb_disconnect entered"); - - if (!instance) { - dbg("speedtch_usb_disconnect: NULL instance!"); - return; - } + struct usb_device *usb_dev = interface_to_usbdev(intf); + struct speedtch_instance_data *instance = usbatm->driver_data; -/*QQ need to handle disconnects on interface #2 while uploading firmware */ -/*QQ and what about interface #1? */ - - if (instance->int_urb) { - struct urb *int_urb = instance->int_urb; - instance->int_urb = NULL; - wmb(); - usb_unlink_urb(int_urb); - usb_free_urb(int_urb); - } + usb_dbg(usbatm, "%s entered\n", __func__); - instance->int_data[0] = 1; - del_timer_sync(&instance->poll_timer); - wmb(); - flush_scheduled_work(); - - udsl_instance_disconnect(&instance->u); - - /* clean up */ - usb_set_intfdata(intf, NULL); - udsl_put_instance(&instance->u); + speedtch_release_interfaces(usb_dev, usb_dev->actconfig->desc.bNumInterfaces); + usb_free_urb(instance->int_urb); + kfree(instance); } + /*********** ** init ** ***********/ +static struct usbatm_driver speedtch_usbatm_driver = { + .owner = THIS_MODULE, + .driver_name = speedtch_driver_name, + .bind = speedtch_bind, + .heavy_init = speedtch_heavy_init, + .unbind = speedtch_unbind, + .atm_start = speedtch_atm_start, + .atm_stop = speedtch_atm_stop, + .in = ENDPOINT_DATA, + .out = ENDPOINT_DATA +}; + +static int speedtch_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + return usbatm_usb_probe(intf, id, &speedtch_usbatm_driver); +} + static int __init speedtch_usb_init(void) { - dbg("speedtch_usb_init: driver version " DRIVER_VERSION); + dbg("%s: driver version %s", __func__, DRIVER_VERSION); return usb_register(&speedtch_usb_driver); } static void __exit speedtch_usb_cleanup(void) { - dbg("speedtch_usb_cleanup entered"); + dbg("%s", __func__); usb_deregister(&speedtch_usb_driver); } -- cgit v1.2.3 From 1b0e614652344a2d39eb336f3dc07651782883bf Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Wed, 11 May 2005 20:19:29 +0200 Subject: [PATCH] USB ATM: driver for the Conexant AccessRunner chipset cxacru Driver for modems based on the Conexant AccessRunner chipset. Original patch by Josep Comas, much reworked by Roman Kagan. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 878 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 878 insertions(+) create mode 100644 drivers/usb/atm/cxacru.c (limited to 'drivers/usb') diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c new file mode 100644 index 000000000000..cbd4a7d25d0b --- /dev/null +++ b/drivers/usb/atm/cxacru.c @@ -0,0 +1,878 @@ +/****************************************************************************** + * cxacru.c - driver for USB ADSL modems based on + * Conexant AccessRunner chipset + * + * Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan + * Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ******************************************************************************/ + +/* + * Credit is due for Josep Comas, who created the original patch to speedtch.c + * to support the different padding used by the AccessRunner (now generalized + * into usbatm), and the userspace firmware loading utility. + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* FIXME: linux/firmware.h should include it itself */ +#include + +#include "usbatm.h" + +#define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands" +#define DRIVER_VERSION "0.2" +#define DRIVER_DESC "Conexant AccessRunner ADSL USB modem driver" + +static const char cxacru_driver_name[] = "cxacru"; + +#define CXACRU_EP_CMD 0x01 /* Bulk/interrupt in/out */ +#define CXACRU_EP_DATA 0x02 /* Bulk in/out */ + +#define CMD_PACKET_SIZE 64 /* Should be maxpacket(ep)? */ + +/* Addresses */ +#define PLLFCLK_ADDR 0x00350068 +#define PLLBCLK_ADDR 0x0035006c +#define SDRAMEN_ADDR 0x00350010 +#define FW_ADDR 0x00801000 +#define BR_ADDR 0x00180600 +#define SIG_ADDR 0x00180500 +#define BR_STACK_ADDR 0x00187f10 + +/* Values */ +#define SDRAM_ENA 0x1 + +#define CMD_TIMEOUT 2000 /* msecs */ +#define POLL_INTERVAL 5000 /* msecs */ + +/* commands for interaction with the modem through the control channel before + * firmware is loaded */ +enum cxacru_fw_request { + FW_CMD_ERR, + FW_GET_VER, + FW_READ_MEM, + FW_WRITE_MEM, + FW_RMW_MEM, + FW_CHECKSUM_MEM, + FW_GOTO_MEM, +}; + +/* commands for interaction with the modem through the control channel once + * firmware is loaded */ +enum cxacru_cm_request { + CM_REQUEST_UNDEFINED = 0x80, + CM_REQUEST_TEST, + CM_REQUEST_CHIP_GET_MAC_ADDRESS, + CM_REQUEST_CHIP_GET_DP_VERSIONS, + CM_REQUEST_CHIP_ADSL_LINE_START, + CM_REQUEST_CHIP_ADSL_LINE_STOP, + CM_REQUEST_CHIP_ADSL_LINE_GET_STATUS, + CM_REQUEST_CHIP_ADSL_LINE_GET_SPEED, + CM_REQUEST_CARD_INFO_GET, + CM_REQUEST_CARD_DATA_GET, + CM_REQUEST_CARD_DATA_SET, + CM_REQUEST_COMMAND_HW_IO, + CM_REQUEST_INTERFACE_HW_IO, + CM_REQUEST_CARD_SERIAL_DATA_PATH_GET, + CM_REQUEST_CARD_SERIAL_DATA_PATH_SET, + CM_REQUEST_CARD_CONTROLLER_VERSION_GET, + CM_REQUEST_CARD_GET_STATUS, + CM_REQUEST_CARD_GET_MAC_ADDRESS, + CM_REQUEST_CARD_GET_DATA_LINK_STATUS, + CM_REQUEST_MAX, +}; + +/* reply codes to the commands above */ +enum cxacru_cm_status { + CM_STATUS_UNDEFINED, + CM_STATUS_SUCCESS, + CM_STATUS_ERROR, + CM_STATUS_UNSUPPORTED, + CM_STATUS_UNIMPLEMENTED, + CM_STATUS_PARAMETER_ERROR, + CM_STATUS_DBG_LOOPBACK, + CM_STATUS_MAX, +}; + +/* indices into CARD_INFO_GET return array */ +enum cxacru_info_idx { + CXINF_DOWNSTREAM_RATE, + CXINF_UPSTREAM_RATE, + CXINF_LINK_STATUS, + CXINF_LINE_STATUS, + CXINF_MAC_ADDRESS_HIGH, + CXINF_MAC_ADDRESS_LOW, + CXINF_UPSTREAM_SNR_MARGIN, + CXINF_DOWNSTREAM_SNR_MARGIN, + CXINF_UPSTREAM_ATTENUATION, + CXINF_DOWNSTREAM_ATTENUATION, + CXINF_TRANSMITTER_POWER, + CXINF_UPSTREAM_BITS_PER_FRAME, + CXINF_DOWNSTREAM_BITS_PER_FRAME, + CXINF_STARTUP_ATTEMPTS, + CXINF_UPSTREAM_CRC_ERRORS, + CXINF_DOWNSTREAM_CRC_ERRORS, + CXINF_UPSTREAM_FEC_ERRORS, + CXINF_DOWNSTREAM_FEC_ERRORS, + CXINF_UPSTREAM_HEC_ERRORS, + CXINF_DOWNSTREAM_HEC_ERRORS, + CXINF_LINE_STARTABLE, + CXINF_MODULATION, + CXINF_ADSL_HEADEND, + CXINF_ADSL_HEADEND_ENVIRONMENT, + CXINF_CONTROLLER_VERSION, + /* dunno what the missing two mean */ + CXINF_MAX = 0x1c, +}; + +struct cxacru_modem_type { + u32 pll_f_clk; + u32 pll_b_clk; + int boot_rom_patch; +}; + +struct cxacru_data { + struct usbatm_data *usbatm; + + const struct cxacru_modem_type *modem_type; + + int line_status; + struct work_struct poll_work; + + /* contol handles */ + struct semaphore cm_serialize; + u8 *rcv_buf; + u8 *snd_buf; + struct urb *rcv_urb; + struct urb *snd_urb; + struct completion rcv_done; + struct completion snd_done; +}; + +/* the following three functions are stolen from drivers/usb/core/message.c */ +static void cxacru_blocking_completion(struct urb *urb, struct pt_regs *regs) +{ + complete((struct completion *)urb->context); +} + +static void cxacru_timeout_kill(unsigned long data) +{ + usb_unlink_urb((struct urb *) data); +} + +static int cxacru_start_wait_urb(struct urb *urb, struct completion *done, + int* actual_length) +{ + struct timer_list timer; + int status; + + init_timer(&timer); + timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT); + timer.data = (unsigned long) urb; + timer.function = cxacru_timeout_kill; + add_timer(&timer); + wait_for_completion(done); + status = urb->status; + if (status == -ECONNRESET) + status = -ETIMEDOUT; + del_timer_sync(&timer); + + if (actual_length) + *actual_length = urb->actual_length; + return status; +} + +static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, + u8 *wdata, int wsize, u8 *rdata, int rsize) +{ + int ret, actlen; + int offb, offd; + const int stride = CMD_PACKET_SIZE - 4; + u8 *wbuf = instance->snd_buf; + u8 *rbuf = instance->rcv_buf; + int wbuflen = ((wsize - 1) / stride + 1) * CMD_PACKET_SIZE; + int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE; + + if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) { + dbg("too big transfer requested"); + ret = -ENOMEM; + goto fail; + } + + down(&instance->cm_serialize); + + /* submit reading urb before the writing one */ + init_completion(&instance->rcv_done); + ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL); + if (ret < 0) { + dbg("submitting read urb for cm %#x failed", cm); + ret = ret; + goto fail; + } + + memset(wbuf, 0, wbuflen); + /* handle wsize == 0 */ + wbuf[0] = cm; + for (offb = offd = 0; offd < wsize; offd += stride, offb += CMD_PACKET_SIZE) { + wbuf[offb] = cm; + memcpy(wbuf + offb + 4, wdata + offd, min_t(int, stride, wsize - offd)); + } + + instance->snd_urb->transfer_buffer_length = wbuflen; + init_completion(&instance->snd_done); + ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL); + if (ret < 0) { + dbg("submitting write urb for cm %#x failed", cm); + ret = ret; + goto fail; + } + + ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL); + if (ret < 0) { + dbg("sending cm %#x failed", cm); + ret = ret; + goto fail; + } + + ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen); + if (ret < 0) { + dbg("receiving cm %#x failed", cm); + ret = ret; + goto fail; + } + if (actlen % CMD_PACKET_SIZE || !actlen) { + dbg("response is not a positive multiple of %d: %#x", + CMD_PACKET_SIZE, actlen); + ret = -EIO; + goto fail; + } + + /* check the return status and copy the data to the output buffer, if needed */ + for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) { + if (rbuf[offb] != cm) { + dbg("wrong cm %#x in response", rbuf[offb]); + ret = -EIO; + goto fail; + } + if (rbuf[offb + 1] != CM_STATUS_SUCCESS) { + dbg("response failed: %#x", rbuf[offb + 1]); + ret = -EIO; + goto fail; + } + if (offd >= rsize) + break; + memcpy(rdata + offd, rbuf + offb + 4, min_t(int, stride, rsize - offd)); + offd += stride; + } + + ret = offd; + dbg("cm %#x", cm); +fail: + up(&instance->cm_serialize); + return ret; +} + +static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_request cm, + u32 *data, int size) +{ + int ret, len; + u32 *buf; + int offb, offd; + const int stride = CMD_PACKET_SIZE / (4 * 2) - 1; + int buflen = ((size - 1) / stride + 1 + size * 2) * 4; + + buf = kmalloc(buflen, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = cxacru_cm(instance, cm, NULL, 0, (u8 *) buf, buflen); + if (ret < 0) + goto cleanup; + + /* len > 0 && len % 4 == 0 guaranteed by cxacru_cm() */ + len = ret / 4; + for (offb = 0; offb < len; ) { + int l = le32_to_cpu(buf[offb++]); + if (l > stride || l > (len - offb) / 2) { + dbg("wrong data length %#x in response", l); + ret = -EIO; + goto cleanup; + } + while (l--) { + offd = le32_to_cpu(buf[offb++]); + if (offd >= size) { + dbg("wrong index %#x in response", offd); + ret = -EIO; + goto cleanup; + } + data[offd] = le32_to_cpu(buf[offb++]); + } + } + + ret = 0; + +cleanup: + kfree(buf); + return ret; +} + +static int cxacru_card_status(struct cxacru_data *instance) +{ + int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); + if (ret < 0) { /* firmware not loaded */ + dbg("cxacru_adsl_start: CARD_GET_STATUS returned %d", ret); + return ret; + } + return 0; +} + +static void cxacru_poll_status(struct cxacru_data *instance); + +static int cxacru_atm_start(struct usbatm_data *usbatm_instance, + struct atm_dev *atm_dev) +{ + struct cxacru_data *instance = usbatm_instance->driver_data; + struct device *dev = &usbatm_instance->usb_intf->dev; + /* + struct atm_dev *atm_dev = usbatm_instance->atm_dev; + */ + int ret; + + dbg("cxacru_atm_start"); + + /* Read MAC address */ + ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0, + atm_dev->esi, sizeof(atm_dev->esi)); + if (ret < 0) { + dev_err(dev, "cxacru_atm_start: CARD_GET_MAC_ADDRESS returned %d\n", ret); + return ret; + } + + /* start ADSL */ + ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(dev, "cxacru_atm_start: CHIP_ADSL_LINE_START returned %d\n", ret); + return ret; + } + + /* Start status polling */ + cxacru_poll_status(instance); + return 0; +} + +static void cxacru_poll_status(struct cxacru_data *instance) +{ + u32 buf[CXINF_MAX] = {}; + struct device *dev = &instance->usbatm->usb_intf->dev; + struct atm_dev *atm_dev = instance->usbatm->atm_dev; + int ret; + + ret = cxacru_cm_get_array(instance, CM_REQUEST_CARD_INFO_GET, buf, CXINF_MAX); + if (ret < 0) { + dev_warn(dev, "poll status: error %d\n", ret); + goto reschedule; + } + + if (instance->line_status == buf[CXINF_LINE_STATUS]) + goto reschedule; + + instance->line_status = buf[CXINF_LINE_STATUS]; + switch (instance->line_status) { + case 0: + atm_dev->signal = ATM_PHY_SIG_LOST; + dev_info(dev, "ADSL line: down\n"); + break; + + case 1: + atm_dev->signal = ATM_PHY_SIG_LOST; + dev_info(dev, "ADSL line: attemtping to activate\n"); + break; + + case 2: + atm_dev->signal = ATM_PHY_SIG_LOST; + dev_info(dev, "ADSL line: training\n"); + break; + + case 3: + atm_dev->signal = ATM_PHY_SIG_LOST; + dev_info(dev, "ADSL line: channel analysis\n"); + break; + + case 4: + atm_dev->signal = ATM_PHY_SIG_LOST; + dev_info(dev, "ADSL line: exchange\n"); + break; + + case 5: + atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424; + atm_dev->signal = ATM_PHY_SIG_FOUND; + + dev_info(dev, "ADSL line: up (%d Kib/s down | %d Kib/s up)\n", + buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]); + break; + + case 6: + atm_dev->signal = ATM_PHY_SIG_LOST; + dev_info(dev, "ADSL line: waiting\n"); + break; + + case 7: + atm_dev->signal = ATM_PHY_SIG_LOST; + dev_info(dev, "ADSL line: initializing\n"); + break; + + default: + atm_dev->signal = ATM_PHY_SIG_UNKNOWN; + dev_info(dev, "Unknown line state %02x\n", instance->line_status); + break; + } +reschedule: + schedule_delayed_work(&instance->poll_work, msecs_to_jiffies(POLL_INTERVAL)); +} + +static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw, + u8 code1, u8 code2, u32 addr, u8 *data, int size) +{ + int ret; + u8 *buf; + int offd, offb; + const int stride = CMD_PACKET_SIZE - 8; + + buf = (u8 *) __get_free_page(GFP_KERNEL); + if (!buf) + return -ENOMEM; + + offb = offd = 0; + do { + int l = min_t(int, stride, size - offd); + buf[offb++] = fw; + buf[offb++] = l; + buf[offb++] = code1; + buf[offb++] = code2; + *((u32 *) (buf + offb)) = cpu_to_le32(addr); + offb += 4; + addr += l; + if(l) + memcpy(buf + offb, data + offd, l); + if (l < stride) + memset(buf + offb + l, 0, stride - l); + offb += stride; + offd += stride; + if ((offb >= PAGE_SIZE) || (offd >= size)) { + ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD), + buf, offb, NULL, CMD_TIMEOUT); + if (ret < 0) { + dbg("sending fw %#x failed", fw); + goto cleanup; + } + offb = 0; + } + } while(offd < size); + dbg("sent fw %#x", fw); + + ret = 0; + +cleanup: + free_page((unsigned long) buf); + return ret; +} + +static void cxacru_upload_firmware(struct cxacru_data *instance, + const struct firmware *fw, + const struct firmware *bp, + const struct firmware *cf) +{ + int ret; + int off; + struct usb_device *usb_dev = instance->usbatm->usb_dev; + struct device *dev = &instance->usbatm->usb_intf->dev; + u16 signature[] = { usb_dev->descriptor.idVendor, usb_dev->descriptor.idProduct }; + u32 val; + + dbg("cxacru_upload_firmware"); + + /* FirmwarePllFClkValue */ + val = cpu_to_le32(instance->modem_type->pll_f_clk); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLFCLK_ADDR, (u8 *) &val, 4); + if (ret) { + dev_err(dev, "FirmwarePllFClkValue failed: %d\n", ret); + return; + } + + /* FirmwarePllBClkValue */ + val = cpu_to_le32(instance->modem_type->pll_b_clk); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLBCLK_ADDR, (u8 *) &val, 4); + if (ret) { + dev_err(dev, "FirmwarePllBClkValue failed: %d\n", ret); + return; + } + + /* Enable SDRAM */ + val = cpu_to_le32(SDRAM_ENA); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SDRAMEN_ADDR, (u8 *) &val, 4); + if (ret) { + dev_err(dev, "Enable SDRAM failed: %d\n", ret); + return; + } + + /* Firmware */ + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size); + if (ret) { + dev_err(dev, "Firmware upload failed: %d\n", ret); + return; + } + + /* Boot ROM patch */ + if (instance->modem_type->boot_rom_patch) { + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size); + if (ret) { + dev_err(dev, "Boot ROM patching failed: %d\n", ret); + return; + } + } + + /* Signature */ + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SIG_ADDR, (u8 *) signature, 4); + if (ret) { + dev_err(dev, "Signature storing failed: %d\n", ret); + return; + } + + if (instance->modem_type->boot_rom_patch) { + val = cpu_to_le32(BR_ADDR); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4); + } + else { + ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0); + } + if (ret) { + dev_err(dev, "Passing control to firmware failed: %d\n", ret); + return; + } + + /* Delay to allow firmware to start up. */ + msleep_interruptible(1000); + + usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD)); + usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_CMD)); + usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_DATA)); + usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_DATA)); + + ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(dev, "modem failed to initialize: %d\n", ret); + return; + } + + /* Load config data (le32), doing one packet at a time */ + if (cf) + for (off = 0; off < cf->size / 4; ) { + u32 buf[CMD_PACKET_SIZE / 4 - 1]; + int i, len = min_t(int, cf->size / 4 - off, CMD_PACKET_SIZE / 4 / 2 - 1); + buf[0] = cpu_to_le32(len); + for (i = 0; i < len; i++, off++) { + buf[i * 2 + 1] = cpu_to_le32(off); + memcpy(buf + i * 2 + 2, cf->data + off * 4, 4); + } + ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET, + (u8 *) buf, len, NULL, 0); + if (ret < 0) { + dev_err(dev, "load config data failed: %d\n", ret); + return; + } + } + + msleep_interruptible(4000); +} + +static int cxacru_find_firmware(struct cxacru_data *instance, + char* phase, const struct firmware **fw_p) +{ + struct device *dev = &instance->usbatm->usb_intf->dev; + char buf[16]; + + sprintf(buf, "cxacru-%s.bin", phase); + dbg("cxacru_find_firmware: looking for %s", buf); + + if (request_firmware(fw_p, buf, dev)) { + dev_dbg(dev, "no stage %s firmware found\n", phase); + return -ENOENT; + } + + dev_info(dev, "found firmware %s\n", buf); + + return 0; +} + +static int cxacru_heavy_init(struct usbatm_data *usbatm_instance, + struct usb_interface *usb_intf) +{ + struct device *dev = &usbatm_instance->usb_intf->dev; + const struct firmware *fw, *bp, *cf; + struct cxacru_data *instance = usbatm_instance->driver_data; + + int ret = cxacru_find_firmware(instance, "fw", &fw); + if (ret) { + dev_warn(dev, "firmware (cxacru-fw.bin) unavailable (hotplug misconfiguration?)\n"); + return ret; + } + + if (instance->modem_type->boot_rom_patch) { + ret = cxacru_find_firmware(instance, "bp", &bp); + if (ret) { + dev_warn(dev, "boot ROM patch (cxacru-bp.bin) unavailable (hotplug misconfiguration?)\n"); + release_firmware(fw); + return ret; + } + } + + if (cxacru_find_firmware(instance, "cf", &cf)) /* optional */ + cf = NULL; + + cxacru_upload_firmware(instance, fw, bp, cf); + + if (cf) + release_firmware(cf); + if (instance->modem_type->boot_rom_patch) + release_firmware(bp); + release_firmware(fw); + + ret = cxacru_card_status(instance); + if (ret) + dbg("modem initialisation failed"); + else + dbg("done setting up the modem"); + + return ret; +} + +static int cxacru_bind(struct usbatm_data *usbatm_instance, + struct usb_interface *intf, const struct usb_device_id *id, + int *need_heavy_init) +{ + struct cxacru_data *instance; + struct usb_device *usb_dev = interface_to_usbdev(intf); + int ret; + + /* instance init */ + instance = kmalloc(sizeof(*instance), GFP_KERNEL); + if (!instance) { + dbg("cxacru_bind: no memory for instance data"); + return -ENOMEM; + } + + memset(instance, 0, sizeof(*instance)); + + instance->usbatm = usbatm_instance; + instance->modem_type = (struct cxacru_modem_type *) id->driver_info; + + instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL); + if (!instance->rcv_buf) { + dbg("cxacru_bind: no memory for rcv_buf"); + ret = -ENOMEM; + goto fail; + } + instance->snd_buf = (u8 *) __get_free_page(GFP_KERNEL); + if (!instance->snd_buf) { + dbg("cxacru_bind: no memory for snd_buf"); + ret = -ENOMEM; + goto fail; + } + instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!instance->rcv_urb) { + dbg("cxacru_bind: no memory for rcv_urb"); + ret = -ENOMEM; + goto fail; + } + instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!instance->snd_urb) { + dbg("cxacru_bind: no memory for snd_urb"); + ret = -ENOMEM; + goto fail; + } + + usb_fill_int_urb(instance->rcv_urb, + usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD), + instance->rcv_buf, PAGE_SIZE, + cxacru_blocking_completion, &instance->rcv_done, 1); + instance->rcv_urb->transfer_flags |= URB_ASYNC_UNLINK; + + usb_fill_int_urb(instance->snd_urb, + usb_dev, usb_sndintpipe(usb_dev, CXACRU_EP_CMD), + instance->snd_buf, PAGE_SIZE, + cxacru_blocking_completion, &instance->snd_done, 4); + instance->snd_urb->transfer_flags |= URB_ASYNC_UNLINK; + + init_MUTEX(&instance->cm_serialize); + + INIT_WORK(&instance->poll_work, (void *)cxacru_poll_status, instance); + + usbatm_instance->driver_data = instance; + + *need_heavy_init = cxacru_card_status(instance); + + return 0; + + fail: + free_page((unsigned long) instance->snd_buf); + free_page((unsigned long) instance->rcv_buf); + usb_free_urb(instance->snd_urb); + usb_free_urb(instance->rcv_urb); + kfree(instance); + + return ret; +} + +static void cxacru_unbind(struct usbatm_data *usbatm_instance, + struct usb_interface *intf) +{ + struct cxacru_data *instance = usbatm_instance->driver_data; + + dbg("cxacru_unbind entered"); + + if (!instance) { + dbg("cxacru_unbind: NULL instance!"); + return; + } + + while (!cancel_delayed_work(&instance->poll_work)) + flush_scheduled_work(); + + usb_kill_urb(instance->snd_urb); + usb_kill_urb(instance->rcv_urb); + usb_free_urb(instance->snd_urb); + usb_free_urb(instance->rcv_urb); + + free_page((unsigned long) instance->snd_buf); + free_page((unsigned long) instance->rcv_buf); + kfree(instance); + + usbatm_instance->driver_data = NULL; +} + +static const struct cxacru_modem_type cxacru_cafe = { + .pll_f_clk = 0x02d874df, + .pll_b_clk = 0x0196a51a, + .boot_rom_patch = 1, +}; + +static const struct cxacru_modem_type cxacru_cb00 = { + .pll_f_clk = 0x5, + .pll_b_clk = 0x3, + .boot_rom_patch = 0, +}; + +static const struct usb_device_id cxacru_usb_ids[] = { + { /* V = Conexant P = ADSL modem (Euphrates project) */ + USB_DEVICE(0x0572, 0xcafe), .driver_info = (unsigned long) &cxacru_cafe + }, + { /* V = Conexant P = ADSL modem (Hasbani project) */ + USB_DEVICE(0x0572, 0xcb00), .driver_info = (unsigned long) &cxacru_cb00 + }, + { /* V = Conexant P = ADSL modem */ + USB_DEVICE(0x0572, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00 + }, + { /* V = Conexant P = ADSL modem */ + USB_DEVICE(0x0572, 0xcb06), .driver_info = (unsigned long) &cxacru_cb00 + }, + { /* V = Olitec P = ADSL modem version 2 */ + USB_DEVICE(0x08e3, 0x0100), .driver_info = (unsigned long) &cxacru_cafe + }, + { /* V = Olitec P = ADSL modem version 3 */ + USB_DEVICE(0x08e3, 0x0102), .driver_info = (unsigned long) &cxacru_cb00 + }, + { /* V = Trust/Amigo Technology Co. P = AMX-CA86U */ + USB_DEVICE(0x0eb0, 0x3457), .driver_info = (unsigned long) &cxacru_cafe + }, + { /* V = Zoom P = 5510 */ + USB_DEVICE(0x1803, 0x5510), .driver_info = (unsigned long) &cxacru_cb00 + }, + { /* V = Draytek P = Vigor 318 */ + USB_DEVICE(0x0675, 0x0200), .driver_info = (unsigned long) &cxacru_cb00 + }, + { /* V = Zyxel P = 630-C1 aka OMNI ADSL USB (Annex A) */ + USB_DEVICE(0x0586, 0x330a), .driver_info = (unsigned long) &cxacru_cb00 + }, + { /* V = Zyxel P = 630-C3 aka OMNI ADSL USB (Annex B) */ + USB_DEVICE(0x0586, 0x330b), .driver_info = (unsigned long) &cxacru_cb00 + }, + { /* V = Aethra P = Starmodem UM1020 */ + USB_DEVICE(0x0659, 0x0020), .driver_info = (unsigned long) &cxacru_cb00 + }, + { /* V = Aztech Systems P = ? AKA Pirelli AUA-010 */ + USB_DEVICE(0x0509, 0x0812), .driver_info = (unsigned long) &cxacru_cb00 + }, + { /* V = Netopia P = Cayman 3341(Annex A)/3351(Annex B) */ + USB_DEVICE(0x100d, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00 + }, + { /* V = Netopia P = Cayman 3342(Annex A)/3352(Annex B) */ + USB_DEVICE(0x100d, 0x3342), .driver_info = (unsigned long) &cxacru_cb00 + }, + {} +}; + +MODULE_DEVICE_TABLE(usb, cxacru_usb_ids); + +static struct usbatm_driver cxacru_driver = { + .owner = THIS_MODULE, + .driver_name = cxacru_driver_name, + .bind = cxacru_bind, + .heavy_init = cxacru_heavy_init, + .unbind = cxacru_unbind, + .atm_start = cxacru_atm_start, + .in = CXACRU_EP_DATA, + .out = CXACRU_EP_DATA, + .rx_padding = 3, + .tx_padding = 11, +}; + +static int cxacru_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + return usbatm_usb_probe(intf, id, &cxacru_driver); +} + +static struct usb_driver cxacru_usb_driver = { + .owner = THIS_MODULE, + .name = cxacru_driver_name, + .probe = cxacru_usb_probe, + .disconnect = usbatm_usb_disconnect, + .id_table = cxacru_usb_ids +}; + +static int __init cxacru_init(void) +{ + return usb_register(&cxacru_usb_driver); +} + +static void __exit cxacru_cleanup(void) +{ + usb_deregister(&cxacru_usb_driver); +} + +module_init(cxacru_init); +module_exit(cxacru_cleanup); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); -- cgit v1.2.3 From 0bb3cf37df1b59a1fed079e7f8f140ef9ec73130 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Wed, 11 May 2005 20:17:09 +0200 Subject: [PATCH] USB ATM: generic DSL modem driver xusbatm Doesn't do any firmware loading etc, just transmission and reception. The user needs to take care of modem initialization, and load the module with parameters giving the endpoints to use and so forth. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/xusbatm.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 drivers/usb/atm/xusbatm.c (limited to 'drivers/usb') diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c new file mode 100644 index 000000000000..7fe7fb484d10 --- /dev/null +++ b/drivers/usb/atm/xusbatm.c @@ -0,0 +1,196 @@ +/****************************************************************************** + * xusbatm.c - dumb usbatm-based driver for modems initialized in userspace + * + * Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ******************************************************************************/ + +#include +#include /* FIXME: required by linux/etherdevice.h */ +#include /* for random_ether_addr() */ + +#include "usbatm.h" + + +#define XUSBATM_DRIVERS_MAX 8 + +#define XUSBATM_PARM(name, type, parmtype, desc) \ + static type name[XUSBATM_DRIVERS_MAX]; \ + static int num_##name; \ + module_param_array(name, parmtype, &num_##name, 0444); \ + MODULE_PARM_DESC(name, desc) + +XUSBATM_PARM(vendor, unsigned short, ushort, "USB device vendor"); +XUSBATM_PARM(product, unsigned short, ushort, "USB device product"); + +XUSBATM_PARM(rx_endpoint, unsigned char, byte, "rx endpoint number"); +XUSBATM_PARM(tx_endpoint, unsigned char, byte, "tx endpoint number"); +XUSBATM_PARM(rx_padding, unsigned char, byte, "rx padding (default 0)"); +XUSBATM_PARM(tx_padding, unsigned char, byte, "tx padding (default 0)"); + +static const char xusbatm_driver_name[] = "xusbatm"; + +static struct usbatm_driver xusbatm_drivers[XUSBATM_DRIVERS_MAX]; +static struct usb_device_id xusbatm_usb_ids[XUSBATM_DRIVERS_MAX + 1]; +static struct usb_driver xusbatm_usb_driver; + +static int usb_intf_has_ep(const struct usb_interface *intf, u8 ep) +{ + int i, j; + + for (i = 0; i < intf->num_altsetting; i++) { + struct usb_host_interface *alt = intf->altsetting; + for (j = 0; j < alt->desc.bNumEndpoints; j++) + if ((alt->endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) == ep) + return 1; + } + return 0; +} + +static int xusbatm_bind(struct usbatm_data *usbatm_instance, + struct usb_interface *intf, const struct usb_device_id *id, + int *need_heavy_init) +{ + struct usb_device *usb_dev = interface_to_usbdev(intf); + int drv_ix = id - xusbatm_usb_ids; + int rx_ep_present = usb_intf_has_ep(intf, rx_endpoint[drv_ix]); + int tx_ep_present = usb_intf_has_ep(intf, tx_endpoint[drv_ix]); + u8 searched_ep = rx_ep_present ? tx_endpoint[drv_ix] : rx_endpoint[drv_ix]; + int i, ret; + + usb_dbg(usbatm_instance, "%s: binding driver %d: vendor %#x product %#x" + " rx: ep %#x padd %d tx: ep %#x padd %d\n", + __func__, drv_ix, vendor[drv_ix], product[drv_ix], + rx_endpoint[drv_ix], rx_padding[drv_ix], + tx_endpoint[drv_ix], tx_padding[drv_ix]); + + if (!rx_ep_present && !tx_ep_present) { + usb_dbg(usbatm_instance, "%s: intf #%d has neither rx (%#x) nor tx (%#x) endpoint\n", + __func__, intf->altsetting->desc.bInterfaceNumber, + rx_endpoint[drv_ix], tx_endpoint[drv_ix]); + return -ENODEV; + } + + if (rx_ep_present && tx_ep_present) + return 0; + + for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *cur_if = usb_dev->actconfig->interface[i]; + + if (cur_if != intf && usb_intf_has_ep(cur_if, searched_ep)) { + ret = usb_driver_claim_interface(&xusbatm_usb_driver, + cur_if, usbatm_instance); + if (!ret) + usb_err(usbatm_instance, "%s: failed to claim interface #%d (%d)\n", + __func__, cur_if->altsetting->desc.bInterfaceNumber, ret); + return ret; + } + } + + usb_err(usbatm_instance, "%s: no interface has endpoint %#x\n", + __func__, searched_ep); + return -ENODEV; +} + +static void xusbatm_unbind(struct usbatm_data *usbatm_instance, + struct usb_interface *intf) +{ + struct usb_device *usb_dev = interface_to_usbdev(intf); + int i; + usb_dbg(usbatm_instance, "%s entered\n", __func__); + + for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *cur_if = usb_dev->actconfig->interface[i]; + usb_set_intfdata(cur_if, NULL); + usb_driver_release_interface(&xusbatm_usb_driver, cur_if); + } +} + +static int xusbatm_atm_start(struct usbatm_data *usbatm_instance, + struct atm_dev *atm_dev) +{ + atm_dbg(usbatm_instance, "%s entered\n", __func__); + + /* use random MAC as we've no way to get it from the device */ + random_ether_addr(atm_dev->esi); + + return 0; +} + + +static int xusbatm_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return usbatm_usb_probe(intf, id, + xusbatm_drivers + (id - xusbatm_usb_ids)); +} + +static struct usb_driver xusbatm_usb_driver = { + .owner = THIS_MODULE, + .name = xusbatm_driver_name, + .probe = xusbatm_usb_probe, + .disconnect = usbatm_usb_disconnect, + .id_table = xusbatm_usb_ids +}; + +static int __init xusbatm_init(void) +{ + int i; + + dbg("xusbatm_init"); + + if (!num_vendor || + num_vendor != num_product || + num_vendor != num_rx_endpoint || + num_vendor != num_tx_endpoint) { + warn("malformed module parameters"); + return -EINVAL; + } + + for (i = 0; i < num_vendor; i++) { + xusbatm_usb_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE; + xusbatm_usb_ids[i].idVendor = vendor[i]; + xusbatm_usb_ids[i].idProduct = product[i]; + + + xusbatm_drivers[i].owner = THIS_MODULE; + xusbatm_drivers[i].driver_name = xusbatm_driver_name; + xusbatm_drivers[i].bind = xusbatm_bind; + xusbatm_drivers[i].unbind = xusbatm_unbind; + xusbatm_drivers[i].atm_start = xusbatm_atm_start; + xusbatm_drivers[i].in = rx_endpoint[i]; + xusbatm_drivers[i].out = tx_endpoint[i]; + xusbatm_drivers[i].rx_padding = rx_padding[i]; + xusbatm_drivers[i].tx_padding = tx_padding[i]; + } + + return usb_register(&xusbatm_usb_driver); +} +module_init(xusbatm_init); + +static void __exit xusbatm_exit(void) +{ + dbg("xusbatm_exit entered"); + + usb_deregister(&xusbatm_usb_driver); +} +module_exit(xusbatm_exit); + +MODULE_AUTHOR("Roman Kagan, Duncan Sands"); +MODULE_DESCRIPTION("Driver for USB ADSL modems initialized in userspace"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); -- cgit v1.2.3 From 86699e35923366ccb5c3451d24e94deb9dd0af29 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Wed, 11 May 2005 20:15:37 +0200 Subject: [PATCH] USB ATM: bits and bobs Makefile and Kconfig entries for the new drivers. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/Kconfig | 50 ++++++++++++++++++++++++++++++++++++++---------- drivers/usb/atm/Makefile | 7 ++++--- 2 files changed, 44 insertions(+), 13 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig index 0d9f5379b8cf..f429862e0974 100644 --- a/drivers/usb/atm/Kconfig +++ b/drivers/usb/atm/Kconfig @@ -1,30 +1,60 @@ # -# USB ATM driver configuration +# USB/ATM DSL configuration # -comment "USB ATM/DSL drivers" + +menu "USB DSL modem support" depends on USB config USB_ATM - tristate "Generic USB ATM/DSL core I/O support" + tristate "USB DSL modem support" depends on USB && ATM select CRC32 default n help - This provides a library which is used for packet I/O by USB DSL - modems, such as the SpeedTouch driver below. + Say Y here if you want to connect a USB Digital Subscriber Line (DSL) + modem to your computer's USB port. You will then need to choose your + modem from the list below. To compile this driver as a module, choose M here: the - module will be called usb_atm. + module will be called usbatm. config USB_SPEEDTOUCH - tristate "Alcatel Speedtouch USB support" - depends on USB && ATM - select USB_ATM + tristate "Speedtouch USB support" + depends on USB_ATM + select FW_LOADER help - Say Y here if you have an Alcatel SpeedTouch USB or SpeedTouch 330 + Say Y here if you have an SpeedTouch USB or SpeedTouch 330 modem. In order to use your modem you will need to install the two parts of the firmware, extracted by the user space tools; see for details. To compile this driver as a module, choose M here: the module will be called speedtch. + +config USB_CXACRU + tristate "Conexant AccessRunner USB support" + depends on USB_ATM + select FW_LOADER + help + Say Y here if you have an ADSL USB modem based on the Conexant + AccessRunner chipset. In order to use your modem you will need to + install the firmware, extracted by the user space tools; see + for details. + + To compile this driver as a module, choose M here: the + module will be called cxacru. + +config USB_XUSBATM + tristate "Other USB DSL modem support" + depends on USB_ATM + help + Say Y here if you have a DSL USB modem not explicitly supported by + another USB DSL drivers. In order to use your modem you will need to + pass the vendor ID, product ID, and endpoint numbers for transmission + and reception as module parameters. You may need to initialize the + the modem using a user space utility (a firmware loader for example). + + To compile this driver as a module, choose M here: the + module will be called xusbatm. + +endmenu diff --git a/drivers/usb/atm/Makefile b/drivers/usb/atm/Makefile index 9213b8b97587..751f297be2ef 100644 --- a/drivers/usb/atm/Makefile +++ b/drivers/usb/atm/Makefile @@ -1,7 +1,8 @@ # -# Makefile for the rest of the USB drivers -# (the ones that don't fit into any other categories) +# Makefile for USB ATM/xDSL drivers # -obj-$(CONFIG_USB_ATM) += usb_atm.o +obj-$(CONFIG_USB_CXACRU) += cxacru.o obj-$(CONFIG_USB_SPEEDTOUCH) += speedtch.o +obj-$(CONFIG_USB_ATM) += usbatm.o +obj-$(CONFIG_USB_XUSBATM) += xusbatm.o -- cgit v1.2.3 From e20d6645f794b51835e6f740a5b6f95c7e3fd843 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 26 May 2005 14:32:51 +0200 Subject: [PATCH] USB ATM: reduce log spamming Reduce the number of "unknown vpi/vci" debug messages to (usually) at most one per-urb, rather than one per-cell. This is only an issue when (a) many packets come in but no connection is open; and (b) CONFIG_USB_DEBUG is set. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/usbatm.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index e134e2794486..bb2b5d256e34 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -298,7 +298,6 @@ static void usbatm_extract_cells(struct usbatm_data *instance, struct usbatm_vcc_data *cached_vcc = NULL; struct atm_vcc *vcc; struct sk_buff *sarb; - struct usbatm_vcc_data *vcc_data; unsigned int stride = instance->rx_channel.stride; int vci, cached_vci = 0; short vpi, cached_vpi = 0; @@ -311,18 +310,20 @@ static void usbatm_extract_cells(struct usbatm_data *instance, vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti); - if (cached_vcc && (vci == cached_vci) && (vpi == cached_vpi)) - vcc_data = cached_vcc; - else if ((vcc_data = usbatm_find_vcc(instance, vpi, vci))) { - cached_vcc = vcc_data; + if ((vci != cached_vci) || (vpi != cached_vpi)) { cached_vpi = vpi; cached_vci = vci; - } else { - atm_dbg(instance, "%s: unknown vpi/vci (%hd/%d)!\n", __func__, vpi, vci); - continue; + + cached_vcc = usbatm_find_vcc(instance, vpi, vci); + + if (!cached_vcc) + atm_dbg(instance, "%s: unknown vpi/vci (%hd/%d)!\n", __func__, vpi, vci); } - vcc = vcc_data->vcc; + if (!cached_vcc) + continue; + + vcc = cached_vcc->vcc; /* OAM F5 end-to-end */ if (pti == ATM_PTI_E2EF5) { @@ -331,7 +332,7 @@ static void usbatm_extract_cells(struct usbatm_data *instance, continue; } - sarb = vcc_data->sarb; + sarb = cached_vcc->sarb; if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) { atm_dbg(instance, "%s: buffer overrun (sarb->len %u, vcc: 0x%p)!\n", -- cgit v1.2.3 From 65412e48e21ff4fdaf2aea1565ef4fb3ef5262ce Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Fri, 27 May 2005 10:00:08 +0200 Subject: [PATCH] USB ATM: avoid oops on bind failure; plug memory leak Zero the entire instance, not just the struct usbatm_data head. Make sure the just allocated urb is freed if we fail to allocate a buffer. Based on a patch by Stanislaw W. Gruszka. Signed-off-by: Duncan Sands Acked-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/usbatm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index bb2b5d256e34..b178c800ced8 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -949,6 +949,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, struct usb_device *usb_dev = interface_to_usbdev(intf); struct usbatm_data *instance; char *buf; + size_t instance_size = sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs); int error = -ENOMEM; int i, length; int need_heavy; @@ -960,14 +961,13 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, intf->altsetting->desc.bInterfaceNumber); /* instance init */ - instance = kmalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), - GFP_KERNEL); + instance = kmalloc(instance_size, GFP_KERNEL); if (!instance) { dev_dbg(dev, "%s: no memory for instance data!\n", __func__); return -ENOMEM; } - memset(instance, 0, sizeof(*instance)); + memset(instance, 0, instance_size); /* public fields */ @@ -1051,6 +1051,8 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, goto fail_unbind; } + instance->urbs[i] = urb; + buffer = kmalloc(channel->buf_size, GFP_KERNEL); if (!buffer) { dev_dbg(dev, "%s: no memory for buffer %d!\n", __func__, i); @@ -1078,7 +1080,6 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, vdbg("%s: alloced buffer 0x%p buf size %u urb 0x%p", __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb); - instance->urbs[i] = urb; } if (need_heavy && driver->heavy_init) { -- cgit v1.2.3 From 843c944fb86e5e31ee7b319172e657ea22301322 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 30 May 2005 01:09:06 -0700 Subject: [PATCH] USB: fix usbatm gcc-2.95.x bug Work around the gcc-2.95.x macro expansion bug. Cc: Duncan Sands Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/usbatm.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h index 2239804453cf..936646457935 100644 --- a/drivers/usb/atm/usbatm.h +++ b/drivers/usb/atm/usbatm.h @@ -62,7 +62,8 @@ /* FIXME: move to dev_* once ATM is driver model aware */ #define atm_printk(level, instance, format, arg...) \ - printk(level "ATM dev %d: " format , (instance)->atm_dev->number, ## arg) + printk(level "ATM dev %d: " format , \ + (instance)->atm_dev->number , ## arg) #define atm_err(instance, format, arg...) \ atm_printk(KERN_ERR, instance , format , ## arg) -- cgit v1.2.3 From f0706930091902641929f2229bfb106144782c94 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Sat, 28 May 2005 22:06:20 +0200 Subject: [PATCH] USB: usbatm kcalloc cleanup you seem to have applied the original, not the new improved one with whiter teeth that uses kcalloc instead of kmalloc + memset. Here's a patch that goes on top of the one you applied. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/usbatm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index b178c800ced8..bb1db1959854 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -949,7 +949,6 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, struct usb_device *usb_dev = interface_to_usbdev(intf); struct usbatm_data *instance; char *buf; - size_t instance_size = sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs); int error = -ENOMEM; int i, length; int need_heavy; @@ -961,14 +960,12 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, intf->altsetting->desc.bInterfaceNumber); /* instance init */ - instance = kmalloc(instance_size, GFP_KERNEL); + instance = kcalloc(1, sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL); if (!instance) { dev_dbg(dev, "%s: no memory for instance data!\n", __func__); return -ENOMEM; } - memset(instance, 0, instance_size); - /* public fields */ instance->driver = driver; -- cgit v1.2.3 From cc095b0b5b653dca3e106710a72ba28b5bb7456b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 10 May 2005 15:28:38 -0400 Subject: [PATCH] USB: dummy_hcd: sparse cleanups This patch fixes the byte-ordering issue for setup packets in the dummy_hcd driver and cleans up a few things that sparse -Wbitwise dislikes. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index f9540adf2a4f..c78c64ae87af 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -734,7 +734,7 @@ show_function (struct device *dev, struct device_attribute *attr, char *buf) return 0; return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); } -DEVICE_ATTR (function, S_IRUGO, show_function, NULL); +static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); /*-------------------------------------------------------------------------*/ @@ -857,6 +857,9 @@ EXPORT_SYMBOL (usb_gadget_unregister_driver); #undef is_enabled +/* just declare this in any driver that really need it */ +extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); + int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) { return -ENOSYS; @@ -1122,7 +1125,6 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) /* high bandwidth mode */ tmp = le16_to_cpu(ep->desc->wMaxPacketSize); - tmp = le16_to_cpu (tmp); tmp = (tmp >> 11) & 0x03; tmp *= 8 /* applies to entire frame */; limit += limit * tmp; @@ -1265,9 +1267,14 @@ restart: struct usb_ctrlrequest setup; int value = 1; struct dummy_ep *ep2; + unsigned w_index; + unsigned w_value; setup = *(struct usb_ctrlrequest*) urb->setup_packet; - if (setup.wLength != urb->transfer_buffer_length) { + w_index = le16_to_cpu(setup.wIndex); + w_value = le16_to_cpu(setup.wValue); + if (le16_to_cpu(setup.wLength) != + urb->transfer_buffer_length) { maybe_set_status (urb, -EOVERFLOW); goto return_urb; } @@ -1297,16 +1304,16 @@ restart: case USB_REQ_SET_ADDRESS: if (setup.bRequestType != Dev_Request) break; - dum->address = setup.wValue; + dum->address = w_value; maybe_set_status (urb, 0); dev_dbg (udc_dev(dum), "set_address = %d\n", - setup.wValue); + w_value); value = 0; break; case USB_REQ_SET_FEATURE: if (setup.bRequestType == Dev_Request) { value = 0; - switch (setup.wValue) { + switch (w_value) { case USB_DEVICE_REMOTE_WAKEUP: break; case USB_DEVICE_B_HNP_ENABLE: @@ -1324,14 +1331,13 @@ restart: } if (value == 0) { dum->devstatus |= - (1 << setup.wValue); + (1 << w_value); maybe_set_status (urb, 0); } } else if (setup.bRequestType == Ep_Request) { // endpoint halt - ep2 = find_endpoint (dum, - setup.wIndex); + ep2 = find_endpoint (dum, w_index); if (!ep2) { value = -EOPNOTSUPP; break; @@ -1343,7 +1349,7 @@ restart: break; case USB_REQ_CLEAR_FEATURE: if (setup.bRequestType == Dev_Request) { - switch (setup.wValue) { + switch (w_value) { case USB_DEVICE_REMOTE_WAKEUP: dum->devstatus &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); @@ -1356,8 +1362,7 @@ restart: } } else if (setup.bRequestType == Ep_Request) { // endpoint halt - ep2 = find_endpoint (dum, - setup.wIndex); + ep2 = find_endpoint (dum, w_index); if (!ep2) { value = -EOPNOTSUPP; break; @@ -1383,7 +1388,7 @@ restart: if (urb->transfer_buffer_length > 0) { if (setup.bRequestType == Ep_InRequest) { - ep2 = find_endpoint (dum, setup.wIndex); + ep2 = find_endpoint (dum, w_index); if (!ep2) { value = -EOPNOTSUPP; break; @@ -1535,7 +1540,8 @@ hub_descriptor (struct usb_hub_descriptor *desc) memset (desc, 0, sizeof *desc); desc->bDescriptorType = 0x29; desc->bDescLength = 9; - desc->wHubCharacteristics = __constant_cpu_to_le16 (0x0001); + desc->wHubCharacteristics = (__force __u16) + (__constant_cpu_to_le16 (0x0001)); desc->bNbrPorts = 1; desc->bitmap [0] = 0xff; desc->bitmap [1] = 0xff; @@ -1581,7 +1587,7 @@ static int dummy_hub_control ( hub_descriptor ((struct usb_hub_descriptor *) buf); break; case GetHubStatus: - *(u32 *) buf = __constant_cpu_to_le32 (0); + *(__le32 *) buf = __constant_cpu_to_le32 (0); break; case GetPortStatus: if (wIndex != 1) @@ -1621,8 +1627,8 @@ static int dummy_hub_control ( } } set_link_state (dum); - ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status); - ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); + ((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status); + ((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); break; case SetHubFeature: retval = -EPIPE; -- cgit v1.2.3 From 391eca9d8892a940ff8dbfee2ca78942e05c2d37 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 10 May 2005 15:34:16 -0400 Subject: [PATCH] USB: dummy_hcd: add suspend/resume support This patch adds support to dummy_hcd for suspending and resuming the root hub and the emulated platform devices. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 179 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 162 insertions(+), 17 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c78c64ae87af..4d692670f288 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -65,7 +65,7 @@ #define DRIVER_DESC "USB Host+Gadget Emulator" -#define DRIVER_VERSION "17 Dec 2004" +#define DRIVER_VERSION "02 May 2005" static const char driver_name [] = "dummy_hcd"; static const char driver_desc [] = "USB Host+Gadget Emulator"; @@ -150,6 +150,13 @@ struct urbp { struct list_head urbp_list; }; + +enum dummy_rh_state { + DUMMY_RH_RESET, + DUMMY_RH_SUSPENDED, + DUMMY_RH_RUNNING +}; + struct dummy { spinlock_t lock; @@ -163,6 +170,7 @@ struct dummy { struct dummy_request fifo_req; u8 fifo_buf [FIFO_SIZE]; u16 devstatus; + unsigned udc_suspended:1; unsigned pullup:1; unsigned active:1; unsigned old_active:1; @@ -170,6 +178,7 @@ struct dummy { /* * MASTER/HOST side support */ + enum dummy_rh_state rh_state; struct timer_list timer; u32 port_status; u32 old_status; @@ -262,7 +271,9 @@ set_link_state (struct dummy *dum) dum->active = 0; if ((dum->port_status & USB_PORT_STAT_POWER) == 0) dum->port_status = 0; - else if (!dum->pullup) { + + /* UDC suspend must cause a disconnect */ + else if (!dum->pullup || dum->udc_suspended) { dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED | @@ -276,7 +287,8 @@ set_link_state (struct dummy *dum) dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0) dum->port_status &= ~USB_PORT_STAT_SUSPEND; - else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0) + else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && + dum->rh_state != DUMMY_RH_SUSPENDED) dum->active = 1; } @@ -675,11 +687,16 @@ static int dummy_wakeup (struct usb_gadget *_gadget) struct dummy *dum; dum = gadget_to_dummy (_gadget); - if (!(dum->port_status & USB_PORT_STAT_SUSPEND) - || !(dum->devstatus & - ( (1 << USB_DEVICE_B_HNP_ENABLE) + if (!(dum->devstatus & ( (1 << USB_DEVICE_B_HNP_ENABLE) | (1 << USB_DEVICE_REMOTE_WAKEUP)))) return -EINVAL; + if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0) + return -ENOLINK; + if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && + dum->rh_state != DUMMY_RH_SUSPENDED) + return -EIO; + + /* FIXME: What if the root hub is suspended but the port isn't? */ /* hub notices our request, issues downstream resume, etc */ dum->resuming = 1; @@ -917,11 +934,50 @@ static int dummy_udc_remove (struct device *dev) return 0; } +static int dummy_udc_suspend (struct device *dev, pm_message_t state, + u32 level) +{ + struct dummy *dum = dev_get_drvdata(dev); + + if (level != SUSPEND_DISABLE) + return 0; + + dev_dbg (dev, "%s\n", __FUNCTION__); + spin_lock_irq (&dum->lock); + dum->udc_suspended = 1; + set_link_state (dum); + spin_unlock_irq (&dum->lock); + + dev->power.power_state = state; + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); + return 0; +} + +static int dummy_udc_resume (struct device *dev, u32 level) +{ + struct dummy *dum = dev_get_drvdata(dev); + + if (level != RESUME_ENABLE) + return 0; + + dev_dbg (dev, "%s\n", __FUNCTION__); + spin_lock_irq (&dum->lock); + dum->udc_suspended = 0; + set_link_state (dum); + spin_unlock_irq (&dum->lock); + + dev->power.power_state = PMSG_ON; + usb_hcd_poll_rh_status (dummy_to_hcd (dum)); + return 0; +} + static struct device_driver dummy_udc_driver = { .name = (char *) gadget_name, .bus = &platform_bus_type, .probe = dummy_udc_probe, .remove = dummy_udc_remove, + .suspend = dummy_udc_suspend, + .resume = dummy_udc_resume, }; /*-------------------------------------------------------------------------*/ @@ -980,7 +1036,16 @@ static int dummy_urb_enqueue ( static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { - /* giveback happens automatically in timer callback */ + struct dummy *dum; + unsigned long flags; + + /* giveback happens automatically in timer callback, + * so make sure the callback happens */ + dum = hcd_to_dummy (hcd); + spin_lock_irqsave (&dum->lock, flags); + if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list)) + mod_timer (&dum->timer, jiffies); + spin_unlock_irqrestore (&dum->lock, flags); return 0; } @@ -1222,7 +1287,8 @@ restart: if (urb->status != -EINPROGRESS) { /* likely it was just unlinked */ goto return_urb; - } + } else if (dum->rh_state != DUMMY_RH_RUNNING) + continue; type = usb_pipetype (urb->pipe); /* used up this frame's non-periodic bandwidth? @@ -1486,12 +1552,12 @@ return_urb: goto restart; } - /* want a 1 msec delay here */ - if (!list_empty (&dum->urbp_list)) - mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); - else { + if (list_empty (&dum->urbp_list)) { usb_put_dev (dum->udev); dum->udev = NULL; + } else if (dum->rh_state == DUMMY_RH_RUNNING) { + /* want a 1 msec delay here */ + mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); } spin_unlock_irqrestore (&dum->lock, flags); @@ -1510,11 +1576,13 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf) { struct dummy *dum; unsigned long flags; - int retval; + int retval = 0; dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); + if (hcd->state != HC_STATE_RUNNING) + goto done; if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); @@ -1522,14 +1590,15 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf) set_link_state (dum); } - if (!(dum->port_status & PORT_C_MASK)) - retval = 0; - else { + if ((dum->port_status & PORT_C_MASK) != 0) { *buf = (1 << 1); dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n", - dum->port_status); + dum->port_status); retval = 1; + if (dum->rh_state == DUMMY_RH_SUSPENDED) + usb_hcd_resume_root_hub (hcd); } +done: spin_unlock_irqrestore (&dum->lock, flags); return retval; } @@ -1559,6 +1628,9 @@ static int dummy_hub_control ( int retval = 0; unsigned long flags; + if (hcd->state != HC_STATE_RUNNING) + return -ETIMEDOUT; + dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); switch (typeReq) { @@ -1658,6 +1730,7 @@ static int dummy_hub_control ( dum->port_status &= ~(USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); + dum->devstatus = 0; /* 50msec reset signaling */ dum->re_timeout = jiffies + msecs_to_jiffies(50); /* FALLS THROUGH */ @@ -1684,6 +1757,29 @@ static int dummy_hub_control ( return retval; } +static int dummy_hub_suspend (struct usb_hcd *hcd) +{ + struct dummy *dum = hcd_to_dummy (hcd); + + spin_lock_irq (&dum->lock); + dum->rh_state = DUMMY_RH_SUSPENDED; + set_link_state (dum); + spin_unlock_irq (&dum->lock); + return 0; +} + +static int dummy_hub_resume (struct usb_hcd *hcd) +{ + struct dummy *dum = hcd_to_dummy (hcd); + + spin_lock_irq (&dum->lock); + dum->rh_state = DUMMY_RH_RUNNING; + set_link_state (dum); + if (!list_empty(&dum->urbp_list)) + mod_timer (&dum->timer, jiffies); + spin_unlock_irq (&dum->lock); + return 0; +} /*-------------------------------------------------------------------------*/ @@ -1751,6 +1847,7 @@ static int dummy_start (struct usb_hcd *hcd) init_timer (&dum->timer); dum->timer.function = dummy_timer; dum->timer.data = (unsigned long) dum; + dum->rh_state = DUMMY_RH_RUNNING; INIT_LIST_HEAD (&dum->urbp_list); @@ -1803,6 +1900,8 @@ static const struct hc_driver dummy_hcd = { .hub_status_data = dummy_hub_status, .hub_control = dummy_hub_control, + .hub_suspend = dummy_hub_suspend, + .hub_resume = dummy_hub_resume, }; static int dummy_hcd_probe (struct device *dev) @@ -1836,11 +1935,57 @@ static int dummy_hcd_remove (struct device *dev) return 0; } +static int dummy_hcd_suspend (struct device *dev, pm_message_t state, + u32 level) +{ + struct usb_hcd *hcd; + + if (level != SUSPEND_DISABLE) + return 0; + + dev_dbg (dev, "%s\n", __FUNCTION__); + hcd = dev_get_drvdata (dev); + +#ifndef CONFIG_USB_SUSPEND + /* Otherwise this would never happen */ + usb_lock_device (hcd->self.root_hub); + dummy_hub_suspend (hcd); + usb_unlock_device (hcd->self.root_hub); +#endif + + hcd->state = HC_STATE_SUSPENDED; + return 0; +} + +static int dummy_hcd_resume (struct device *dev, u32 level) +{ + struct usb_hcd *hcd; + + if (level != RESUME_ENABLE) + return 0; + + dev_dbg (dev, "%s\n", __FUNCTION__); + hcd = dev_get_drvdata (dev); + hcd->state = HC_STATE_RUNNING; + +#ifndef CONFIG_USB_SUSPEND + /* Otherwise this would never happen */ + usb_lock_device (hcd->self.root_hub); + dummy_hub_resume (hcd); + usb_unlock_device (hcd->self.root_hub); +#endif + + usb_hcd_poll_rh_status (hcd); + return 0; +} + static struct device_driver dummy_hcd_driver = { .name = (char *) driver_name, .bus = &platform_bus_type, .probe = dummy_hcd_probe, .remove = dummy_hcd_remove, + .suspend = dummy_hcd_suspend, + .resume = dummy_hcd_resume, }; /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From 45e45ab45c266642276d01e56d9fb5dccbfad960 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 16 May 2005 08:26:38 -0700 Subject: [PATCH] USB: fix drivers/usb/gadget/ether.c compile error This fixes a compile glitch with CONFIG_USB_ETH_RNDIS disabled, and replaces some inline #ifdeffery (and other code) with inline functions which can evaluate to constants. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 53 ++++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 9f8413e3c10a..86affef226e5 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -91,12 +91,12 @@ static const char driver_desc [] = DRIVER_DESC; #define RX_EXTRA 20 /* guard against rx overflows */ -#ifdef CONFIG_USB_ETH_RNDIS #include "rndis.h" -#else -#define rndis_init() 0 -#define rndis_uninit(x) do{}while(0) -#define rndis_exit() do{}while(0) + +#ifndef CONFIG_USB_ETH_RNDIS +#define rndis_uninit(x) do{}while(0) +#define rndis_deregister(c) do{}while(0) +#define rndis_exit() do{}while(0) #endif /* CDC and RNDIS support the same host-chosen outgoing packet filters. */ @@ -1133,9 +1133,9 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) dev->config = number; INFO (dev, "%s speed config #%d: %d mA, %s, using %s\n", speed, number, power, driver_desc, - dev->rndis + rndis_active(dev) ? "RNDIS" - : (dev->cdc + : (cdc_active(dev) ? "CDC Ethernet" : "CDC Ethernet Subset")); } @@ -1350,7 +1350,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) || !dev->config || wIndex > 1) break; - if (!dev->cdc && wIndex != 0) + if (!cdc_active(dev) && wIndex != 0) break; spin_lock (&dev->lock); @@ -1420,11 +1420,11 @@ done_set_intf: || !dev->config || wIndex > 1) break; - if (!(dev->cdc || dev->rndis) && wIndex != 0) + if (!(cdc_active(dev) || rndis_active(dev)) && wIndex != 0) break; /* for CDC, iff carrier is on, data interface is active. */ - if (dev->rndis || wIndex != 1) + if (rndis_active(dev) || wIndex != 1) *(u8 *)req->buf = 0; else *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0; @@ -1437,8 +1437,7 @@ done_set_intf: * wValue = packet filter bitmap */ if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) - || !dev->cdc - || dev->rndis + || !cdc_active(dev) || wLength != 0 || wIndex > 1) break; @@ -1462,7 +1461,7 @@ done_set_intf: */ case USB_CDC_SEND_ENCAPSULATED_COMMAND: if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) - || !dev->rndis + || !rndis_active(dev) || wLength > USB_BUFSIZ || wValue || rndis_control_intf.bInterfaceNumber @@ -1477,7 +1476,7 @@ done_set_intf: case USB_CDC_GET_ENCAPSULATED_RESPONSE: if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE) == ctrl->bRequestType - && dev->rndis + && rndis_active(dev) // && wLength >= 0x0400 && !wValue && rndis_control_intf.bInterfaceNumber @@ -1661,11 +1660,9 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req) /* normal completion */ case 0: skb_put (skb, req->actual); -#ifdef CONFIG_USB_ETH_RNDIS /* we know MaxPacketsPerTransfer == 1 here */ - if (dev->rndis) + if (rndis_active(dev)) status = rndis_rm_hdr (skb); -#endif if (status < 0 || ETH_HLEN > skb->len || skb->len > ETH_FRAME_LEN) { @@ -1893,8 +1890,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) * or the hardware can't use skb buffers. * or there's not enough space for any RNDIS headers we need */ -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis) { + if (rndis_active(dev)) { struct sk_buff *skb_rndis; skb_rndis = skb_realloc_headroom (skb, @@ -1907,7 +1903,6 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) rndis_add_hdr (skb); length = skb->len; } -#endif req->buf = skb->data; req->context = skb; req->complete = tx_complete; @@ -1940,9 +1935,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) } if (retval) { -#ifdef CONFIG_USB_ETH_RNDIS drop: -#endif dev->stats.tx_dropped++; dev_kfree_skb_any (skb); spin_lock_irqsave (&dev->lock, flags); @@ -2023,6 +2016,10 @@ static int rndis_control_ack (struct net_device *net) return 0; } +#else + +#define rndis_control_ack NULL + #endif /* RNDIS */ static void eth_start (struct eth_dev *dev, int gfp_flags) @@ -2035,14 +2032,12 @@ static void eth_start (struct eth_dev *dev, int gfp_flags) /* and open the tx floodgates */ atomic_set (&dev->tx_qlen, 0); netif_wake_queue (dev->net); -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis) { + if (rndis_active(dev)) { rndis_set_param_medium (dev->rndis_config, NDIS_MEDIUM_802_3, BITRATE(dev->gadget)/100); (void) rndis_signal_connect (dev->rndis_config); } -#endif } static int eth_open (struct net_device *net) @@ -2083,13 +2078,11 @@ static int eth_stop (struct net_device *net) } } -#ifdef CONFIG_USB_ETH_RNDIS - if (dev->rndis) { + if (rndis_active(dev)) { rndis_set_param_medium (dev->rndis_config, NDIS_MEDIUM_802_3, 0); (void) rndis_signal_disconnect (dev->rndis_config); } -#endif return 0; } @@ -2127,10 +2120,8 @@ eth_unbind (struct usb_gadget *gadget) struct eth_dev *dev = get_gadget_data (gadget); DEBUG (dev, "unbind\n"); -#ifdef CONFIG_USB_ETH_RNDIS rndis_deregister (dev->rndis_config); rndis_exit (); -#endif /* we've already been disconnected ... no i/o is active */ if (dev->req) { @@ -2481,7 +2472,6 @@ autoconf_fail: dev->host_mac [2], dev->host_mac [3], dev->host_mac [4], dev->host_mac [5]); -#ifdef CONFIG_USB_ETH_RNDIS if (rndis) { u32 vendorID = 0; @@ -2509,7 +2499,6 @@ fail0: goto fail0; INFO (dev, "RNDIS ready\n"); } -#endif return status; -- cgit v1.2.3 From 486e2df6ce213d0c776befdf3fe5ffc61dd61688 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 24 May 2005 17:51:52 -0700 Subject: [PATCH] USB gadget: drain rndis response queue on disconnect Drain the rndis response queue on disconnect. This fixes a problem in which an rndis response left in the queue from a previous session could cause a subsequent session to fail. Signed-off-by: Andy Lowe Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/rndis.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index c9a0af29ecb6..06b6eba925b5 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -1025,11 +1025,17 @@ int rndis_signal_disconnect (int configNr) void rndis_uninit (int configNr) { + u8 *buf; + u32 length; + if (configNr >= RNDIS_MAX_CONFIGS) return; rndis_per_dev_params [configNr].used = 0; rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED; - return; + + /* drain the response queue */ + while ((buf = rndis_get_next_response(configNr, &length))) + rndis_free_response(configNr, buf); } void rndis_set_host_mac (int configNr, const u8 *addr) -- cgit v1.2.3 From e07fefa6b212f43c40fdbc1a62de690d91a4b617 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 31 May 2005 16:33:21 -0400 Subject: [PATCH] USB UHCI: Detect invalid ports This patch changes the way uhci-hcd detects valid ports. The specification doesn't mention any way to find out how many ports a controller has, so the driver has to use some heuristics, reading the port status and control register and deciding whether the value makes sense. With this patch the driver will recognize a typical failure mode (all bits set to one) for nonexistent ports and won't assume there are always at least 2 ports -- such an assumption seems silly if the heuristics have already shown that the ports don't exist. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index fdf54295da73..0d5d2545bf07 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -495,24 +495,24 @@ static int uhci_reset(struct usb_hcd *hcd) /* The UHCI spec says devices must have 2 ports, and goes on to say * they may have more but gives no way to determine how many there - * are. However, according to the UHCI spec, Bit 7 of the port + * are. However according to the UHCI spec, Bit 7 of the port * status and control register is always set to 1. So we try to - * use this to our advantage. + * use this to our advantage. Another common failure mode when + * a nonexistent register is addressed is to return all ones, so + * we test for that also. */ for (port = 0; port < (io_size - USBPORTSC1) / 2; port++) { unsigned int portstatus; portstatus = inw(uhci->io_addr + USBPORTSC1 + (port * 2)); - if (!(portstatus & 0x0080)) + if (!(portstatus & 0x0080) || portstatus == 0xffff) break; } if (debug) dev_info(uhci_dev(uhci), "detected %d ports\n", port); - /* Anything less than 2 or greater than 7 is weird, - * so we'll ignore it. - */ - if (port < 2 || port > UHCI_RH_MAXCHILD) { + /* Anything greater than 7 is weird so we'll ignore it. */ + if (port > UHCI_RH_MAXCHILD) { dev_info(uhci_dev(uhci), "port count misdetected? " "forcing to 2 ports\n"); port = 2; -- cgit v1.2.3 From 77078570abe0848c3076b4f7d42f79b1407f3e8f Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 28 May 2005 10:46:18 -0700 Subject: [PATCH] USB: ehci-hcd - fix page pointer allocation in itd_patch() The itd_patch() function is responsible for allocating entries in the buffer page pointer list of the iTD. Particularly, a new page pointer is needed every time when buffer data crosses a page boundary. However, there is a bug in the allocation logic: the function does not allocate a new entry when the current transaction is the first transaction in the iTD (as indicated by first!=0). The consequence is that, when the data of the first transaction begins somewhere at the end of a page so that it actually does cross the page boundary, no new page pointer is allocated. This means that the data at the end of the first transaction (beyond the page boundary) will be accessed by the HC using the second page pointer, which is zero. Furthermore, the first page pointer will be later overwritten by the page pointers of the other transactions, which will garble it because the value is or-ed into the iTD field. All this particular check (for !first) does is cause incorrect behaviour, so it should be entirely removed (and with it the variable first that is not used for anything else). Signed-off-by: Clemens Ladisch Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 2fa1ffee5ff3..c2104cad4033 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -637,9 +637,8 @@ iso_stream_alloc (int mem_flags) { struct ehci_iso_stream *stream; - stream = kmalloc(sizeof *stream, mem_flags); + stream = kcalloc(1, sizeof *stream, mem_flags); if (likely (stream != NULL)) { - memset (stream, 0, sizeof(*stream)); INIT_LIST_HEAD(&stream->td_list); INIT_LIST_HEAD(&stream->free_list); stream->next_uframe = -1; @@ -894,7 +893,7 @@ itd_sched_init ( trans |= length << 16; uframe->transaction = cpu_to_le32 (trans); - /* might need to cross a buffer page within a td */ + /* might need to cross a buffer page within a uframe */ uframe->bufp = (buf & ~(u64)0x0fff); buf += length; if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff)))) @@ -1194,6 +1193,7 @@ itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd) { int i; + /* it's been recently zeroed */ itd->hw_next = EHCI_LIST_END; itd->hw_bufp [0] = stream->buf0; itd->hw_bufp [1] = stream->buf1; @@ -1210,8 +1210,7 @@ itd_patch ( struct ehci_itd *itd, struct ehci_iso_sched *iso_sched, unsigned index, - u16 uframe, - int first + u16 uframe ) { struct ehci_iso_packet *uf = &iso_sched->packet [index]; @@ -1228,7 +1227,7 @@ itd_patch ( itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(uf->bufp >> 32)); /* iso_frame_desc[].offset must be strictly increasing */ - if (unlikely (!first && uf->cross)) { + if (unlikely (uf->cross)) { u64 bufp = uf->bufp + 4096; itd->pg = ++pg; itd->hw_bufp [pg] |= cpu_to_le32 (bufp & ~(u32)0); @@ -1257,7 +1256,7 @@ itd_link_urb ( struct ehci_iso_stream *stream ) { - int packet, first = 1; + int packet; unsigned next_uframe, uframe, frame; struct ehci_iso_sched *iso_sched = urb->hcpriv; struct ehci_itd *itd; @@ -1290,7 +1289,6 @@ itd_link_urb ( list_move_tail (&itd->itd_list, &stream->td_list); itd->stream = iso_stream_get (stream); itd->urb = usb_get_urb (urb); - first = 1; itd_init (stream, itd); } @@ -1298,8 +1296,7 @@ itd_link_urb ( frame = next_uframe >> 3; itd->usecs [uframe] = stream->usecs; - itd_patch (itd, iso_sched, packet, uframe, first); - first = 0; + itd_patch (itd, iso_sched, packet, uframe); next_uframe += stream->interval; stream->depth += stream->interval; -- cgit v1.2.3 From 2c45b6feb394337b4b468229632b8737375caf1d Mon Sep 17 00:00:00 2001 From: "C. Adam Oldham" Date: Thu, 2 Jun 2005 17:16:34 -0400 Subject: [PATCH] USB: Fix race condition in usblp_write Initialize status fields in the read and write urbs to prevent a race condition with open/read/close - open/write/close sequences. Fixes bug #4432 at bugzilla.kernel.org Signed-off-by: Adam Oldham Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index bba22e97ea0f..dff134185c18 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -379,6 +379,8 @@ static int usblp_open(struct inode *inode, struct file *file) usblp->writeurb->transfer_buffer_length = 0; usblp->wcomplete = 1; /* we begin writeable */ usblp->rcomplete = 0; + usblp->writeurb->status = 0; + usblp->readurb->status = 0; if (usblp->bidir) { usblp->readcount = 0; -- cgit v1.2.3 From 16367877949a91b11bcc6f37b94d0033388b4256 Mon Sep 17 00:00:00 2001 From: Kiril Jovchev Date: Sun, 5 Jun 2005 01:52:33 +0300 Subject: [PATCH] USB: add support for Creative WebCam mini to stv680 driver Added support for Creative WebCam Go Mini. Camera has STV680 chip and just different Product ID(0x4007) and Vendor ID (0x041e). Signed-off-by: Kiril Jovchev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/stv680.c | 8 ++++++-- drivers/usb/media/stv680.h | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c index ae455c8e3702..7398a7f19c1e 100644 --- a/drivers/usb/media/stv680.c +++ b/drivers/usb/media/stv680.c @@ -1375,9 +1375,13 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) { camera_name = "STV0680"; PDEBUG (0, "STV(i): STV0680 camera found."); + } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) && + (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) { + camera_name = "Creative WebCam Go Mini"; + PDEBUG (0, "STV(i): Creative WebCam Go Mini found."); } else { - PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 values."); - PDEBUG (0, "STV(e): Check that the STV0680 camera is connected to the computer."); + PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values."); + PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer."); retval = -ENODEV; goto error; } diff --git a/drivers/usb/media/stv680.h b/drivers/usb/media/stv680.h index 7e0e314dcf12..445940612603 100644 --- a/drivers/usb/media/stv680.h +++ b/drivers/usb/media/stv680.h @@ -41,12 +41,17 @@ #define USB_PENCAM_VENDOR_ID 0x0553 #define USB_PENCAM_PRODUCT_ID 0x0202 + +#define USB_CREATIVEGOMINI_VENDOR_ID 0x041e +#define USB_CREATIVEGOMINI_PRODUCT_ID 0x4007 + #define PENCAM_TIMEOUT 1000 /* fmt 4 */ #define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24 static struct usb_device_id device_table[] = { {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)}, + {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)}, {} }; MODULE_DEVICE_TABLE (usb, device_table); -- cgit v1.2.3 From c11372da33c9d38cb35867915f15c74778e1a3a4 Mon Sep 17 00:00:00 2001 From: Vincent Vanackere Date: Sun, 5 Jun 2005 12:21:43 +0200 Subject: [PATCH] USB: fix atiremote input doesn`t register `device` & `driver` section in sysfs (/sys/class/input/event#) > On Sun, Apr 10, 2005 at 07:21:28PM +0600, Viktor A. Danilov wrote: > > > > PROBLEM: aiptek input doesn`t register `device` & `driver` section in sysfs (/sys/class/input/event#) > > REASON: `dev` - field not filled... > > SOLUTION: in linux/drivers/usb/input/aiptek.c write > > aiptek->inputdev.dev = &intf->dev; > > before calling > > input_register_device(&aiptek->inputdev); The following (tested) patch fixes the exact same issue with the ATI Remote input driver. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/ati_remote.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index 860df26323b1..7d30f55ad7bd 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -654,6 +654,7 @@ static void ati_remote_input_init(struct ati_remote *ati_remote) idev->id.vendor = le16_to_cpu(ati_remote->udev->descriptor.idVendor); idev->id.product = le16_to_cpu(ati_remote->udev->descriptor.idProduct); idev->id.version = le16_to_cpu(ati_remote->udev->descriptor.bcdDevice); + idev->dev = &(ati_remote->udev->dev); } static int ati_remote_initialize(struct ati_remote *ati_remote) -- cgit v1.2.3 From 01205a0e60bb5a66d768b881fb8355981b912510 Mon Sep 17 00:00:00 2001 From: Domen Puncer Date: Sun, 5 Jun 2005 14:46:16 +0200 Subject: [PATCH] USB: usblp: 2x up() in usblp_read up(&usblp->sem) was called twice in a row in this code path. Signed-off-by: Domen Puncer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index dff134185c18..7ce43fb8118a 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -753,6 +753,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, schedule(); } else { set_current_state(TASK_RUNNING); + down(&usblp->sem); break; } down (&usblp->sem); -- cgit v1.2.3 From 5203ad441310a4c2abd4fb79015a6bdadc2a5a4f Mon Sep 17 00:00:00 2001 From: Matthew Dharm Date: Mon, 6 Jun 2005 17:19:29 -0700 Subject: [PATCH] USB Storage: endpoint toggles and reset delays This patch does two things to help reset recovery. It started life as as496 and was rediffed by me. First, the patch checks the result of a CLEAR_HALT request and doesn't reset the endpoint's data toggle unless the request succeeded. Second, it reduces the timeout for a device reset from 20 seconds to 5 seconds. If all goes well, then I've finally figured quilt out and this patch should apply cleanly. Signed-off-by: Alan Stern Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 9743e289cd3b..419afb2216b9 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -266,8 +266,9 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) NULL, 0, 3*HZ); /* reset the endpoint toggle */ - usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), - usb_pipeout(pipe), 0); + if (result >= 0) + usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), + usb_pipeout(pipe), 0); US_DEBUGP("%s: result = %d\n", __FUNCTION__, result); return result; @@ -1124,7 +1125,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) * It's handy that every transport mechanism uses the control endpoint for * resets. * - * Basically, we send a reset with a 20-second timeout, so we don't get + * Basically, we send a reset with a 5-second timeout, so we don't get * jammed attempting to do the reset. */ static int usb_stor_reset_common(struct us_data *us, @@ -1145,13 +1146,9 @@ static int usb_stor_reset_common(struct us_data *us, clear_bit(US_FLIDX_ABORTING, &us->flags); scsi_unlock(us_to_host(us)); - /* A 20-second timeout may seem rather long, but a LaCie - * StudioDrive USB2 device takes 16+ seconds to get going - * following a powerup or USB attach event. - */ result = usb_stor_control_msg(us, us->send_ctrl_pipe, request, requesttype, value, index, data, size, - 20*HZ); + 5*HZ); if (result < 0) { US_DEBUGP("Soft reset failed: %d\n", result); goto Done; @@ -1173,8 +1170,10 @@ static int usb_stor_reset_common(struct us_data *us, US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n"); result2 = usb_stor_clear_halt(us, us->send_bulk_pipe); - /* return a result code based on the result of the control message */ - if (result < 0 || result2 < 0) { + /* return a result code based on the result of the clear-halts */ + if (result >= 0) + result = result2; + if (result < 0) { US_DEBUGP("Soft reset failed\n"); goto Done; } -- cgit v1.2.3 From 4d07ef762fc8d6d35ecc1511a3b953a733a61a5f Mon Sep 17 00:00:00 2001 From: Matthew Dharm Date: Mon, 6 Jun 2005 17:21:41 -0700 Subject: [PATCH] USB Storage: port reset on transport error This patch causes a port reset whenever there's a transport error or abort. If that fails it reverts back to doing a mass-storage device reset. It started life as as497 and was rediffed by me. This makes error recovery a lot quicker and more reliable. Signed-off-by: Alan Stern Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/scsiglue.c | 45 ++++++------------- drivers/usb/storage/scsiglue.h | 1 + drivers/usb/storage/transport.c | 99 ++++++++++++++++++++++++++++------------- drivers/usb/storage/transport.h | 1 + 4 files changed, 82 insertions(+), 64 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index e43eddc3d44b..da2bfa944b96 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -255,50 +255,23 @@ static int device_reset(struct scsi_cmnd *srb) /* lock the device pointers and do the reset */ down(&(us->dev_semaphore)); - if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { - result = FAILED; - US_DEBUGP("No reset during disconnect\n"); - } else - result = us->transport_reset(us); + result = us->transport_reset(us); up(&(us->dev_semaphore)); - return result; + return result < 0 ? FAILED : SUCCESS; } -/* This resets the device's USB port. */ -/* It refuses to work if there's more than one interface in - * the device, so that other users are not affected. */ +/* Simulate a SCSI bus reset by resetting the device's USB port. */ /* This is always called with scsi_lock(host) held */ static int bus_reset(struct scsi_cmnd *srb) { struct us_data *us = host_to_us(srb->device->host); - int result, rc; + int result; US_DEBUGP("%s called\n", __FUNCTION__); - /* The USB subsystem doesn't handle synchronisation between - * a device's several drivers. Therefore we reset only devices - * with just one interface, which we of course own. */ - down(&(us->dev_semaphore)); - if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { - result = -EIO; - US_DEBUGP("No reset during disconnect\n"); - } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) { - result = -EBUSY; - US_DEBUGP("Refusing to reset a multi-interface device\n"); - } else { - rc = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); - if (rc < 0) { - US_DEBUGP("unable to lock device for reset: %d\n", rc); - result = rc; - } else { - result = usb_reset_device(us->pusb_dev); - if (rc) - usb_unlock_device(us->pusb_dev); - US_DEBUGP("usb_reset_device returns %d\n", result); - } - } + result = usb_stor_port_reset(us); up(&(us->dev_semaphore)); /* lock the host for the return */ @@ -320,6 +293,14 @@ void usb_stor_report_device_reset(struct us_data *us) } } +/* Report a driver-initiated bus reset to the SCSI layer. + * Calling this for a SCSI-initiated reset is unnecessary but harmless. + * The caller must own the SCSI host lock. */ +void usb_stor_report_bus_reset(struct us_data *us) +{ + scsi_report_bus_reset(us_to_host(us), 0); +} + /*********************************************************************** * /proc/scsi/ functions ***********************************************************************/ diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h index d0a49af026c4..737e4fa6045f 100644 --- a/drivers/usb/storage/scsiglue.h +++ b/drivers/usb/storage/scsiglue.h @@ -42,6 +42,7 @@ #define _SCSIGLUE_H_ extern void usb_stor_report_device_reset(struct us_data *us); +extern void usb_stor_report_bus_reset(struct us_data *us); extern unsigned char usb_stor_sense_invalidCDB[18]; extern struct scsi_host_template usb_stor_host_template; diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 419afb2216b9..e6b1c6cf07f2 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -541,15 +541,15 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) */ if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { US_DEBUGP("-- command was aborted\n"); - goto Handle_Abort; + srb->result = DID_ABORT << 16; + goto Handle_Errors; } /* if there is a transport error, reset and don't auto-sense */ if (result == USB_STOR_TRANSPORT_ERROR) { US_DEBUGP("-- transport indicates error, resetting\n"); - us->transport_reset(us); srb->result = DID_ERROR << 16; - return; + goto Handle_Errors; } /* if the transport provided its own sense data, don't auto-sense */ @@ -669,7 +669,8 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { US_DEBUGP("-- auto-sense aborted\n"); - goto Handle_Abort; + srb->result = DID_ABORT << 16; + goto Handle_Errors; } if (temp_result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("-- auto-sense failure\n"); @@ -678,9 +679,9 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) * multi-target device, since failure of an * auto-sense is perfectly valid */ - if (!(us->flags & US_FL_SCM_MULT_TARG)) - us->transport_reset(us); srb->result = DID_ERROR << 16; + if (!(us->flags & US_FL_SCM_MULT_TARG)) + goto Handle_Errors; return; } @@ -721,12 +722,28 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) return; - /* abort processing: the bulk-only transport requires a reset - * following an abort */ - Handle_Abort: - srb->result = DID_ABORT << 16; - if (us->protocol == US_PR_BULK) + /* Error and abort processing: try to resynchronize with the device + * by issuing a port reset. If that fails, try a class-specific + * device reset. */ + Handle_Errors: + + /* Let the SCSI layer know we are doing a reset, set the + * RESETTING bit, and clear the ABORTING bit so that the reset + * may proceed. */ + scsi_lock(us_to_host(us)); + usb_stor_report_bus_reset(us); + set_bit(US_FLIDX_RESETTING, &us->flags); + clear_bit(US_FLIDX_ABORTING, &us->flags); + scsi_unlock(us_to_host(us)); + + result = usb_stor_port_reset(us); + if (result < 0) { + scsi_lock(us_to_host(us)); + usb_stor_report_device_reset(us); + scsi_unlock(us_to_host(us)); us->transport_reset(us); + } + clear_bit(US_FLIDX_RESETTING, &us->flags); } /* Stop the current URB transfer */ @@ -1134,24 +1151,18 @@ static int usb_stor_reset_common(struct us_data *us, { int result; int result2; - int rc = FAILED; - /* Let the SCSI layer know we are doing a reset, set the - * RESETTING bit, and clear the ABORTING bit so that the reset - * may proceed. - */ - scsi_lock(us_to_host(us)); - usb_stor_report_device_reset(us); - set_bit(US_FLIDX_RESETTING, &us->flags); - clear_bit(US_FLIDX_ABORTING, &us->flags); - scsi_unlock(us_to_host(us)); + if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { + US_DEBUGP("No reset during disconnect\n"); + return -EIO; + } result = usb_stor_control_msg(us, us->send_ctrl_pipe, request, requesttype, value, index, data, size, 5*HZ); if (result < 0) { US_DEBUGP("Soft reset failed: %d\n", result); - goto Done; + return result; } /* Give the device some time to recover from the reset, @@ -1161,7 +1172,7 @@ static int usb_stor_reset_common(struct us_data *us, HZ*6); if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { US_DEBUGP("Reset interrupted by disconnect\n"); - goto Done; + return -EIO; } US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n"); @@ -1173,16 +1184,11 @@ static int usb_stor_reset_common(struct us_data *us, /* return a result code based on the result of the clear-halts */ if (result >= 0) result = result2; - if (result < 0) { + if (result < 0) US_DEBUGP("Soft reset failed\n"); - goto Done; - } - US_DEBUGP("Soft reset done\n"); - rc = SUCCESS; - - Done: - clear_bit(US_FLIDX_RESETTING, &us->flags); - return rc; + else + US_DEBUGP("Soft reset done\n"); + return result; } /* This issues a CB[I] Reset to the device in question @@ -1212,3 +1218,32 @@ int usb_stor_Bulk_reset(struct us_data *us) USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, NULL, 0); } + +/* Issue a USB port reset to the device. But don't do anything if + * there's more than one interface in the device, so that other users + * are not affected. */ +int usb_stor_port_reset(struct us_data *us) +{ + int result, rc; + + if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { + result = -EIO; + US_DEBUGP("No reset during disconnect\n"); + } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) { + result = -EBUSY; + US_DEBUGP("Refusing to reset a multi-interface device\n"); + } else { + result = rc = + usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); + if (result < 0) { + US_DEBUGP("unable to lock device for reset: %d\n", + result); + } else { + result = usb_reset_device(us->pusb_dev); + if (rc) + usb_unlock_device(us->pusb_dev); + US_DEBUGP("usb_reset_device returns %d\n", result); + } + } + return result; +} diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index e25f8d8fc741..8d9e0663f8fe 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -171,4 +171,5 @@ extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe, void *buf, unsigned int length, int use_sg, int *residual); +extern int usb_stor_port_reset(struct us_data *us); #endif -- cgit v1.2.3 From 86dbde9cbdfe8bc2c2dfe5d33027d3acc55e0470 Mon Sep 17 00:00:00 2001 From: Matthew Dharm Date: Mon, 6 Jun 2005 17:22:42 -0700 Subject: [PATCH] USB Storage: retry hard errors This patch started life as as527, and was rediffed by me. Since the IDE interface doesn't convey much information about types of errors, many USB-IDE adapters report all low-level errors with SK = 0x04, which is supposed to be used only for non-recoverable errors. As a result the SCSI midlayer doesn't retry the command. But quite often a retry would succeed, whereas an unnecessary retry doesn't really hurt anything. This patch uses a recently-implemented flag to tell the SCSI midlayer that such hardware errors should be retried. Signed-off-by: Alan Stern Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/scsiglue.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index da2bfa944b96..af294bb68c35 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -155,6 +155,15 @@ static int slave_configure(struct scsi_device *sdev) * If this device makes that mistake, tell the sd driver. */ if (us->flags & US_FL_FIX_CAPACITY) sdev->fix_capacity = 1; + + /* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable + * Hardware Error) when any low-level error occurs, + * recoverable or not. Setting this flag tells the SCSI + * midlayer to retry such commands, which frequently will + * succeed and fix the error. The worst this can lead to + * is an occasional series of retries that will all fail. */ + sdev->retry_hwerror = 1; + } else { /* Non-disk-type devices don't need to blacklist any pages -- cgit v1.2.3 From e3bc8b4e00d0ce219165d469409f2770698574f6 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 15 Jun 2005 08:04:30 -0700 Subject: [PATCH] USB: usbnet debug message fix One debug message won't print the right value; OSDL bugid 4545. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/usbnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 4cbb408af727..8a945f4f3693 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1429,7 +1429,7 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf) info->ether = (void *) buf; if (info->ether->bLength != sizeof *info->ether) { dev_dbg (&intf->dev, "CDC ether len %u\n", - info->u->bLength); + info->ether->bLength); goto bad_desc; } dev->net->mtu = le16_to_cpup ( -- cgit v1.2.3 From 822e14ac222d1dad3f5393b75603f0455aebbefc Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 13 Jun 2005 06:55:03 -0700 Subject: [PATCH] USB: resolve ethernet gadget build glitch on pxa This fixes a build error on pxa25x processes with pxa2xx_udc and CONFIG_USB_ETH=m # CONFIG_USB_ETH_RNDIS is not set The error is because on that CPU there's no status transfer support except with RNDIS. Workaround, enable the RNDIS support too. Signed-off-by: Ian Campbell Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 86affef226e5..5bb53ae88969 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2428,6 +2428,7 @@ autoconf_fail: dev->req->complete = eth_setup_complete; /* ... and maybe likewise for status transfer */ +#ifdef DEV_CONFIG_CDC if (dev->status_ep) { dev->stat_req = eth_req_alloc (dev->status_ep, STATUS_BYTECOUNT, GFP_KERNEL); @@ -2437,6 +2438,7 @@ autoconf_fail: } dev->stat_req->context = NULL; } +#endif /* finish hookup to lower layer ... */ dev->gadget = gadget; -- cgit v1.2.3 From 0ed0c0c48c508578c30aa58f755ca0d692636906 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 15 Jun 2005 15:49:48 -0400 Subject: [PATCH] USB: usbcore: inverted test for resuming interfaces This one-liner fixes a test for interfaces that are already resumed. It would be nice if this could get into 2.6.12, but it's not critical since it only affects people doing selective (runtime) suspend/resume. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 63ee3d97b6a9..32ff32181852 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1733,7 +1733,7 @@ static int finish_port_resume(struct usb_device *udev) struct usb_driver *driver; intf = udev->actconfig->interface[i]; - if (intf->dev.power.power_state == PMSG_SUSPEND) + if (intf->dev.power.power_state == PMSG_ON) continue; if (!intf->dev.driver) { /* FIXME maybe force to alt 0 */ -- cgit v1.2.3 From 8c8709334cec803368a432a33e0f2e116d48fe07 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 27 Jun 2005 14:36:34 -0700 Subject: [PATCH] ppc32: Remove CONFIG_PMAC_PBOOK This patch removes CONFIG_PMAC_PBOOK (PowerBook support). This is now split into CONFIG_PMAC_MEDIABAY for the actual hotswap bay that some powerbooks have, CONFIG_PM for power management related code, and just left out of any CONFIG_* option for some generally useful stuff that can be used on non-laptops as well. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/platforms/pmac_sleep.S | 4 +- arch/ppc/platforms/pmac_time.c | 8 +- drivers/block/swim3.c | 10 +- drivers/char/misc.c | 3 - drivers/ide/ppc/pmac.c | 8 +- drivers/ieee1394/ohci1394.c | 10 +- drivers/macintosh/Kconfig | 35 ++----- drivers/macintosh/Makefile | 2 +- drivers/macintosh/adb.c | 10 +- drivers/macintosh/via-pmu.c | 70 ++++++-------- drivers/usb/host/ohci-pci.c | 13 +-- drivers/video/aty/aty128fb.c | 14 --- drivers/video/chipsfb.c | 176 +++++++++++++++++++----------------- include/linux/pmu.h | 6 +- sound/oss/dmasound/dmasound_awacs.c | 14 +-- sound/ppc/awacs.c | 8 +- sound/ppc/daca.c | 6 +- sound/ppc/pmac.c | 11 ++- sound/ppc/pmac.h | 2 +- sound/ppc/tumbler.c | 4 +- 20 files changed, 193 insertions(+), 221 deletions(-) (limited to 'drivers/usb') diff --git a/arch/ppc/platforms/pmac_sleep.S b/arch/ppc/platforms/pmac_sleep.S index f459ade1bd63..016a74649155 100644 --- a/arch/ppc/platforms/pmac_sleep.S +++ b/arch/ppc/platforms/pmac_sleep.S @@ -46,7 +46,7 @@ .section .text .align 5 -#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ_PMAC) +#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC) /* This gets called by via-pmu.c late during the sleep process. * The PMU was already send the sleep command and will shut us down @@ -382,7 +382,7 @@ turn_on_mmu: isync rfi -#endif /* defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ) */ +#endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */ .section .data .balign L1_CACHE_LINE_SIZE diff --git a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c index de60ccc7db9f..778ce4fec368 100644 --- a/arch/ppc/platforms/pmac_time.c +++ b/arch/ppc/platforms/pmac_time.c @@ -206,7 +206,7 @@ via_calibrate_decr(void) return 1; } -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM /* * Reset the time after a sleep. */ @@ -238,7 +238,7 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when) static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = { time_sleep_notify, SLEEP_LEVEL_MISC, }; -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PM */ /* * Query the OF and get the decr frequency. @@ -251,9 +251,9 @@ pmac_calibrate_decr(void) struct device_node *cpu; unsigned int freq, *fp; -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM pmu_register_sleep_notifier(&time_sleep_notifier); -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PM */ /* We assume MacRISC2 machines have correct device-tree * calibration. That's better since the VIA itself seems diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 5b09cf154ac7..e5f7494c00ee 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -253,7 +253,7 @@ static int floppy_revalidate(struct gendisk *disk); static int swim3_add_device(struct device_node *swims); int swim3_init(void); -#ifndef CONFIG_PMAC_PBOOK +#ifndef CONFIG_PMAC_MEDIABAY #define check_media_bay(which, what) 1 #endif @@ -297,9 +297,11 @@ static void do_fd_request(request_queue_t * q) int i; for(i=0;imedia_bay && check_media_bay(fs->media_bay, MB_FD)) return -ENXIO; +#endif switch (cmd) { case FDEJECT: @@ -881,8 +885,10 @@ static int floppy_open(struct inode *inode, struct file *filp) int n, err = 0; if (fs->ref_count == 0) { +#ifdef CONFIG_PMAC_MEDIABAY if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) return -ENXIO; +#endif out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2); out_8(&sw->control_bic, 0xff); out_8(&sw->mode, 0x95); @@ -967,8 +973,10 @@ static int floppy_revalidate(struct gendisk *disk) struct swim3 __iomem *sw; int ret, n; +#ifdef CONFIG_PMAC_MEDIABAY if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) return -ENXIO; +#endif sw = fs->swim3; grab_drive(fs, revalidating, 0); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 31cf84d69026..931efd58f87a 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -308,9 +308,6 @@ static int __init misc_init(void) #endif #ifdef CONFIG_BVME6000 rtc_DP8570A_init(); -#endif -#ifdef CONFIG_PMAC_PBOOK - pmu_device_init(); #endif if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { printk("unable to get major %d for misc devices\n", diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 569f16767442..818380b5fd27 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1324,9 +1324,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) /* XXX FIXME: Media bay stuff need re-organizing */ if (np->parent && np->parent->name && strcasecmp(np->parent->name, "media-bay") == 0) { -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PMAC_MEDIABAY media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, hwif->index); -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PMAC_MEDIABAY */ pmif->mediabay = 1; if (!bidp) pmif->aapl_bus_id = 1; @@ -1382,10 +1382,10 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) hwif->index, model_name[pmif->kind], pmif->aapl_bus_id, pmif->mediabay ? " (mediabay)" : "", hwif->irq); -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PMAC_MEDIABAY if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0) hwif->noprobe = 0; -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PMAC_MEDIABAY */ hwif->sg_max_nents = MAX_DCMDS; diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 36e25ac823dc..b3d3d22fde64 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -3538,8 +3538,8 @@ static void ohci1394_pci_remove(struct pci_dev *pdev) static int ohci1394_pci_resume (struct pci_dev *pdev) { -#ifdef CONFIG_PMAC_PBOOK - { +#ifdef CONFIG_PPC_PMAC + if (_machine == _MACH_Pmac) { struct device_node *of_node; /* Re-enable 1394 */ @@ -3547,7 +3547,7 @@ static int ohci1394_pci_resume (struct pci_dev *pdev) if (of_node) pmac_call_feature (PMAC_FTR_1394_ENABLE, of_node, 0, 1); } -#endif +#endif /* CONFIG_PPC_PMAC */ pci_enable_device(pdev); @@ -3557,8 +3557,8 @@ static int ohci1394_pci_resume (struct pci_dev *pdev) static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state) { -#ifdef CONFIG_PMAC_PBOOK - { +#ifdef CONFIG_PPC_PMAC + if (_machine == _MACH_Pmac) { struct device_node *of_node; /* Disable 1394 */ diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index b0ace5bc950c..91691a6c004e 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -86,33 +86,18 @@ config PMAC_SMU on the "SMU" system control chip which replaces the old PMU. If you don't know, say Y. -config PMAC_PBOOK - bool "Power management support for PowerBooks" - depends on ADB_PMU - ---help--- - This provides support for putting a PowerBook to sleep; it also - enables media bay support. Power management works on the - PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3 and - the Titanium Powerbook G4, as well as the iBooks. You should get - the power management daemon, pmud, to make it work and you must have - the /dev/pmu device (see the pmud README). - - Get pmud from . - - If you have a PowerBook, you should say Y here. - - You may also want to compile the dma sound driver as a module and - have it autoloaded. The act of removing the module shuts down the - sound hardware for more power savings. - -config PM - bool - depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK - default y - config PMAC_APM_EMU tristate "APM emulation" - depends on PMAC_PBOOK + depends on PPC_PMAC && PPC32 && PM + +config PMAC_MEDIABAY + bool "Support PowerBook hotswap media bay" + depends on PPC_PMAC && PPC32 + help + This option adds support for older PowerBook's hotswap media bay + that can contains batteries, floppy drives, or IDE devices. PCI + devices are not fully supported in the bay as I never had one to + try with # made a separate option since backlight may end up beeing used # on non-powerbook machines (but only on PMU based ones AFAIK) diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index b3f88a4fcef7..f5ae171dbfef 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_PPC_PMAC) += macio_asic.o -obj-$(CONFIG_PMAC_PBOOK) += mediabay.o +obj-$(CONFIG_PMAC_MEDIABAY) += mediabay.o obj-$(CONFIG_MAC_EMUMOUSEBTN) += mac_hid.o obj-$(CONFIG_INPUT_ADBHID) += adbhid.o obj-$(CONFIG_ANSLCD) += ans-lcd.o diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 493e2afa191c..c0dc1e3fa58b 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -90,7 +90,7 @@ static int sleepy_trackpad; static int autopoll_devs; int __adb_probe_sync; -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when); static struct pmu_sleep_notifier adb_sleep_notifier = { adb_notify_sleep, @@ -320,9 +320,9 @@ int __init adb_init(void) printk(KERN_WARNING "Warning: no ADB interface detected\n"); adb_controller = NULL; } else { -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM pmu_register_sleep_notifier(&adb_sleep_notifier); -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PM */ #ifdef CONFIG_PPC if (machine_is_compatible("AAPL,PowerBook1998") || machine_is_compatible("PowerBook1,1")) @@ -337,7 +337,7 @@ int __init adb_init(void) __initcall(adb_init); -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM /* * notify clients before sleep and reset bus afterwards */ @@ -378,7 +378,7 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when) } return PBOOK_SLEEP_OK; } -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PM */ static int do_adb_reset_bus(void) diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 5375df03c6f3..4a0a0ad2d03c 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -155,10 +155,10 @@ static spinlock_t pmu_lock; static u8 pmu_intr_mask; static int pmu_version; static int drop_interrupts; -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM static int option_lid_wakeup = 1; static int sleep_in_progress; -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PM */ static unsigned long async_req_locks; static unsigned int pmu_irq_stats[11]; @@ -168,7 +168,6 @@ static struct proc_dir_entry *proc_pmu_irqstats; static struct proc_dir_entry *proc_pmu_options; static int option_server_mode; -#ifdef CONFIG_PMAC_PBOOK int pmu_battery_count; int pmu_cur_battery; unsigned int pmu_power_flags; @@ -176,7 +175,6 @@ struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES]; static int query_batt_timer = BATTERY_POLLING_COUNT; static struct adb_request batt_req; static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES]; -#endif /* CONFIG_PMAC_PBOOK */ #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) extern int disable_kernel_backlight; @@ -210,11 +208,9 @@ static int proc_get_irqstats(char *page, char **start, off_t off, static int pmu_set_backlight_level(int level, void* data); static int pmu_set_backlight_enable(int on, int level, void* data); #endif /* CONFIG_PMAC_BACKLIGHT */ -#ifdef CONFIG_PMAC_PBOOK static void pmu_pass_intr(unsigned char *data, int len); static int proc_get_batt(char *page, char **start, off_t off, int count, int *eof, void *data); -#endif /* CONFIG_PMAC_PBOOK */ static int proc_read_options(char *page, char **start, off_t off, int count, int *eof, void *data); static int proc_write_options(struct file *file, const char __user *buffer, @@ -407,9 +403,7 @@ static int __init via_pmu_start(void) bright_req_1.complete = 1; bright_req_2.complete = 1; -#ifdef CONFIG_PMAC_PBOOK batt_req.complete = 1; -#endif #ifdef CONFIG_PPC32 if (pmu_kind == PMU_KEYLARGO_BASED) @@ -468,7 +462,7 @@ static int __init via_pmu_dev_init(void) register_backlight_controller(&pmu_backlight_controller, NULL, "pmu"); #endif /* CONFIG_PMAC_BACKLIGHT */ -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PPC32 if (machine_is_compatible("AAPL,3400/2400") || machine_is_compatible("AAPL,3500")) { int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO, @@ -496,20 +490,19 @@ static int __init via_pmu_dev_init(void) pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART; } } -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PPC32 */ + /* Create /proc/pmu */ proc_pmu_root = proc_mkdir("pmu", NULL); if (proc_pmu_root) { -#ifdef CONFIG_PMAC_PBOOK - int i; + long i; for (i=0; i= 0) p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup); -#endif /* CONFIG_PMAC_PBOOK */ +#endif if (pmu_kind == PMU_KEYLARGO_BASED) p += sprintf(p, "server_mode=%d\n", option_server_mode); @@ -932,12 +917,12 @@ proc_write_options(struct file *file, const char __user *buffer, *(val++) = 0; while(*val == ' ') val++; -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM if (pmu_kind == PMU_KEYLARGO_BASED && pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) if (!strcmp(label, "lid_wakeup")) option_lid_wakeup = ((*val) == '1'); -#endif /* CONFIG_PMAC_PBOOK */ +#endif if (pmu_kind == PMU_KEYLARGO_BASED && !strcmp(label, "server_mode")) { int new_value; new_value = ((*val) == '1'); @@ -1432,7 +1417,6 @@ next: } /* Tick interrupt */ else if ((1 << pirq) & PMU_INT_TICK) { -#ifdef CONFIG_PMAC_PBOOK /* Environement or tick interrupt, query batteries */ if (pmu_battery_count) { if ((--query_batt_timer) == 0) { @@ -1447,7 +1431,6 @@ next: pmu_pass_intr(data, len); } else { pmu_pass_intr(data, len); -#endif /* CONFIG_PMAC_PBOOK */ } goto next; } @@ -2062,7 +2045,7 @@ pmu_i2c_simple_write(int bus, int addr, u8* data, int len) return -1; } -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM static LIST_HEAD(sleep_notifiers); @@ -2715,6 +2698,8 @@ powerbook_sleep_3400(void) return 0; } +#endif /* CONFIG_PM */ + /* * Support for /dev/pmu device */ @@ -2894,11 +2879,11 @@ static int __pmac pmu_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) { - struct pmu_private *pp = filp->private_data; __u32 __user *argp = (__u32 __user *)arg; - int error; + int error = -EINVAL; switch (cmd) { +#ifdef CONFIG_PM case PMU_IOC_SLEEP: if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -2920,12 +2905,13 @@ pmu_ioctl(struct inode * inode, struct file *filp, error = -ENOSYS; } sleep_in_progress = 0; - return error; + break; case PMU_IOC_CAN_SLEEP: if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) return put_user(0, argp); else return put_user(1, argp); +#endif /* CONFIG_PM */ #ifdef CONFIG_PMAC_BACKLIGHT /* Backlight should have its own device or go via @@ -2946,11 +2932,13 @@ pmu_ioctl(struct inode * inode, struct file *filp, error = get_user(value, argp); if (!error) error = set_backlight_level(value); - return error; + break; } #ifdef CONFIG_INPUT_ADBHID case PMU_IOC_GRAB_BACKLIGHT: { + struct pmu_private *pp = filp->private_data; unsigned long flags; + if (pp->backlight_locker) return 0; pp->backlight_locker = 1; @@ -2966,7 +2954,7 @@ pmu_ioctl(struct inode * inode, struct file *filp, case PMU_IOC_HAS_ADB: return put_user(pmu_has_adb, argp); } - return -EINVAL; + return error; } static struct file_operations pmu_device_fops __pmacdata = { @@ -2982,14 +2970,16 @@ static struct miscdevice pmu_device __pmacdata = { PMU_MINOR, "pmu", &pmu_device_fops }; -void pmu_device_init(void) +static int pmu_device_init(void) { if (!via) - return; + return 0; if (misc_register(&pmu_device) < 0) printk(KERN_ERR "via-pmu: cannot register misc device.\n"); + return 0; } -#endif /* CONFIG_PMAC_PBOOK */ +device_initcall(pmu_device_init); + #ifdef DEBUG_SLEEP static inline void __pmac @@ -3157,12 +3147,12 @@ EXPORT_SYMBOL(pmu_i2c_combined_read); EXPORT_SYMBOL(pmu_i2c_stdsub_write); EXPORT_SYMBOL(pmu_i2c_simple_read); EXPORT_SYMBOL(pmu_i2c_simple_write); -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM EXPORT_SYMBOL(pmu_register_sleep_notifier); EXPORT_SYMBOL(pmu_unregister_sleep_notifier); EXPORT_SYMBOL(pmu_enable_irled); EXPORT_SYMBOL(pmu_battery_count); EXPORT_SYMBOL(pmu_batteries); EXPORT_SYMBOL(pmu_power_flags); -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PM */ diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 57fd07d00549..eede6be098d2 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -14,14 +14,11 @@ * This file is licenced under the GPL. */ -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PPC_PMAC #include #include #include #include -#ifndef CONFIG_PM -# define CONFIG_PM -#endif #endif #ifndef CONFIG_PCI @@ -132,7 +129,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) /* let things settle down a bit */ msleep (100); -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PPC_PMAC if (_machine == _MACH_Pmac) { struct device_node *of_node; @@ -141,7 +138,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) if (of_node) pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); } -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PPC_PMAC */ return 0; } @@ -151,7 +148,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd) struct ohci_hcd *ohci = hcd_to_ohci (hcd); int retval = 0; -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PPC_PMAC if (_machine == _MACH_Pmac) { struct device_node *of_node; @@ -160,7 +157,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd) if (of_node) pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1); } -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PPC_PMAC */ /* resume root hub */ if (time_before (jiffies, ohci->next_statechange)) diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 9789115980a5..7bc1d44d8814 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -350,10 +350,8 @@ static int default_vmode __initdata = VMODE_1024_768_60; static int default_cmode __initdata = CMODE_8; #endif -#ifdef CONFIG_PMAC_PBOOK static int default_crt_on __initdata = 0; static int default_lcd_on __initdata = 1; -#endif #ifdef CONFIG_MTRR static int mtrr = 1; @@ -1249,7 +1247,6 @@ static int aty128_crtc_to_var(const struct aty128_crtc *crtc, return 0; } -#ifdef CONFIG_PMAC_PBOOK static void aty128_set_crt_enable(struct aty128fb_par *par, int on) { if (on) { @@ -1284,7 +1281,6 @@ static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) aty_st_le32(LVDS_GEN_CNTL, reg); } } -#endif /* CONFIG_PMAC_PBOOK */ static void aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par) { @@ -1491,12 +1487,10 @@ static int aty128fb_set_par(struct fb_info *info) info->fix.visual = par->crtc.bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; -#ifdef CONFIG_PMAC_PBOOK if (par->chip_gen == rage_M3) { aty128_set_crt_enable(par, par->crt_on); aty128_set_lcd_enable(par, par->lcd_on); } -#endif if (par->accel_flags & FB_ACCELF_TEXT) aty128_init_engine(par); @@ -1652,7 +1646,6 @@ static int __init aty128fb_setup(char *options) return 0; while ((this_opt = strsep(&options, ",")) != NULL) { -#ifdef CONFIG_PMAC_PBOOK if (!strncmp(this_opt, "lcd:", 4)) { default_lcd_on = simple_strtoul(this_opt+4, NULL, 0); continue; @@ -1660,7 +1653,6 @@ static int __init aty128fb_setup(char *options) default_crt_on = simple_strtoul(this_opt+4, NULL, 0); continue; } -#endif #ifdef CONFIG_MTRR if(!strncmp(this_opt, "nomtrr", 6)) { mtrr = 0; @@ -1752,10 +1744,8 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id * info->fbops = &aty128fb_ops; info->flags = FBINFO_FLAG_DEFAULT; -#ifdef CONFIG_PMAC_PBOOK par->lcd_on = default_lcd_on; par->crt_on = default_crt_on; -#endif var = default_var; #ifdef CONFIG_PPC_PMAC @@ -2035,12 +2025,10 @@ static int aty128fb_blank(int blank, struct fb_info *fb) aty_st_8(CRTC_EXT_CNTL+1, state); -#ifdef CONFIG_PMAC_PBOOK if (par->chip_gen == rage_M3) { aty128_set_crt_enable(par, par->crt_on && !blank); aty128_set_lcd_enable(par, par->lcd_on && !blank); } -#endif #ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && !blank) set_backlight_enable(1); @@ -2124,7 +2112,6 @@ static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, struct fb_info *info) { -#ifdef CONFIG_PMAC_PBOOK struct aty128fb_par *par = info->par; u32 value; int rc; @@ -2149,7 +2136,6 @@ static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd, value = (par->crt_on << 1) | par->lcd_on; return put_user(value, (__u32 __user *)arg); } -#endif return -EINVAL; } diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index 95e72550d43f..e75a965ec760 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -28,22 +28,17 @@ #include #include #include +#include #include #ifdef CONFIG_PMAC_BACKLIGHT #include #endif -#ifdef CONFIG_PMAC_PBOOK -#include -#include -#endif /* * Since we access the display with inb/outb to fixed port numbers, * we can only handle one 6555x chip. -- paulus */ -static struct fb_info chipsfb_info; - #define write_ind(num, val, ap, dp) do { \ outb((num), (ap)); outb((val), (dp)); \ } while (0) @@ -74,14 +69,6 @@ static struct fb_info chipsfb_info; inb(0x3da); read_ind(num, var, 0x3c0, 0x3c1); \ } while (0) -#ifdef CONFIG_PMAC_PBOOK -static unsigned char *save_framebuffer; -int chips_sleep_notify(struct pmu_sleep_notifier *self, int when); -static struct pmu_sleep_notifier chips_sleep_notifier = { - chips_sleep_notify, SLEEP_LEVEL_VIDEO, -}; -#endif - /* * Exported functions */ @@ -356,6 +343,8 @@ static struct fb_var_screeninfo chipsfb_var __initdata = { static void __init init_chips(struct fb_info *p, unsigned long addr) { + memset(p->screen_base, 0, 0x100000); + p->fix = chipsfb_fix; p->fix.smem_start = addr; @@ -366,34 +355,41 @@ static void __init init_chips(struct fb_info *p, unsigned long addr) fb_alloc_cmap(&p->cmap, 256, 0); - if (register_framebuffer(p) < 0) { - printk(KERN_ERR "C&T 65550 framebuffer failed to register\n"); - return; - } - - printk(KERN_INFO "fb%d: Chips 65550 frame buffer (%dK RAM detected)\n", - p->node, p->fix.smem_len / 1024); - chips_hw_init(); } static int __devinit chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) { - struct fb_info *p = &chipsfb_info; + struct fb_info *p; unsigned long addr, size; unsigned short cmd; + int rc = -ENODEV; + + if (pci_enable_device(dp) < 0) { + dev_err(&dp->dev, "Cannot enable PCI device\n"); + goto err_out; + } if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) - return -ENODEV; + goto err_disable; addr = pci_resource_start(dp, 0); size = pci_resource_len(dp, 0); if (addr == 0) - return -ENODEV; - if (p->screen_base != 0) - return -EBUSY; - if (!request_mem_region(addr, size, "chipsfb")) - return -EBUSY; + goto err_disable; + + p = framebuffer_alloc(0, &dp->dev); + if (p == NULL) { + dev_err(&dp->dev, "Cannot allocate framebuffer structure\n"); + rc = -ENOMEM; + goto err_disable; + } + + if (pci_request_region(dp, 0, "chipsfb") != 0) { + dev_err(&dp->dev, "Cannot request framebuffer\n"); + rc = -EBUSY; + goto err_release_fb; + } #ifdef __BIG_ENDIAN addr += 0x800000; // Use big-endian aperture @@ -411,37 +407,89 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) set_backlight_enable(1); #endif /* CONFIG_PMAC_BACKLIGHT */ +#ifdef CONFIG_PPC p->screen_base = __ioremap(addr, 0x200000, _PAGE_NO_CACHE); +#else + p->screen_base = ioremap(addr, 0x200000); +#endif if (p->screen_base == NULL) { - release_mem_region(addr, size); - return -ENOMEM; + dev_err(&dp->dev, "Cannot map framebuffer\n"); + rc = -ENOMEM; + goto err_release_pci; } + + pci_set_drvdata(dp, p); p->device = &dp->dev; + init_chips(p, addr); -#ifdef CONFIG_PMAC_PBOOK - pmu_register_sleep_notifier(&chips_sleep_notifier); -#endif /* CONFIG_PMAC_PBOOK */ + if (register_framebuffer(p) < 0) { + dev_err(&dp->dev,"C&T 65550 framebuffer failed to register\n"); + goto err_unmap; + } + + dev_info(&dp->dev,"fb%d: Chips 65550 frame buffer" + " (%dK RAM detected)\n", + p->node, p->fix.smem_len / 1024); - pci_set_drvdata(dp, p); return 0; + + err_unmap: + iounmap(p->screen_base); + err_release_pci: + pci_release_region(dp, 0); + err_release_fb: + framebuffer_release(p); + err_disable: + err_out: + return rc; } static void __devexit chipsfb_remove(struct pci_dev *dp) { struct fb_info *p = pci_get_drvdata(dp); - if (p != &chipsfb_info || p->screen_base == NULL) + if (p->screen_base == NULL) return; unregister_framebuffer(p); iounmap(p->screen_base); p->screen_base = NULL; - release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0)); + pci_release_region(dp, 0); +} + +#ifdef CONFIG_PM +static int chipsfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct fb_info *p = pci_get_drvdata(pdev); + + if (state == pdev->dev.power.power_state) + return 0; + if (state != PM_SUSPEND_MEM) + goto done; + + acquire_console_sem(); + chipsfb_blank(1, p); + fb_set_suspend(p, 1); + release_console_sem(); + done: + pdev->dev.power.power_state = state; + return 0; +} + +static int chipsfb_pci_resume(struct pci_dev *pdev) +{ + struct fb_info *p = pci_get_drvdata(pdev); -#ifdef CONFIG_PMAC_PBOOK - pmu_unregister_sleep_notifier(&chips_sleep_notifier); -#endif /* CONFIG_PMAC_PBOOK */ + acquire_console_sem(); + fb_set_suspend(p, 0); + chipsfb_blank(0, p); + release_console_sem(); + + pdev->dev.power.power_state = PMSG_ON; + return 0; } +#endif /* CONFIG_PM */ + static struct pci_device_id chipsfb_pci_tbl[] = { { PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_65550, PCI_ANY_ID, PCI_ANY_ID }, @@ -455,6 +503,10 @@ static struct pci_driver chipsfb_driver = { .id_table = chipsfb_pci_tbl, .probe = chipsfb_pci_init, .remove = __devexit_p(chipsfb_remove), +#ifdef CONFIG_PM + .suspend = chipsfb_pci_suspend, + .resume = chipsfb_pci_resume, +#endif }; int __init chips_init(void) @@ -472,48 +524,4 @@ static void __exit chipsfb_exit(void) pci_unregister_driver(&chipsfb_driver); } -#ifdef CONFIG_PMAC_PBOOK -/* - * Save the contents of the frame buffer when we go to sleep, - * and restore it when we wake up again. - */ -int -chips_sleep_notify(struct pmu_sleep_notifier *self, int when) -{ - struct fb_info *p = &chipsfb_info; - int nb = p->var.yres * p->fix.line_length; - - if (p->screen_base == NULL) - return PBOOK_SLEEP_OK; - - switch (when) { - case PBOOK_SLEEP_REQUEST: - save_framebuffer = vmalloc(nb); - if (save_framebuffer == NULL) - return PBOOK_SLEEP_REFUSE; - break; - case PBOOK_SLEEP_REJECT: - if (save_framebuffer) { - vfree(save_framebuffer); - save_framebuffer = NULL; - } - break; - case PBOOK_SLEEP_NOW: - chipsfb_blank(1, p); - if (save_framebuffer) - memcpy(save_framebuffer, p->screen_base, nb); - break; - case PBOOK_WAKE: - if (save_framebuffer) { - memcpy(p->screen_base, save_framebuffer, nb); - vfree(save_framebuffer); - save_framebuffer = NULL; - } - chipsfb_blank(0, p); - break; - } - return PBOOK_SLEEP_OK; -} -#endif /* CONFIG_PMAC_PBOOK */ - MODULE_LICENSE("GPL"); diff --git a/include/linux/pmu.h b/include/linux/pmu.h index 6d73eada277e..373bd3b9b330 100644 --- a/include/linux/pmu.h +++ b/include/linux/pmu.h @@ -166,7 +166,7 @@ extern int pmu_i2c_simple_read(int bus, int addr, u8* data, int len); extern int pmu_i2c_simple_write(int bus, int addr, u8* data, int len); -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM /* * Stuff for putting the powerbook to sleep and waking it again. * @@ -208,6 +208,8 @@ struct pmu_sleep_notifier int pmu_register_sleep_notifier(struct pmu_sleep_notifier* notifier); int pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* notifier); +#endif /* CONFIG_PM */ + #define PMU_MAX_BATTERIES 2 /* values for pmu_power_flags */ @@ -235,6 +237,4 @@ extern int pmu_battery_count; extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES]; extern unsigned int pmu_power_flags; -#endif /* CONFIG_PMAC_PBOOK */ - #endif /* __KERNEL__ */ diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c index 33108661e671..2704e1598add 100644 --- a/sound/oss/dmasound/dmasound_awacs.c +++ b/sound/oss/dmasound/dmasound_awacs.c @@ -255,7 +255,7 @@ static int awacs_burgundy_read_mvolume(unsigned address); static volatile struct dbdma_cmd *emergency_dbdma_cmd; -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM /* * Stuff for restoring after a sleep. */ @@ -263,7 +263,7 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when); struct pmu_sleep_notifier awacs_sleep_notifier = { awacs_sleep_notify, SLEEP_LEVEL_SOUND, }; -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PM */ /* for (soft) sample rate translations */ int expand_bal; /* Balance factor for expanding (not volume!) */ @@ -675,7 +675,7 @@ static void PMacIrqCleanup(void) kfree(awacs_rx_cmd_space); kfree(beep_dbdma_cmd_space); kfree(beep_buf); -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM pmu_unregister_sleep_notifier(&awacs_sleep_notifier); #endif } @@ -1415,7 +1415,7 @@ load_awacs(void) } } -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM /* * Save state when going to sleep, restore it afterwards. */ @@ -1551,7 +1551,7 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when) } return PBOOK_SLEEP_OK; } -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PM */ /* All the burgundy functions: */ @@ -3053,9 +3053,9 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev); if ((res=setup_beep())) return res ; -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM pmu_register_sleep_notifier(&awacs_sleep_notifier); -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PM */ /* Powerbooks have odd ways of enabling inputs such as an expansion-bay CD or sound from an internal modem diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index e052bd071e5b..061e52d3d771 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -90,7 +90,7 @@ snd_pmac_awacs_write_noreg(pmac_t *chip, int reg, int val) snd_pmac_awacs_write(chip, val | (reg << 12)); } -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM /* Recalibrate chip */ static void screamer_recalibrate(pmac_t *chip) { @@ -642,7 +642,7 @@ static void awacs_restore_all_regs(pmac_t *chip) } } -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM static void snd_pmac_awacs_suspend(pmac_t *chip) { snd_pmac_awacs_write_noreg(chip, 1, (chip->awacs_reg[1] @@ -676,7 +676,7 @@ static void snd_pmac_awacs_resume(pmac_t *chip) } #endif } -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PM */ #ifdef PMAC_SUPPORT_AUTOMUTE /* @@ -883,7 +883,7 @@ snd_pmac_awacs_init(pmac_t *chip) * set lowlevel callbacks */ chip->set_format = snd_pmac_awacs_set_format; -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM chip->suspend = snd_pmac_awacs_suspend; chip->resume = snd_pmac_awacs_resume; #endif diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c index f24a91693616..a737f298e77d 100644 --- a/sound/ppc/daca.c +++ b/sound/ppc/daca.c @@ -218,7 +218,7 @@ static snd_kcontrol_new_t daca_mixers[] = { }; -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM static void daca_resume(pmac_t *chip) { pmac_daca_t *mix = chip->mixer_data; @@ -227,7 +227,7 @@ static void daca_resume(pmac_t *chip) mix->amp_on ? 0x05 : 0x04); daca_set_volume(mix); } -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PM */ static void daca_cleanup(pmac_t *chip) @@ -275,7 +275,7 @@ int __init snd_pmac_daca_init(pmac_t *chip) return err; } -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM chip->resume = daca_resume; #endif diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 080ef3928465..75b8b7423036 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -36,7 +36,7 @@ #include -#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK) +#ifdef CONFIG_PM static int snd_pmac_register_sleep_notifier(pmac_t *chip); static int snd_pmac_unregister_sleep_notifier(pmac_t *chip); static int snd_pmac_suspend(snd_card_t *card, pm_message_t state); @@ -782,7 +782,7 @@ static int snd_pmac_free(pmac_t *chip) } snd_pmac_sound_feature(chip, 0); -#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK) +#ifdef CONFIG_PM snd_pmac_unregister_sleep_notifier(chip); #endif @@ -1292,7 +1292,7 @@ int __init snd_pmac_new(snd_card_t *card, pmac_t **chip_return) /* Reset dbdma channels */ snd_pmac_dbdma_reset(chip); -#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK) +#ifdef CONFIG_PM /* add sleep notifier */ if (! snd_pmac_register_sleep_notifier(chip)) snd_card_set_pm_callback(chip->card, snd_pmac_suspend, snd_pmac_resume, chip); @@ -1316,7 +1316,7 @@ int __init snd_pmac_new(snd_card_t *card, pmac_t **chip_return) * sleep notify for powerbook */ -#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK) +#ifdef CONFIG_PM /* * Save state when going to sleep, restore it afterwards. @@ -1414,4 +1414,5 @@ static int snd_pmac_unregister_sleep_notifier(pmac_t *chip) return 0; } -#endif /* CONFIG_PM && CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PM */ + diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h index 0a84c05f714b..582db5220119 100644 --- a/sound/ppc/pmac.h +++ b/sound/ppc/pmac.h @@ -167,7 +167,7 @@ struct snd_pmac { void (*set_format)(pmac_t *chip); void (*update_automute)(pmac_t *chip, int do_notify); int (*detect_headphone)(pmac_t *chip); -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM void (*suspend)(pmac_t *chip); void (*resume)(pmac_t *chip); #endif diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 9332237cb6a4..36c5d5d45bb1 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -1128,7 +1128,7 @@ static void tumbler_reset_audio(pmac_t *chip) } } -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM /* suspend mixer */ static void tumbler_suspend(pmac_t *chip) { @@ -1370,7 +1370,7 @@ int __init snd_pmac_tumbler_init(pmac_t *chip) if ((err = snd_ctl_add(chip->card, chip->drc_sw_ctl)) < 0) return err; -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PM chip->suspend = tumbler_suspend; chip->resume = tumbler_resume; #endif -- cgit v1.2.3 From 22f3a8f5fc94be4dd31c4c5ec1d1dc2b9c83a8ac Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 27 Jun 2005 16:28:43 -0700 Subject: [PATCH] pcmcia id_table for sl811.cs Catch up with some PCMCIA API changes: - Docs say that as of 2.6.11 the PCMCIA IRQInfo2 field is ignored, but it's not yet removed from the API; stop using it anyway. - As of 2.6.13 PCMCIA finally hotplugs and does driver binding without "cardmgr"; add a MODULE_DEVICE_TABLE to support this. Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/host/sl811_cs.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 6e173265095c..269d8ef01459 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -68,13 +68,6 @@ static const char driver_name[DEV_NAME_LEN] = "sl811_cs"; static dev_link_t *dev_list = NULL; -static int irq_list[4] = { -1 }; -static int irq_list_count; - -module_param_array(irq_list, int, &irq_list_count, 0444); - -INT_MODULE_PARM(irq_mask, 0xdeb8); - typedef struct local_info_t { dev_link_t link; dev_node_t node; @@ -373,7 +366,7 @@ static dev_link_t *sl811_cs_attach(void) local_info_t *local; dev_link_t *link; client_reg_t client_reg; - int ret, i; + int ret; local = kmalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) @@ -385,11 +378,6 @@ static dev_link_t *sl811_cs_attach(void) /* Initialize */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; - if (irq_list[0] == -1) - link->irq.IRQInfo2 = irq_mask; - else - for (i = 0; i < irq_list_count; i++) - link->irq.IRQInfo2 |= 1 << irq_list[i]; link->irq.Handler = NULL; link->conf.Attributes = 0; @@ -418,6 +406,12 @@ static dev_link_t *sl811_cs_attach(void) return link; } +static struct pcmcia_device_id sl811_ids[] = { + PCMCIA_DEVICE_MANF_CARD(0xc015, 0x0001), /* RATOC USB HOST CF+ Card */ + PCMCIA_DEVICE_NULL, +}; +MODULE_DEVICE_TABLE(pcmcia, sl811_ids); + static struct pcmcia_driver sl811_cs_driver = { .owner = THIS_MODULE, .drv = { @@ -425,6 +419,7 @@ static struct pcmcia_driver sl811_cs_driver = { }, .attach = sl811_cs_attach, .detach = sl811_cs_detach, + .id_table = sl811_ids, }; /*====================================================================*/ -- cgit v1.2.3 From c27a748225fe5c7e485ea471178c26e43f9f7fbe Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 30 Jun 2005 00:48:51 -0500 Subject: Input: acecad - drop unneeded cast and couple unneeded spaces. Noticed by Joe Perches. Signed-off-by: Dmitry Torokhov Acked-by: Stephane VOLTZ --- drivers/usb/input/acecad.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c index ebcf7c955800..68039b04af3b 100644 --- a/drivers/usb/input/acecad.c +++ b/drivers/usb/input/acecad.c @@ -87,8 +87,8 @@ static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs) if (prox) { int x = data[1] | (data[2] << 8); int y = data[3] | (data[4] << 8); - /*Pressure should compute the same way for flair and 302*/ - int pressure = data[5] | ((int)data[6] << 8); + /* Pressure should compute the same way for flair and 302 */ + int pressure = data[5] | (data[6] << 8); int touch = data[0] & 0x01; int stylus = (data[0] & 0x10) >> 4; int stylus2 = (data[0] & 0x20) >> 5; @@ -104,9 +104,9 @@ static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs) input_sync(dev); resubmit: - status = usb_submit_urb (urb, GFP_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) - err ("can't resubmit intr, %s-%s/input0, status %d", + err("can't resubmit intr, %s-%s/input0, status %d", acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status); } -- cgit v1.2.3 From 16a334c0de5a94b1d10a1ac9a33f4dedac89a075 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 30 Jun 2005 00:49:08 -0500 Subject: Input: introduce usb_to_input_id() to uniformly produce struct input_id for USB input devices. Signed-off-by: Dmitry Torokhov --- drivers/usb/input/acecad.c | 6 ++---- drivers/usb/input/aiptek.c | 6 ++---- drivers/usb/input/ati_remote.c | 8 +++----- drivers/usb/input/hid-input.c | 6 ++---- drivers/usb/input/itmtouch.c | 6 ++---- drivers/usb/input/kbtab.c | 6 ++---- drivers/usb/input/mtouchusb.c | 6 ++---- drivers/usb/input/powermate.c | 6 ++---- drivers/usb/input/touchkitusb.c | 7 ++----- drivers/usb/input/usbkbd.c | 6 ++---- drivers/usb/input/usbmouse.c | 6 ++---- drivers/usb/input/wacom.c | 6 ++---- drivers/usb/input/xpad.c | 6 ++---- drivers/usb/media/konicawc.c | 6 ++---- include/linux/usb_input.h | 25 +++++++++++++++++++++++++ 15 files changed, 54 insertions(+), 58 deletions(-) create mode 100644 include/linux/usb_input.h (limited to 'drivers/usb') diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c index 68039b04af3b..13532f3e3efc 100644 --- a/drivers/usb/input/acecad.c +++ b/drivers/usb/input/acecad.c @@ -31,6 +31,7 @@ #include #include #include +#include /* * Version Information @@ -212,10 +213,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ acecad->dev.name = acecad->name; acecad->dev.phys = acecad->phys; - acecad->dev.id.bustype = BUS_USB; - acecad->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor); - acecad->dev.id.product = le16_to_cpu(dev->descriptor.idProduct); - acecad->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice); + usb_to_input_id(dev, &acecad->dev.id); acecad->dev.dev = &intf->dev; usb_fill_int_urb(acecad->irq, dev, pipe, diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index 6bb0f25e8e93..cd0cbfe20723 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -2125,10 +2126,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) aiptek->inputdev.absflat[ABS_WHEEL] = 0; aiptek->inputdev.name = "Aiptek"; aiptek->inputdev.phys = aiptek->features.usbPath; - aiptek->inputdev.id.bustype = BUS_USB; - aiptek->inputdev.id.vendor = le16_to_cpu(usbdev->descriptor.idVendor); - aiptek->inputdev.id.product = le16_to_cpu(usbdev->descriptor.idProduct); - aiptek->inputdev.id.version = le16_to_cpu(usbdev->descriptor.bcdDevice); + usb_to_input_id(usbdev, &aiptek->inputdev.id); aiptek->inputdev.dev = &intf->dev; aiptek->usbdev = usbdev; diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index 654ac454744d..fd99681ee483 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -94,6 +94,7 @@ #include #include #include +#include #include /* @@ -635,11 +636,8 @@ static void ati_remote_input_init(struct ati_remote *ati_remote) idev->name = ati_remote->name; idev->phys = ati_remote->phys; - idev->id.bustype = BUS_USB; - idev->id.vendor = le16_to_cpu(ati_remote->udev->descriptor.idVendor); - idev->id.product = le16_to_cpu(ati_remote->udev->descriptor.idProduct); - idev->id.version = le16_to_cpu(ati_remote->udev->descriptor.bcdDevice); - idev->dev = &(ati_remote->udev->dev); + usb_to_input_id(ati_remote->udev, &idev->id); + idev->dev = &ati_remote->udev->dev; } static int ati_remote_initialize(struct ati_remote *ati_remote) diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 9ac1e9095334..e071c8eeccee 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -31,6 +31,7 @@ #include #include #include +#include #undef DEBUG @@ -581,10 +582,7 @@ int hidinput_connect(struct hid_device *hid) hidinput->input.name = hid->name; hidinput->input.phys = hid->phys; hidinput->input.uniq = hid->uniq; - hidinput->input.id.bustype = BUS_USB; - hidinput->input.id.vendor = le16_to_cpu(dev->descriptor.idVendor); - hidinput->input.id.product = le16_to_cpu(dev->descriptor.idProduct); - hidinput->input.id.version = le16_to_cpu(dev->descriptor.bcdDevice); + usb_to_input_id(dev, &hidinput->input.id); hidinput->input.dev = &hid->intf->dev; } diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c index 47dec6a1b344..0dc439f10823 100644 --- a/drivers/usb/input/itmtouch.c +++ b/drivers/usb/input/itmtouch.c @@ -53,6 +53,7 @@ #include #include #include +#include /* only an 8 byte buffer necessary for a single packet */ #define ITM_BUFSIZE 8 @@ -184,10 +185,7 @@ static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id itmtouch->inputdev.name = itmtouch->name; itmtouch->inputdev.phys = itmtouch->phys; - itmtouch->inputdev.id.bustype = BUS_USB; - itmtouch->inputdev.id.vendor = udev->descriptor.idVendor; - itmtouch->inputdev.id.product = udev->descriptor.idProduct; - itmtouch->inputdev.id.version = udev->descriptor.bcdDevice; + usb_to_input_id(udev, &itmtouch->inputdev.id); itmtouch->inputdev.dev = &intf->dev; if (!strlen(itmtouch->name)) diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index d2f0f90a9bcd..b6f6ac8d9c2f 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -167,10 +168,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i kbtab->dev.name = "KB Gear Tablet"; kbtab->dev.phys = kbtab->phys; - kbtab->dev.id.bustype = BUS_USB; - kbtab->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor); - kbtab->dev.id.product = le16_to_cpu(dev->descriptor.idProduct); - kbtab->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice); + usb_to_input_id(dev, &kbtab->dev.id); kbtab->dev.dev = &intf->dev; kbtab->usbdev = dev; diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index 09b5cc7c66de..ff9275057a18 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c @@ -53,6 +53,7 @@ #include #include #include +#include #define MTOUCHUSB_MIN_XC 0x0 #define MTOUCHUSB_MAX_RAW_XC 0x4000 @@ -232,10 +233,7 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i mtouch->input.name = mtouch->name; mtouch->input.phys = mtouch->phys; - mtouch->input.id.bustype = BUS_USB; - mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor); - mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct); - mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice); + usb_to_input_id(udev, &mtouch->input.id); mtouch->input.dev = &intf->dev; mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c index 3975b309d55f..ad4afe7e5897 100644 --- a/drivers/usb/input/powermate.c +++ b/drivers/usb/input/powermate.c @@ -35,6 +35,7 @@ #include #include #include +#include #define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */ #define POWERMATE_PRODUCT_NEW 0x0410 /* Griffin PowerMate */ @@ -389,10 +390,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i pm->input.keybit[LONG(BTN_0)] = BIT(BTN_0); pm->input.relbit[LONG(REL_DIAL)] = BIT(REL_DIAL); pm->input.mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED); - pm->input.id.bustype = BUS_USB; - pm->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor); - pm->input.id.product = le16_to_cpu(udev->descriptor.idProduct); - pm->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice); + usb_to_input_id(udev, &pm->input.id); pm->input.event = powermate_input_event; pm->input.dev = &intf->dev; pm->input.phys = pm->phys; diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c index 386595ee21c0..4276c24a5080 100644 --- a/drivers/usb/input/touchkitusb.c +++ b/drivers/usb/input/touchkitusb.c @@ -35,7 +35,7 @@ #define DEBUG #endif #include - +#include #define TOUCHKIT_MIN_XC 0x0 #define TOUCHKIT_MAX_XC 0x07ff @@ -202,10 +202,7 @@ static int touchkit_probe(struct usb_interface *intf, touchkit->input.name = touchkit->name; touchkit->input.phys = touchkit->phys; - touchkit->input.id.bustype = BUS_USB; - touchkit->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor); - touchkit->input.id.product = le16_to_cpu(udev->descriptor.idProduct); - touchkit->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice); + usb_to_input_id(udev, &touchkit->input.id); touchkit->input.dev = &intf->dev; touchkit->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index f35db1974c42..28987f15eeee 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -32,6 +32,7 @@ #include #include #include +#include /* * Version Information @@ -288,10 +289,7 @@ static int usb_kbd_probe(struct usb_interface *iface, kbd->dev.name = kbd->name; kbd->dev.phys = kbd->phys; - kbd->dev.id.bustype = BUS_USB; - kbd->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor); - kbd->dev.id.product = le16_to_cpu(dev->descriptor.idProduct); - kbd->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice); + usb_to_input_id(dev, &kbd->dev.id); kbd->dev.dev = &iface->dev; if (dev->manufacturer) diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index 1ec41b5effe6..4104dec847fb 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c @@ -32,6 +32,7 @@ #include #include #include +#include /* * Version Information @@ -171,10 +172,7 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_ mouse->dev.name = mouse->name; mouse->dev.phys = mouse->phys; - mouse->dev.id.bustype = BUS_USB; - mouse->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor); - mouse->dev.id.product = le16_to_cpu(dev->descriptor.idProduct); - mouse->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice); + usb_to_input_id(dev, &mouse->dev.id); mouse->dev.dev = &intf->dev; if (dev->manufacturer) diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index f6b34af66b3d..02412e31a46b 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #include @@ -823,10 +824,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i wacom->dev.name = wacom->features->name; wacom->dev.phys = wacom->phys; - wacom->dev.id.bustype = BUS_USB; - wacom->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor); - wacom->dev.id.product = le16_to_cpu(dev->descriptor.idProduct); - wacom->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice); + usb_to_input_id(dev, &wacom->dev.id); wacom->dev.dev = &intf->dev; wacom->usbdev = dev; diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index a7fa1b17dcfe..18125e0bffa2 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c @@ -62,6 +62,7 @@ #include #include #include +#include #define DRIVER_VERSION "v0.0.5" #define DRIVER_AUTHOR "Marko Friedemann " @@ -256,10 +257,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->udev = udev; - xpad->dev.id.bustype = BUS_USB; - xpad->dev.id.vendor = le16_to_cpu(udev->descriptor.idVendor); - xpad->dev.id.product = le16_to_cpu(udev->descriptor.idProduct); - xpad->dev.id.version = le16_to_cpu(udev->descriptor.bcdDevice); + usb_to_input_id(udev, &xpad->dev.id); xpad->dev.dev = &intf->dev; xpad->dev.private = xpad; xpad->dev.name = xpad_device[i].name; diff --git a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c index 08521a2b4f3d..20ac9e1069d4 100644 --- a/drivers/usb/media/konicawc.c +++ b/drivers/usb/media/konicawc.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "usbvideo.h" @@ -845,10 +846,7 @@ static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id cam->input.private = cam; cam->input.evbit[0] = BIT(EV_KEY); cam->input.keybit[LONG(BTN_0)] = BIT(BTN_0); - cam->input.id.bustype = BUS_USB; - cam->input.id.vendor = le16_to_cpu(dev->descriptor.idVendor); - cam->input.id.product = le16_to_cpu(dev->descriptor.idProduct); - cam->input.id.version = le16_to_cpu(dev->descriptor.bcdDevice); + usb_to_input_id(dev, &cam->input.id); input_register_device(&cam->input); usb_make_path(dev, cam->input_physname, 56); diff --git a/include/linux/usb_input.h b/include/linux/usb_input.h new file mode 100644 index 000000000000..716e0cc16043 --- /dev/null +++ b/include/linux/usb_input.h @@ -0,0 +1,25 @@ +#ifndef __USB_INPUT_H +#define __USB_INPUT_H + +/* + * Copyright (C) 2005 Dmitry Torokhov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include + +static inline void +usb_to_input_id(const struct usb_device *dev, struct input_id *id) +{ + id->bustype = BUS_USB; + id->vendor = le16_to_cpu(dev->descriptor.idVendor); + id->product = le16_to_cpu(dev->descriptor.idProduct); + id->version = le16_to_cpu(dev->descriptor.bcdDevice); +} + +#endif -- cgit v1.2.3 From 1e212f3645a6b355de8c43a23376bc0e2ac49a63 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 7 Jul 2005 17:59:00 -0700 Subject: [PATCH] pcmcia: move event handler Move the "event handler" to struct pcmcia_driver -- the unified event handler will disappear really soon, but switching it to struct pcmcia_driver in the meantime allows for better "step-by-step" patches. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/bluetooth/bluecard_cs.c | 6 +----- drivers/bluetooth/bt3c_cs.c | 6 +----- drivers/bluetooth/btuart_cs.c | 6 +----- drivers/bluetooth/dtl1_cs.c | 6 +----- drivers/char/pcmcia/synclink_cs.c | 6 +----- drivers/ide/legacy/ide-cs.c | 6 +----- drivers/isdn/hardware/avm/avm_cs.c | 6 +----- drivers/isdn/hisax/avma1_cs.c | 6 +----- drivers/isdn/hisax/elsa_cs.c | 6 +----- drivers/isdn/hisax/sedlbauer_cs.c | 6 +----- drivers/isdn/hisax/teles_cs.c | 6 +----- drivers/mtd/maps/pcmciamtd.c | 6 +----- drivers/net/pcmcia/3c574_cs.c | 6 +----- drivers/net/pcmcia/3c589_cs.c | 6 +----- drivers/net/pcmcia/axnet_cs.c | 6 +----- drivers/net/pcmcia/com20020_cs.c | 6 +----- drivers/net/pcmcia/fmvj18x_cs.c | 6 +----- drivers/net/pcmcia/ibmtr_cs.c | 6 +----- drivers/net/pcmcia/nmclan_cs.c | 6 +----- drivers/net/pcmcia/pcnet_cs.c | 6 +----- drivers/net/pcmcia/smc91c92_cs.c | 5 +---- drivers/net/pcmcia/xirc2ps_cs.c | 6 +----- drivers/net/wireless/airo_cs.c | 6 +----- drivers/net/wireless/atmel_cs.c | 16 ++++++---------- drivers/net/wireless/netwave_cs.c | 6 +----- drivers/net/wireless/orinoco_cs.c | 6 +----- drivers/net/wireless/ray_cs.c | 6 +----- drivers/net/wireless/wavelan_cs.c | 7 +------ drivers/net/wireless/wl3501_cs.c | 18 ++++++------------ drivers/parport/parport_cs.c | 6 +----- drivers/pcmcia/cs_internal.h | 3 --- drivers/pcmcia/ds.c | 32 ++++++++++++++++++++------------ drivers/scsi/pcmcia/aha152x_stub.c | 6 +----- drivers/scsi/pcmcia/fdomain_stub.c | 6 +----- drivers/scsi/pcmcia/nsp_cs.c | 16 ++++++---------- drivers/scsi/pcmcia/qlogic_stub.c | 3 +-- drivers/scsi/pcmcia/sym53c500_cs.c | 5 +---- drivers/serial/serial_cs.c | 6 +----- drivers/telephony/ixj_pcmcia.c | 6 +----- drivers/usb/host/sl811_cs.c | 6 +----- include/pcmcia/ds.h | 8 ++++---- sound/pcmcia/pdaudiocf/pdaudiocf.c | 19 ++++++------------- sound/pcmcia/vx/vx_entry.c | 12 ++---------- 43 files changed, 85 insertions(+), 245 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 5ef9adb9fe73..53661246100e 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -895,11 +895,6 @@ static dev_link_t *bluecard_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &bluecard_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -1103,6 +1098,7 @@ static struct pcmcia_driver bluecard_driver = { .name = "bluecard_cs", }, .attach = bluecard_attach, + .event = bluecard_event, .detach = bluecard_detach, .id_table = bluecard_ids, }; diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 9013cd759afb..06539a542e98 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -696,11 +696,6 @@ static dev_link_t *bt3c_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &bt3c_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -947,6 +942,7 @@ static struct pcmcia_driver bt3c_driver = { .name = "bt3c_cs", }, .attach = bt3c_attach, + .event = bt3c_event, .detach = bt3c_detach, .id_table = bt3c_ids, }; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index c479484a1f7f..f15a9cf2b787 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -615,11 +615,6 @@ static dev_link_t *btuart_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &btuart_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -867,6 +862,7 @@ static struct pcmcia_driver btuart_driver = { .name = "btuart_cs", }, .attach = btuart_attach, + .event = btuart_event, .detach = btuart_detach, .id_table = btuart_ids, }; diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index bb12f7daeb91..58b09a9cc4c6 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -594,11 +594,6 @@ static dev_link_t *dtl1_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &dtl1_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -820,6 +815,7 @@ static struct pcmcia_driver dtl1_driver = { .name = "dtl1_cs", }, .attach = dtl1_attach, + .event = dtl1_event, .detach = dtl1_detach, .id_table = dtl1_ids, }; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 8f36b1758eb6..ea691561e083 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -593,11 +593,6 @@ static dev_link_t *mgslpc_attach(void) dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &mgslpc_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -3093,6 +3088,7 @@ static struct pcmcia_driver mgslpc_driver = { .name = "synclink_cs", }, .attach = mgslpc_attach, + .event = mgslpc_event, .detach = mgslpc_detach, .id_table = mgslpc_ids, }; diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 978d27d6452d..fde0d5f1b876 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -134,11 +134,6 @@ static dev_link_t *ide_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &ide_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -497,6 +492,7 @@ static struct pcmcia_driver ide_cs_driver = { .name = "ide-cs", }, .attach = ide_attach, + .event = ide_event, .detach = ide_detach, .id_table = ide_ids, }; diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index ee750e9456dd..a30c74fd75da 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -161,11 +161,6 @@ static dev_link_t *avmcs_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &avmcs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -500,6 +495,7 @@ static struct pcmcia_driver avmcs_driver = { .name = "avm_cs", }, .attach = avmcs_attach, + .event = avmcs_event, .detach = avmcs_detach, .id_table = avmcs_ids, }; diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index 67c60e04a37b..d3de0e856192 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -183,11 +183,6 @@ static dev_link_t *avma1cs_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &avma1cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -514,6 +509,7 @@ static struct pcmcia_driver avma1cs_driver = { .name = "avma1_cs", }, .attach = avma1cs_attach, + .event = avma1cs_event, .detach = avma1cs_detach, .id_table = avma1cs_ids, }; diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index 9146be547044..54f0d68ad796 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -212,11 +212,6 @@ static dev_link_t *elsa_cs_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &elsa_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -521,6 +516,7 @@ static struct pcmcia_driver elsa_cs_driver = { .name = "elsa_cs", }, .attach = elsa_cs_attach, + .event = elsa_cs_event, .detach = elsa_cs_detach, .id_table = elsa_ids, }; diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 058147a69576..baf733e86474 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -226,11 +226,6 @@ static dev_link_t *sedlbauer_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &sedlbauer_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -634,6 +629,7 @@ static struct pcmcia_driver sedlbauer_driver = { .name = "sedlbauer_cs", }, .attach = sedlbauer_attach, + .event = sedlbauer_event, .detach = sedlbauer_detach, .id_table = sedlbauer_ids, }; diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index 107376ff5b9b..b8eeb789f901 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -193,11 +193,6 @@ static dev_link_t *teles_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &teles_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -501,6 +496,7 @@ static struct pcmcia_driver teles_cs_driver = { .name = "teles_cs", }, .attach = teles_attach, + .event = teles_cs_event, .detach = teles_detach, .id_table = teles_ids, }; diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index c2655a817e3d..aa820ee4c31a 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -800,11 +800,6 @@ static dev_link_t *pcmciamtd_attach(void) /* Register with Card Services */ client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &pcmciamtd_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; DEBUG(2, "Calling RegisterClient"); @@ -850,6 +845,7 @@ static struct pcmcia_driver pcmciamtd_driver = { .name = "pcmciamtd" }, .attach = pcmciamtd_attach, + .event = pcmciamtd_event, .detach = pcmciamtd_detach, .owner = THIS_MODULE, .id_table = pcmciamtd_ids, diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index f0fc04bd37c4..c942964a49d2 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -312,11 +312,6 @@ static dev_link_t *tc574_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &tc574_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -1299,6 +1294,7 @@ static struct pcmcia_driver tc574_driver = { .name = "3c574_cs", }, .attach = tc574_attach, + .event = tc574_event, .detach = tc574_detach, .id_table = tc574_ids, }; diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 8fa1b5f0fb68..810864c6d1ea 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -226,11 +226,6 @@ static dev_link_t *tc589_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &tc589_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -1074,6 +1069,7 @@ static struct pcmcia_driver tc589_driver = { .name = "3c589_cs", }, .attach = tc589_attach, + .event = tc589_event, .detach = tc589_detach, .id_table = tc589_ids, }; diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 23ce77b1d5b0..3d01079598c8 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -181,11 +181,6 @@ static dev_link_t *axnet_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &axnet_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -884,6 +879,7 @@ static struct pcmcia_driver axnet_cs_driver = { .name = "axnet_cs", }, .attach = axnet_attach, + .event = axnet_event, .detach = axnet_detach, .id_table = axnet_ids, }; diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 68d58cc58d31..b5119607d5af 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -200,11 +200,6 @@ static dev_link_t *com20020_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &com20020_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -495,6 +490,7 @@ static struct pcmcia_driver com20020_cs_driver = { .name = "com20020_cs", }, .attach = com20020_attach, + .event = com20020_event, .detach = com20020_detach, .id_table = com20020_ids, }; diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 917adbbf0b5b..c7d9bb1da417 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -288,11 +288,6 @@ static dev_link_t *fmvj18x_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &fmvj18x_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -797,6 +792,7 @@ static struct pcmcia_driver fmvj18x_cs_driver = { .name = "fmvj18x_cs", }, .attach = fmvj18x_attach, + .event = fmvj18x_event, .detach = fmvj18x_detach, .id_table = fmvj18x_ids, }; diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index cf6d073ea558..39cec4a1e4b3 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -190,11 +190,6 @@ static dev_link_t *ibmtr_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &ibmtr_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -521,6 +516,7 @@ static struct pcmcia_driver ibmtr_cs_driver = { .name = "ibmtr_cs", }, .attach = ibmtr_attach, + .event = ibmtr_event, .detach = ibmtr_detach, .id_table = ibmtr_ids, }; diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index b86e7253fbfc..49124dc26b35 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -502,11 +502,6 @@ static dev_link_t *nmclan_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &nmclan_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -1688,6 +1683,7 @@ static struct pcmcia_driver nmclan_cs_driver = { .name = "nmclan_cs", }, .attach = nmclan_attach, + .event = nmclan_event, .detach = nmclan_detach, .id_table = nmclan_ids, }; diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 855a45d062b1..b22b354af5c0 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -276,11 +276,6 @@ static dev_link_t *pcnet_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &pcnet_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -1844,6 +1839,7 @@ static struct pcmcia_driver pcnet_driver = { .name = "pcnet_cs", }, .attach = pcnet_attach, + .event = pcnet_event, .detach = pcnet_detach, .owner = THIS_MODULE, .id_table = pcnet_ids, diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index bc01c88c6709..6b5471dfb554 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -370,10 +370,6 @@ static dev_link_t *smc91c92_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &smc91c92_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -2365,6 +2361,7 @@ static struct pcmcia_driver smc91c92_cs_driver = { .name = "smc91c92_cs", }, .attach = smc91c92_attach, + .event = smc91c92_event, .detach = smc91c92_detach, .id_table = smc91c92_ids, }; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 0cd225e1595c..03d4c0c6b3fd 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -619,11 +619,6 @@ xirc2ps_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &xirc2ps_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; if ((err = pcmcia_register_client(&link->handle, &client_reg))) { @@ -2016,6 +2011,7 @@ static struct pcmcia_driver xirc2ps_cs_driver = { .name = "xirc2ps_cs", }, .attach = xirc2ps_attach, + .event = xirc2ps_event, .detach = xirc2ps_detach, .id_table = xirc2ps_ids, }; diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index f10a9523034a..fd46393e743e 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -210,11 +210,6 @@ static dev_link_t *airo_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &airo_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -574,6 +569,7 @@ static struct pcmcia_driver airo_driver = { .name = "airo_cs", }, .attach = airo_attach, + .event = airo_event, .detach = airo_detach, .id_table = airo_ids, }; diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 86379d4998ac..863be2995036 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -218,11 +218,6 @@ static dev_link_t *atmel_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &atmel_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -668,12 +663,13 @@ static struct pcmcia_device_id atmel_ids[] = { MODULE_DEVICE_TABLE(pcmcia, atmel_ids); static struct pcmcia_driver atmel_driver = { - .owner = THIS_MODULE, - .drv = { - .name = "atmel_cs", + .owner = THIS_MODULE, + .drv = { + .name = "atmel_cs", }, - .attach = atmel_attach, - .detach = atmel_detach, + .attach = atmel_attach, + .event = atmel_event, + .detach = atmel_detach, .id_table = atmel_ids, }; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index e12bd75b2694..bdd3e7083d9e 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -491,11 +491,6 @@ static dev_link_t *netwave_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &netwave_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -1680,6 +1675,7 @@ static struct pcmcia_driver netwave_driver = { .name = "netwave_cs", }, .attach = netwave_attach, + .event = netwave_event, .detach = netwave_detach, .id_table = netwave_ids, }; diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 597c4586d049..c883404b1d59 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -186,11 +186,6 @@ orinoco_cs_attach(void) dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &orinoco_cs_event; client_reg.Version = 0x0210; /* FIXME: what does this mean? */ client_reg.event_callback_args.client_data = link; @@ -664,6 +659,7 @@ static struct pcmcia_driver orinoco_driver = { .name = DRIVER_NAME, }, .attach = orinoco_cs_attach, + .event = orinoco_cs_event, .detach = orinoco_cs_detach, .id_table = orinoco_cs_ids, }; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 31652af52eac..0643b1b94a39 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -393,11 +393,6 @@ static dev_link_t *ray_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &ray_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -2916,6 +2911,7 @@ static struct pcmcia_driver ray_driver = { .name = "ray_cs", }, .attach = ray_attach, + .event = ray_event, .detach = ray_detach, .id_table = ray_ids, }; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 89532fd92941..f6130a53b796 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -4684,12 +4684,6 @@ wavelan_attach(void) /* Register with Card Services */ client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_REGISTRATION_COMPLETE | - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &wavelan_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -4904,6 +4898,7 @@ static struct pcmcia_driver wavelan_driver = { .name = "wavelan_cs", }, .attach = wavelan_attach, + .event = wavelan_event, .detach = wavelan_detach, .id_table = wavelan_ids, }; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index e3a900482d92..e3aaaa5efccf 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -2005,13 +2005,6 @@ static dev_link_t *wl3501_attach(void) link->next = wl3501_dev_list; wl3501_dev_list = link; client_reg.dev_info = &wl3501_dev_info; - client_reg.EventMask = CS_EVENT_CARD_INSERTION | - CS_EVENT_RESET_PHYSICAL | - CS_EVENT_CARD_RESET | - CS_EVENT_CARD_REMOVAL | - CS_EVENT_PM_SUSPEND | - CS_EVENT_PM_RESUME; - client_reg.event_handler = wl3501_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -2246,12 +2239,13 @@ static struct pcmcia_device_id wl3501_ids[] = { MODULE_DEVICE_TABLE(pcmcia, wl3501_ids); static struct pcmcia_driver wl3501_driver = { - .owner = THIS_MODULE, - .drv = { - .name = "wl3501_cs", + .owner = THIS_MODULE, + .drv = { + .name = "wl3501_cs", }, - .attach = wl3501_attach, - .detach = wl3501_detach, + .attach = wl3501_attach, + .event = wl3501_event, + .detach = wl3501_detach, .id_table = wl3501_ids, }; diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index ff45662c4f7c..ad8921a260ec 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -133,11 +133,6 @@ static dev_link_t *parport_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &parport_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -386,6 +381,7 @@ static struct pcmcia_driver parport_cs_driver = { .name = "parport_cs", }, .attach = parport_attach, + .event = parport_event, .detach = parport_detach, .id_table = parport_ids, diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 0b4c18edfa49..e0ba4b5daa13 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -114,9 +114,6 @@ static inline void cs_socket_put(struct pcmcia_socket *skt) #define CHECK_ERASEQ(q) \ (((q) == NULL) || ((q)->eraseq_magic != ERASEQ_MAGIC)) -#define EVENT(h, e, p) \ - ((h)->event_handler((e), (p), &(h)->event_callback_args)) - /* In cardbus.c */ int cb_alloc(struct pcmcia_socket *s); void cb_free(struct pcmcia_socket *s); diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index d5afd557fe37..367ebf75beeb 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -207,6 +207,10 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv) unsigned int i; u32 hash; + if (!p_drv->attach || !p_drv->event || !p_drv->detach) + printk(KERN_DEBUG "pcmcia: %s does misses a callback function", + p_drv->drv.name); + while (did && did->match_flags) { for (i=0; i<4; i++) { if (!did->prod_id[i]) @@ -914,6 +918,7 @@ struct send_event_data { static int send_event_callback(struct device *dev, void * _data) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); + struct pcmcia_driver *p_drv; struct send_event_data *data = _data; /* we get called for all sockets, but may only pass the event @@ -921,11 +926,16 @@ static int send_event_callback(struct device *dev, void * _data) if (p_dev->socket != data->skt) return 0; + p_drv = to_pcmcia_drv(p_dev->dev.driver); + if (!p_drv) + return 0; + if (p_dev->client.state & (CLIENT_UNBOUND|CLIENT_STALE)) return 0; - if (p_dev->client.EventMask & data->event) - return EVENT(&p_dev->client, data->event, data->priority); + if (p_drv->event) + return p_drv->event(data->event, data->priority, + &p_dev->event_callback_args); return 0; } @@ -992,6 +1002,7 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) client_t *client = NULL; struct pcmcia_socket *s = NULL; struct pcmcia_device *p_dev = NULL; + struct pcmcia_driver *p_drv = NULL; /* Look for unbound client with matching dev_info */ down_read(&pcmcia_socket_list_rwsem); @@ -1006,7 +1017,6 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) continue; spin_lock_irqsave(&pcmcia_dev_list_lock, flags); list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { - struct pcmcia_driver *p_drv; p_dev = pcmcia_get_dev(p_dev); if (!p_dev) continue; @@ -1036,10 +1046,9 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) *handle = client; client->state &= ~CLIENT_UNBOUND; client->Socket = s; - client->EventMask = req->EventMask; - client->event_handler = req->event_handler; - client->event_callback_args = req->event_callback_args; - client->event_callback_args.client_handle = client; + p_dev->event_callback_args = req->event_callback_args; + p_dev->event_callback_args.client_handle = client; + if (s->state & SOCKET_CARDBUS) client->state |= CLIENT_CARDBUS; @@ -1061,12 +1070,12 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) ds_dbg(1, "register_client(): client 0x%p, dev %s\n", client, p_dev->dev.bus_id); - if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE) - EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW); if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) { - if (client->EventMask & CS_EVENT_CARD_INSERTION) - EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); + if (p_drv->event) + p_drv->event(CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW, + &p_dev->event_callback_args); + } return CS_SUCCESS; @@ -1132,7 +1141,6 @@ int pcmcia_deregister_client(client_handle_t handle) pcmcia_put_dev(p_dev); } else { handle->state = CLIENT_UNBOUND; - handle->event_handler = NULL; } return CS_SUCCESS; diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index f1f6bf596dc9..3dc6957bad10 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -134,11 +134,6 @@ static dev_link_t *aha152x_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.event_handler = &aha152x_event; - client_reg.EventMask = - CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -334,6 +329,7 @@ static struct pcmcia_driver aha152x_cs_driver = { .name = "aha152x_cs", }, .attach = aha152x_attach, + .event = aha152x_event, .detach = aha152x_detach, .id_table = aha152x_ids, }; diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index 853e6ee9b71a..d2281eba790d 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -120,11 +120,6 @@ static dev_link_t *fdomain_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.event_handler = &fdomain_event; - client_reg.EventMask = - CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -314,6 +309,7 @@ static struct pcmcia_driver fdomain_cs_driver = { .name = "fdomain_cs", }, .attach = fdomain_attach, + .event = fdomain_event, .detach = fdomain_detach, .id_table = fdomain_ids, }; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 91b3f28e7a19..c8755adfd917 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1642,11 +1642,6 @@ static dev_link_t *nsp_cs_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME ; - client_reg.event_handler = &nsp_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -2138,12 +2133,13 @@ static struct pcmcia_device_id nsp_cs_ids[] = { MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids); static struct pcmcia_driver nsp_driver = { - .owner = THIS_MODULE, - .drv = { - .name = "nsp_cs", + .owner = THIS_MODULE, + .drv = { + .name = "nsp_cs", }, - .attach = nsp_cs_attach, - .detach = nsp_cs_detach, + .attach = nsp_cs_attach, + .event = nsp_cs_event, + .detach = nsp_cs_detach, .id_table = nsp_cs_ids, }; #endif diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index 0dcf41102abf..e6e496180d11 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -194,8 +194,6 @@ static dev_link_t *qlogic_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.event_handler = &qlogic_event; - client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -423,6 +421,7 @@ static struct pcmcia_driver qlogic_cs_driver = { .name = "qlogic_cs", }, .attach = qlogic_attach, + .event = qlogic_event, .detach = qlogic_detach, .id_table = qlogic_ids, }; diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 7d4b16b6797d..b4b3a1a8a0c7 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -979,10 +979,6 @@ SYM53C500_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.event_handler = &SYM53C500_event; - client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -1013,6 +1009,7 @@ static struct pcmcia_driver sym53c500_cs_driver = { .name = "sym53c500_cs", }, .attach = SYM53C500_attach, + .event = SYM53C500_event, .detach = SYM53C500_detach, .id_table = sym53c500_ids, }; diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 73a34b18866f..83bfd11a1cc4 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -232,11 +232,6 @@ static dev_link_t *serial_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &serial_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -883,6 +878,7 @@ static struct pcmcia_driver serial_cs_driver = { .name = "serial_cs", }, .attach = serial_attach, + .event = serial_event, .detach = serial_detach, .id_table = serial_ids, }; diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c index ce5ebfe4af2b..2fcb4db3abc5 100644 --- a/drivers/telephony/ixj_pcmcia.c +++ b/drivers/telephony/ixj_pcmcia.c @@ -69,11 +69,6 @@ static dev_link_t *ixj_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &ixj_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -307,6 +302,7 @@ static struct pcmcia_driver ixj_driver = { .name = "ixj_cs", }, .attach = ixj_attach, + .event = ixj_event, .detach = ixj_detach, .id_table = ixj_ids, }; diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 269d8ef01459..55dfeec6fdb5 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -389,11 +389,6 @@ static dev_link_t *sl811_cs_attach(void) dev_list = link; client_reg.dev_info = (dev_info_t *) &driver_name; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &sl811_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -418,6 +413,7 @@ static struct pcmcia_driver sl811_cs_driver = { .name = (char *)driver_name, }, .attach = sl811_cs_attach, + .event = sl811_cs_event, .detach = sl811_cs_detach, .id_table = sl811_ids, }; diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index 2b52553f2d94..c574ff108148 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -133,6 +133,8 @@ struct pcmcia_socket; struct pcmcia_driver { dev_link_t *(*attach)(void); + int (*event) (event_t event, int priority, + event_callback_args_t *); void (*detach)(dev_link_t *); struct module *owner; struct pcmcia_device_id *id_table; @@ -159,15 +161,13 @@ struct pcmcia_device { /* deprecated, a cleaned up version will be moved into this struct soon */ dev_link_t *instance; + event_callback_args_t event_callback_args; + struct client_t { u_short client_magic; struct pcmcia_socket *Socket; u_char Function; u_int state; - event_t EventMask; - int (*event_handler) (event_t event, int priority, - event_callback_args_t *); - event_callback_args_t event_callback_args; } client; /* information about this device */ diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 2d4f8e28478b..c8622f5f7c3a 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -171,14 +171,6 @@ static dev_link_t *snd_pdacf_attach(void) /* Register with Card Services */ client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL -#ifdef CONFIG_PM - | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET - | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME -#endif - ; - client_reg.event_handler = &pdacf_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -387,12 +379,13 @@ static struct pcmcia_device_id snd_pdacf_ids[] = { MODULE_DEVICE_TABLE(pcmcia, snd_pdacf_ids); static struct pcmcia_driver pdacf_cs_driver = { - .owner = THIS_MODULE, - .drv = { - .name = "snd-pdaudiocf", + .owner = THIS_MODULE, + .drv = { + .name = "snd-pdaudiocf", }, - .attach = snd_pdacf_attach, - .detach = snd_pdacf_detach, + .attach = snd_pdacf_attach, + .event = pdacf_event, + .detach = snd_pdacf_detach, .id_table = snd_pdacf_ids, }; diff --git a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c index 332bbca3dfc4..df7a39ba9680 100644 --- a/sound/pcmcia/vx/vx_entry.c +++ b/sound/pcmcia/vx/vx_entry.c @@ -35,7 +35,6 @@ MODULE_LICENSE("GPL"); * prototypes */ static void vxpocket_config(dev_link_t *link); -static int vxpocket_event(event_t event, int priority, event_callback_args_t *args); static void vxpocket_release(dev_link_t *link) @@ -169,14 +168,6 @@ dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw) /* Register with Card Services */ memset(&client_reg, 0, sizeof(client_reg)); client_reg.dev_info = hw->dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL -#ifdef CONFIG_PM - | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET - | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME -#endif - ; - client_reg.event_handler = &vxpocket_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -321,7 +312,7 @@ failed: /* * event callback */ -static int vxpocket_event(event_t event, int priority, event_callback_args_t *args) +int vxpocket_event(event_t event, int priority, event_callback_args_t *args) { dev_link_t *link = args->client_data; vx_core_t *chip = link->priv; @@ -380,4 +371,5 @@ static int vxpocket_event(event_t event, int priority, event_callback_args_t *ar */ EXPORT_SYMBOL(snd_vxpocket_ops); EXPORT_SYMBOL(snd_vxpocket_attach); +EXPORT_SYMBOL(vxpocket_event); EXPORT_SYMBOL(snd_vxpocket_detach); -- cgit v1.2.3 From 44670d2b50efd2443c3810239d6ea3fd02f8ef64 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 7 Jul 2005 17:59:05 -0700 Subject: [PATCH] pcmcia: remove references to pcmcia/version.h As a follow-up, remove the inclusion of pcmcia/version.h in many files. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/bluetooth/bluecard_cs.c | 1 - drivers/bluetooth/bt3c_cs.c | 1 - drivers/bluetooth/btuart_cs.c | 1 - drivers/bluetooth/dtl1_cs.c | 1 - drivers/char/pcmcia/synclink_cs.c | 1 - drivers/ide/legacy/ide-cs.c | 1 - drivers/isdn/hardware/avm/avm_cs.c | 1 - drivers/isdn/hisax/avma1_cs.c | 1 - drivers/isdn/hisax/elsa_cs.c | 1 - drivers/isdn/hisax/sedlbauer_cs.c | 1 - drivers/isdn/hisax/teles_cs.c | 1 - drivers/mtd/maps/pcmciamtd.c | 1 - drivers/net/pcmcia/3c574_cs.c | 1 - drivers/net/pcmcia/3c589_cs.c | 1 - drivers/net/pcmcia/axnet_cs.c | 1 - drivers/net/pcmcia/com20020_cs.c | 1 - drivers/net/pcmcia/fmvj18x_cs.c | 1 - drivers/net/pcmcia/ibmtr_cs.c | 1 - drivers/net/pcmcia/nmclan_cs.c | 1 - drivers/net/pcmcia/pcnet_cs.c | 1 - drivers/net/pcmcia/smc91c92_cs.c | 1 - drivers/net/pcmcia/xirc2ps_cs.c | 1 - drivers/net/wireless/airo_cs.c | 1 - drivers/net/wireless/atmel_cs.c | 1 - drivers/net/wireless/netwave_cs.c | 1 - drivers/net/wireless/orinoco_cs.c | 1 - drivers/net/wireless/ray_cs.c | 1 - drivers/net/wireless/wavelan_cs.p.h | 1 - drivers/net/wireless/wl3501_cs.c | 1 - drivers/parport/parport_cs.c | 1 - drivers/pcmcia/au1000_generic.h | 1 - drivers/pcmcia/au1000_pb1x00.c | 1 - drivers/pcmcia/au1000_xxs1500.c | 1 - drivers/pcmcia/cardbus.c | 1 - drivers/pcmcia/cs.c | 1 - drivers/pcmcia/hd64465_ss.c | 1 - drivers/pcmcia/i82365.c | 1 - drivers/pcmcia/m32r_cfc.c | 1 - drivers/pcmcia/m32r_pcc.c | 1 - drivers/pcmcia/pcmcia_compat.c | 1 - drivers/pcmcia/pcmcia_ioctl.c | 1 - drivers/pcmcia/pcmcia_resource.c | 1 - drivers/pcmcia/sa1100_generic.c | 1 - drivers/pcmcia/soc_common.h | 1 - drivers/pcmcia/socket_sysfs.c | 1 - drivers/pcmcia/tcic.c | 1 - drivers/pcmcia/yenta_socket.c | 1 - drivers/scsi/pcmcia/aha152x_stub.c | 1 - drivers/scsi/pcmcia/fdomain_stub.c | 1 - drivers/scsi/pcmcia/nsp_cs.c | 1 - drivers/scsi/pcmcia/qlogic_stub.c | 1 - drivers/serial/serial_cs.c | 1 - drivers/telephony/ixj_pcmcia.c | 1 - drivers/usb/host/sl811_cs.c | 1 - sound/pcmcia/pdaudiocf/pdaudiocf.c | 1 - sound/pcmcia/vx/vxpocket.c | 1 - 56 files changed, 56 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 53661246100e..bd2ec7e284cc 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -40,7 +40,6 @@ #include #include -#include #include #include #include diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 06539a542e98..adf1750ea58d 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -47,7 +47,6 @@ #include #include -#include #include #include #include diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index f15a9cf2b787..e4c59fdc0e12 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 58b09a9cc4c6..e39868c3da48 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index ea691561e083..7a0c74648124 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -71,7 +71,6 @@ #include #include -#include #include #include #include diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index fde0d5f1b876..aac59751e1b4 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -46,7 +46,6 @@ #include #include -#include #include #include #include diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index a30c74fd75da..db9bad2b3d16 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index d3de0e856192..0e22991635e7 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index 54f0d68ad796..6fc6868de0b0 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -47,7 +47,6 @@ #include #include -#include #include #include #include diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index baf733e86474..c6b5bf7d2aca 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -47,7 +47,6 @@ #include #include -#include #include #include #include diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index b8eeb789f901..0ddef1bf778b 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -28,7 +28,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index aa820ee4c31a..ff7c50d10180 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index c942964a49d2..71fd41122c91 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -86,7 +86,6 @@ earlier 3Com products. #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 810864c6d1ea..d83fdd8c1943 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -40,7 +40,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 3d01079598c8..8bb4e85689ea 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -37,7 +37,6 @@ #include #include "../8390.h" -#include #include #include #include diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index b5119607d5af..b9355d9498a3 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index c7d9bb1da417..9d8197bb293a 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -49,7 +49,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 39cec4a1e4b3..b6c140eb9799 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -57,7 +57,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 49124dc26b35..dbb941004ae9 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -146,7 +146,6 @@ Include Files #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index b22b354af5c0..e1664aef3dfd 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -40,7 +40,6 @@ #include #include <../drivers/net/8390.h> -#include #include #include #include diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 6b5471dfb554..fbc2f58ff688 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -42,7 +42,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 03d4c0c6b3fd..9f33bad174e9 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -81,7 +81,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index fd46393e743e..bf25584d68d3 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 863be2995036..ff031a3985b3 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index bdd3e7083d9e..5f507c49907b 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -62,7 +62,6 @@ #endif /* WIRELESS_EXT > 12 */ #endif -#include #include #include #include diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index c883404b1d59..368d2f962f67 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 0643b1b94a39..0e0ba614259a 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -46,7 +46,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index ea2ef8dddb92..677ff71883cb 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h @@ -452,7 +452,6 @@ #include #include #include -#include /* Wavelan declarations */ #include "i82593.h" /* Definitions for the Intel chip */ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index e3aaaa5efccf..dd902126d018 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -49,7 +49,6 @@ #include -#include #include #include #include diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index ad8921a260ec..24e6aacddb74 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -48,7 +48,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h index 417bc1500bad..d5122b1ea94b 100644 --- a/drivers/pcmcia/au1000_generic.h +++ b/drivers/pcmcia/au1000_generic.h @@ -22,7 +22,6 @@ #define __ASM_AU1000_PCMCIA_H /* include the world */ -#include #include #include #include diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c index df19ce1ea4f3..d414a3bb50b9 100644 --- a/drivers/pcmcia/au1000_pb1x00.c +++ b/drivers/pcmcia/au1000_pb1x00.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c index 1dfc77653660..f113b69d699b 100644 --- a/drivers/pcmcia/au1000_xxs1500.c +++ b/drivers/pcmcia/au1000_xxs1500.c @@ -38,7 +38,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index 3ccb5247ec50..1d755e20880c 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -31,7 +31,6 @@ #include #define IN_CARD_SERVICES -#include #include #include #include diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index e82859d3227a..4d1cc5304e17 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -33,7 +33,6 @@ #include #define IN_CARD_SERVICES -#include #include #include #include diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index 5ab55ae0ac36..316f8bcc878b 100644 --- a/drivers/pcmcia/hd64465_ss.c +++ b/drivers/pcmcia/hd64465_ss.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 3546158ef776..a713015e8228 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -53,7 +53,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index b1111c6bf062..65f3ee3d4d3c 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -29,7 +29,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index c0997c4714f0..7b14d7efd68c 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c index 962ca004ac1b..ebb161c4f819 100644 --- a/drivers/pcmcia/pcmcia_compat.c +++ b/drivers/pcmcia/pcmcia_compat.c @@ -18,7 +18,6 @@ #include #define IN_CARD_SERVICES -#include #include #include #include diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index ee02224dd774..39ba6406fd54 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -31,7 +31,6 @@ #include #define IN_CARD_SERVICES -#include #include #include #include diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index ec2abb37f407..184f4f88b2a0 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -23,7 +23,6 @@ #include #define IN_CARD_SERVICES -#include #include #include #include diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index f1bb79153021..e98bb3d80e7c 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -34,7 +34,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 700a155fbc78..6f14126889b3 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -11,7 +11,6 @@ /* include the world */ #include -#include #include #include #include diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index fcef54c1c2da..1040a6c1a8a4 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -29,7 +29,6 @@ #include #define IN_CARD_SERVICES -#include #include #include #include diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index aacbbb5f055d..d5a61eae6119 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -50,7 +50,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 02b23abc2df1..1d593e1dc3d9 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 3dc6957bad10..7c5306499832 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -50,7 +50,6 @@ #include #include "aha152x.h" -#include #include #include #include diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index d2281eba790d..db8f5cd85ffe 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -47,7 +47,6 @@ #include #include "fdomain.h" -#include #include #include #include diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index c8755adfd917..3cd3b40b1a4c 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -51,7 +51,6 @@ #include #include -#include #include #include #include diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index e6e496180d11..7a516f35834e 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -49,7 +49,6 @@ #include #include "../qlogicfas408.h" -#include #include #include #include diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 83bfd11a1cc4..de0136cc5938 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -45,7 +45,6 @@ #include #include -#include #include #include #include diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c index 2fcb4db3abc5..57c0c6e3fbed 100644 --- a/drivers/telephony/ixj_pcmcia.c +++ b/drivers/telephony/ixj_pcmcia.c @@ -9,7 +9,6 @@ #include /* error codes */ #include -#include #include #include #include diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 55dfeec6fdb5..38aebe361ca1 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -20,7 +20,6 @@ #include #include -#include #include #include #include diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index c8622f5f7c3a..d6918b453f28 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include "pdaudiocf.h" diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 5f4c13264159..62d6fa128148 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "vxpocket.h" #include -- cgit v1.2.3 From b03efcfb2180289718991bb984044ce6c5b7d1b0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 8 Jul 2005 14:57:23 -0700 Subject: [NET]: Transform skb_queue_len() binary tests into skb_queue_empty() This is part of the grand scheme to eliminate the qlen member of skb_queue_head, and subsequently remove the 'list' member of sk_buff. Most users of skb_queue_len() want to know if the queue is empty or not, and that's trivially done with skb_queue_empty() which doesn't use the skb_queue_head->qlen member and instead uses the queue list emptyness as the test. Signed-off-by: David S. Miller --- drivers/bluetooth/hci_vhci.c | 2 +- drivers/isdn/hisax/isdnl1.c | 3 ++- drivers/isdn/hisax/isdnl2.c | 17 +++++++++-------- drivers/isdn/hisax/isdnl3.c | 2 +- drivers/isdn/i4l/isdn_tty.c | 4 ++-- drivers/isdn/icn/icn.c | 4 ++-- drivers/net/hamradio/scc.c | 5 ++--- drivers/net/ppp_async.c | 2 +- drivers/net/ppp_generic.c | 12 ++++++------ drivers/net/ppp_synctty.c | 2 +- drivers/net/tun.c | 2 +- drivers/net/wireless/airo.c | 4 ++-- drivers/s390/net/claw.c | 4 ++-- drivers/s390/net/ctctty.c | 6 +++--- drivers/usb/net/usbnet.c | 6 +++--- include/net/irda/irda_device.h | 2 +- include/net/tcp.h | 2 +- net/bluetooth/cmtp/core.c | 6 ++---- net/bluetooth/hidp/core.c | 5 +---- net/bluetooth/rfcomm/sock.c | 7 +++++-- net/bluetooth/rfcomm/tty.c | 2 +- net/decnet/af_decnet.c | 10 +++++----- net/decnet/dn_nsp_out.c | 3 ++- net/ipv4/tcp.c | 8 ++++---- net/ipv4/tcp_input.c | 11 +++++------ net/ipv4/tcp_timer.c | 5 ++--- net/irda/irlap.c | 3 +-- net/irda/irlap_event.c | 14 +++++++------- net/irda/irlap_frame.c | 8 +++----- net/irda/irttp.c | 2 +- net/llc/llc_c_ev.c | 2 +- net/netlink/af_netlink.c | 2 +- net/sched/sch_red.c | 2 +- net/unix/af_unix.c | 4 ++-- 34 files changed, 84 insertions(+), 89 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 3256192dcde8..f9b956fb2b8b 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -120,7 +120,7 @@ static unsigned int hci_vhci_chr_poll(struct file *file, poll_table * wait) poll_wait(file, &hci_vhci->read_wait, wait); - if (skb_queue_len(&hci_vhci->readq)) + if (!skb_queue_empty(&hci_vhci->readq)) return POLLIN | POLLRDNORM; return POLLOUT | POLLWRNORM; diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index ac899503a74f..bab356886483 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -279,7 +279,8 @@ BChannel_proc_xmt(struct BCState *bcs) if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) { - if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) { + if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && + skb_queue_empty(&bcs->squeue)) { st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); } } diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c index 9022583fd6a0..1615c1a76ab8 100644 --- a/drivers/isdn/hisax/isdnl2.c +++ b/drivers/isdn/hisax/isdnl2.c @@ -108,7 +108,8 @@ static int l2addrsize(struct Layer2 *l2); static void set_peer_busy(struct Layer2 *l2) { test_and_set_bit(FLG_PEER_BUSY, &l2->flag); - if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue)) + if (!skb_queue_empty(&l2->i_queue) || + !skb_queue_empty(&l2->ui_queue)) test_and_set_bit(FLG_L2BLOCK, &l2->flag); } @@ -754,7 +755,7 @@ l2_restart_multi(struct FsmInst *fi, int event, void *arg) st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL); if ((ST_L2_7==state) || (ST_L2_8 == state)) - if (skb_queue_len(&st->l2.i_queue) && cansend(st)) + if (!skb_queue_empty(&st->l2.i_queue) && cansend(st)) st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } @@ -810,7 +811,7 @@ l2_connected(struct FsmInst *fi, int event, void *arg) if (pr != -1) st->l2.l2l3(st, pr, NULL); - if (skb_queue_len(&st->l2.i_queue) && cansend(st)) + if (!skb_queue_empty(&st->l2.i_queue) && cansend(st)) st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } @@ -1014,7 +1015,7 @@ l2_st7_got_super(struct FsmInst *fi, int event, void *arg) if(typ != RR) FsmDelTimer(&st->l2.t203, 9); restart_t200(st, 12); } - if (skb_queue_len(&st->l2.i_queue) && (typ == RR)) + if (!skb_queue_empty(&st->l2.i_queue) && (typ == RR)) st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } else nrerrorrecovery(fi); @@ -1120,7 +1121,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg) return; } - if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7)) + if (!skb_queue_empty(&st->l2.i_queue) && (fi->state == ST_L2_7)) st->l2.l2l1(st, PH_PULL | REQUEST, NULL); if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag)) enquiry_cr(st, RR, RSP, 0); @@ -1138,7 +1139,7 @@ l2_got_tei(struct FsmInst *fi, int event, void *arg) test_and_set_bit(FLG_L3_INIT, &st->l2.flag); } else FsmChangeState(fi, ST_L2_4); - if (skb_queue_len(&st->l2.ui_queue)) + if (!skb_queue_empty(&st->l2.ui_queue)) tx_ui(st); } @@ -1301,7 +1302,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) FsmDelTimer(&st->l2.t203, 13); FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11); } - if (skb_queue_len(&l2->i_queue) && cansend(st)) + if (!skb_queue_empty(&l2->i_queue) && cansend(st)) st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } @@ -1347,7 +1348,7 @@ l2_st8_got_super(struct FsmInst *fi, int event, void *arg) } invoke_retransmission(st, nr); FsmChangeState(fi, ST_L2_7); - if (skb_queue_len(&l2->i_queue) && cansend(st)) + if (!skb_queue_empty(&l2->i_queue) && cansend(st)) st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } else nrerrorrecovery(fi); diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c index abcc9530eb34..c9917cd2132b 100644 --- a/drivers/isdn/hisax/isdnl3.c +++ b/drivers/isdn/hisax/isdnl3.c @@ -302,7 +302,7 @@ release_l3_process(struct l3_process *p) !test_bit(FLG_PTP, &p->st->l2.flag)) { if (p->debug) l3_debug(p->st, "release_l3_process: last process"); - if (!skb_queue_len(&p->st->l3.squeue)) { + if (skb_queue_empty(&p->st->l3.squeue)) { if (p->debug) l3_debug(p->st, "release_l3_process: release link"); if (p->st->protocol != ISDN_PTYPE_NI1) diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index ad5aa38fb5a6..b37ef1f06b3d 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1223,7 +1223,7 @@ isdn_tty_write(struct tty_struct *tty, const u_char * buf, int count) total += c; } atomic_dec(&info->xmit_lock); - if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) { + if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) { if (m->mdmreg[REG_DXMT] & BIT_DXMT) { isdn_tty_senddown(info); isdn_tty_tint(info); @@ -1284,7 +1284,7 @@ isdn_tty_flush_chars(struct tty_struct *tty) if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars")) return; - if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) + if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); } diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 9fc0c1e03732..e0d1b01cc74c 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -304,12 +304,12 @@ icn_pollbchan_send(int channel, icn_card * card) isdn_ctrl cmd; if (!(card->sndcount[channel] || card->xskb[channel] || - skb_queue_len(&card->spqueue[channel]))) + !skb_queue_empty(&card->spqueue[channel]))) return; if (icn_trymaplock_channel(card, mch)) { while (sbfree && (card->sndcount[channel] || - skb_queue_len(&card->spqueue[channel]) || + !skb_queue_empty(&card->spqueue[channel]) || card->xskb[channel])) { spin_lock_irqsave(&card->lock, flags); if (card->xmit_lock[channel]) { diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index ece1b1a13186..c27e417f32bf 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -304,7 +304,7 @@ static inline void scc_discard_buffers(struct scc_channel *scc) scc->tx_buff = NULL; } - while (skb_queue_len(&scc->tx_queue)) + while (!skb_queue_empty(&scc->tx_queue)) dev_kfree_skb(skb_dequeue(&scc->tx_queue)); spin_unlock_irqrestore(&scc->lock, flags); @@ -1126,8 +1126,7 @@ static void t_dwait(unsigned long channel) if (scc->stat.tx_state == TXS_WAIT) /* maxkeyup or idle timeout */ { - if (skb_queue_len(&scc->tx_queue) == 0) /* nothing to send */ - { + if (skb_queue_empty(&scc->tx_queue)) { /* nothing to send */ scc->stat.tx_state = TXS_IDLE; netif_wake_queue(scc->dev); /* t_maxkeyup locked it. */ return; diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index 5e48b9ab3045..59e8183c639e 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -364,7 +364,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, spin_lock_irqsave(&ap->recv_lock, flags); ppp_async_input(ap, buf, cflags, count); spin_unlock_irqrestore(&ap->recv_lock, flags); - if (skb_queue_len(&ap->rqueue)) + if (!skb_queue_empty(&ap->rqueue)) tasklet_schedule(&ap->tsk); ap_put(ap); if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index ab726ab43798..a32668e88e09 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1237,8 +1237,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) pch = list_entry(list, struct channel, clist); navail += pch->avail = (pch->chan != NULL); if (pch->avail) { - if (skb_queue_len(&pch->file.xq) == 0 - || !pch->had_frag) { + if (skb_queue_empty(&pch->file.xq) || + !pch->had_frag) { pch->avail = 2; ++nfree; } @@ -1374,8 +1374,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) /* try to send it down the channel */ chan = pch->chan; - if (skb_queue_len(&pch->file.xq) - || !chan->ops->start_xmit(chan, frag)) + if (!skb_queue_empty(&pch->file.xq) || + !chan->ops->start_xmit(chan, frag)) skb_queue_tail(&pch->file.xq, frag); pch->had_frag = 1; p += flen; @@ -1412,7 +1412,7 @@ ppp_channel_push(struct channel *pch) spin_lock_bh(&pch->downl); if (pch->chan != 0) { - while (skb_queue_len(&pch->file.xq) > 0) { + while (!skb_queue_empty(&pch->file.xq)) { skb = skb_dequeue(&pch->file.xq); if (!pch->chan->ops->start_xmit(pch->chan, skb)) { /* put the packet back and try again later */ @@ -1426,7 +1426,7 @@ ppp_channel_push(struct channel *pch) } spin_unlock_bh(&pch->downl); /* see if there is anything from the attached unit to be sent */ - if (skb_queue_len(&pch->file.xq) == 0) { + if (skb_queue_empty(&pch->file.xq)) { read_lock_bh(&pch->upl); ppp = pch->ppp; if (ppp != 0) diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index fd9f50180355..4d51c0c8023d 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -406,7 +406,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf, spin_lock_irqsave(&ap->recv_lock, flags); ppp_sync_input(ap, buf, cflags, count); spin_unlock_irqrestore(&ap->recv_lock, flags); - if (skb_queue_len(&ap->rqueue)) + if (!skb_queue_empty(&ap->rqueue)) tasklet_schedule(&ap->tsk); sp_put(ap); if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 7bfee366297b..effab0b9adca 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -215,7 +215,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) poll_wait(file, &tun->read_wait, wait); - if (skb_queue_len(&tun->readq)) + if (!skb_queue_empty(&tun->readq)) mask |= POLLIN | POLLRDNORM; return mask; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index c12648d8192b..47f3c5d0203d 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2374,7 +2374,7 @@ void stop_airo_card( struct net_device *dev, int freeres ) /* * Clean out tx queue */ - if (test_bit(FLAG_MPI, &ai->flags) && skb_queue_len (&ai->txq) > 0) { + if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) { struct sk_buff *skb = NULL; for (;(skb = skb_dequeue(&ai->txq));) dev_kfree_skb(skb); @@ -3287,7 +3287,7 @@ exitrx: if (status & EV_TXEXC) get_tx_error(apriv, -1); spin_lock_irqsave(&apriv->aux_lock, flags); - if (skb_queue_len (&apriv->txq)) { + if (!skb_queue_empty(&apriv->txq)) { spin_unlock_irqrestore(&apriv->aux_lock,flags); mpi_send_packet (dev); } else { diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 60440dbe3a27..24c0af49c25c 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -428,7 +428,7 @@ claw_pack_skb(struct claw_privbk *privptr) new_skb = NULL; /* assume no dice */ pkt_cnt = 0; CLAW_DBF_TEXT(4,trace,"PackSKBe"); - if (skb_queue_len(&p_ch->collect_queue) > 0) { + if (!skb_queue_empty(&p_ch->collect_queue)) { /* some data */ held_skb = skb_dequeue(&p_ch->collect_queue); if (p_env->packing != DO_PACKED) @@ -1254,7 +1254,7 @@ claw_write_next ( struct chbk * p_ch ) privptr = (struct claw_privbk *) dev->priv; claw_free_wrt_buf( dev ); if ((privptr->write_free_count > 0) && - (skb_queue_len(&p_ch->collect_queue) > 0)) { + !skb_queue_empty(&p_ch->collect_queue)) { pk_skb = claw_pack_skb(privptr); while (pk_skb != NULL) { rc = claw_hw_tx( pk_skb, dev,1); diff --git a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c index 3080393e823d..968f2c113efe 100644 --- a/drivers/s390/net/ctctty.c +++ b/drivers/s390/net/ctctty.c @@ -156,7 +156,7 @@ ctc_tty_readmodem(ctc_tty_info *info) skb_queue_head(&info->rx_queue, skb); else { kfree_skb(skb); - ret = skb_queue_len(&info->rx_queue); + ret = !skb_queue_empty(&info->rx_queue); } } } @@ -530,7 +530,7 @@ ctc_tty_write(struct tty_struct *tty, const u_char * buf, int count) total += c; count -= c; } - if (skb_queue_len(&info->tx_queue)) { + if (!skb_queue_empty(&info->tx_queue)) { info->lsr &= ~UART_LSR_TEMT; tasklet_schedule(&info->tasklet); } @@ -594,7 +594,7 @@ ctc_tty_flush_chars(struct tty_struct *tty) return; if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_chars")) return; - if (tty->stopped || tty->hw_stopped || (!skb_queue_len(&info->tx_queue))) + if (tty->stopped || tty->hw_stopped || skb_queue_empty(&info->tx_queue)) return; tasklet_schedule(&info->tasklet); } diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 8a945f4f3693..576f3b852fce 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -3227,9 +3227,9 @@ static int usbnet_stop (struct net_device *net) temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq); // maybe wait for deletions to finish. - while (skb_queue_len (&dev->rxq) - && skb_queue_len (&dev->txq) - && skb_queue_len (&dev->done)) { + while (!skb_queue_empty(&dev->rxq) && + !skb_queue_empty(&dev->txq) && + !skb_queue_empty(&dev->done)) { msleep(UNLINK_TIMEOUT_MS); if (netif_msg_ifdown (dev)) devdbg (dev, "waited for %d urb completions", temp); diff --git a/include/net/irda/irda_device.h b/include/net/irda/irda_device.h index 71d6af83b631..92c828029cd8 100644 --- a/include/net/irda/irda_device.h +++ b/include/net/irda/irda_device.h @@ -224,7 +224,7 @@ int irda_device_is_receiving(struct net_device *dev); /* Interface for internal use */ static inline int irda_device_txqueue_empty(const struct net_device *dev) { - return (skb_queue_len(&dev->qdisc->q) == 0); + return skb_queue_empty(&dev->qdisc->q); } int irda_device_set_raw_mode(struct net_device* self, int status); struct net_device *alloc_irdadev(int sizeof_priv); diff --git a/include/net/tcp.h b/include/net/tcp.h index a166918ca56d..4d5b12e4dc11 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -991,7 +991,7 @@ static __inline__ void tcp_fast_path_on(struct tcp_sock *tp) static inline void tcp_fast_path_check(struct sock *sk, struct tcp_sock *tp) { - if (skb_queue_len(&tp->out_of_order_queue) == 0 && + if (skb_queue_empty(&tp->out_of_order_queue) && tp->rcv_wnd && atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf && !tp->urg_data) diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 2e341de3e763..901eff7ebe74 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -213,7 +213,7 @@ static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, in return kernel_sendmsg(sock, &msg, &iv, 1, len); } -static int cmtp_process_transmit(struct cmtp_session *session) +static void cmtp_process_transmit(struct cmtp_session *session) { struct sk_buff *skb, *nskb; unsigned char *hdr; @@ -223,7 +223,7 @@ static int cmtp_process_transmit(struct cmtp_session *session) if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) { BT_ERR("Can't allocate memory for new frame"); - return -ENOMEM; + return; } while ((skb = skb_dequeue(&session->transmit))) { @@ -275,8 +275,6 @@ static int cmtp_process_transmit(struct cmtp_session *session) cmtp_send_frame(session, nskb->data, nskb->len); kfree_skb(nskb); - - return skb_queue_len(&session->transmit); } static int cmtp_session(void *arg) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index affbc55462e8..de8af5f42394 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -428,7 +428,7 @@ static int hidp_send_frame(struct socket *sock, unsigned char *data, int len) return kernel_sendmsg(sock, &msg, &iv, 1, len); } -static int hidp_process_transmit(struct hidp_session *session) +static void hidp_process_transmit(struct hidp_session *session) { struct sk_buff *skb; @@ -453,9 +453,6 @@ static int hidp_process_transmit(struct hidp_session *session) hidp_set_timer(session); kfree_skb(skb); } - - return skb_queue_len(&session->ctrl_transmit) + - skb_queue_len(&session->intr_transmit); } static int hidp_session(void *arg) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index f3f6355a2786..63a123c5c41b 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -590,8 +590,11 @@ static long rfcomm_sock_data_wait(struct sock *sk, long timeo) for (;;) { set_current_state(TASK_INTERRUPTIBLE); - if (skb_queue_len(&sk->sk_receive_queue) || sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN) || - signal_pending(current) || !timeo) + if (!skb_queue_empty(&sk->sk_receive_queue) || + sk->sk_err || + (sk->sk_shutdown & RCV_SHUTDOWN) || + signal_pending(current) || + !timeo) break; set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 6d689200bcf3..6304590fd36a 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -781,7 +781,7 @@ static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty) BT_DBG("tty %p dev %p", tty, dev); - if (skb_queue_len(&dlc->tx_queue)) + if (!skb_queue_empty(&dlc->tx_queue)) return dlc->mtu; return 0; diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 29bb3cd21965..96a02800cd28 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -536,7 +536,7 @@ static void dn_keepalive(struct sock *sk) * we are double checking that we are not sending too * many of these keepalive frames. */ - if (skb_queue_len(&scp->other_xmit_queue) == 0) + if (skb_queue_empty(&scp->other_xmit_queue)) dn_nsp_send_link(sk, DN_NOCHANGE, 0); } @@ -1191,7 +1191,7 @@ static unsigned int dn_poll(struct file *file, struct socket *sock, poll_table struct dn_scp *scp = DN_SK(sk); int mask = datagram_poll(file, sock, wait); - if (skb_queue_len(&scp->other_receive_queue)) + if (!skb_queue_empty(&scp->other_receive_queue)) mask |= POLLRDBAND; return mask; @@ -1214,7 +1214,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCATMARK: lock_sock(sk); - val = (skb_queue_len(&scp->other_receive_queue) != 0); + val = !skb_queue_empty(&scp->other_receive_queue); if (scp->state != DN_RUN) val = -ENOTCONN; release_sock(sk); @@ -1630,7 +1630,7 @@ static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int int len = 0; if (flags & MSG_OOB) - return skb_queue_len(q) ? 1 : 0; + return !skb_queue_empty(q) ? 1 : 0; while(skb != (struct sk_buff *)q) { struct dn_skb_cb *cb = DN_SKB_CB(skb); @@ -1707,7 +1707,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, if (sk->sk_err) goto out; - if (skb_queue_len(&scp->other_receive_queue)) { + if (!skb_queue_empty(&scp->other_receive_queue)) { if (!(flags & MSG_OOB)) { msg->msg_flags |= MSG_OOB; if (!scp->other_report) { diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c index 42abbf3f524f..8cce1fdbda90 100644 --- a/net/decnet/dn_nsp_out.c +++ b/net/decnet/dn_nsp_out.c @@ -342,7 +342,8 @@ int dn_nsp_xmit_timeout(struct sock *sk) dn_nsp_output(sk); - if (skb_queue_len(&scp->data_xmit_queue) || skb_queue_len(&scp->other_xmit_queue)) + if (!skb_queue_empty(&scp->data_xmit_queue) || + !skb_queue_empty(&scp->other_xmit_queue)) scp->persist = dn_nsp_persist(sk); return 0; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 29894c749163..ddb6ce4ecff2 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1105,7 +1105,7 @@ static void tcp_prequeue_process(struct sock *sk) struct sk_buff *skb; struct tcp_sock *tp = tcp_sk(sk); - NET_ADD_STATS_USER(LINUX_MIB_TCPPREQUEUED, skb_queue_len(&tp->ucopy.prequeue)); + NET_INC_STATS_USER(LINUX_MIB_TCPPREQUEUED); /* RX process wants to run with disabled BHs, though it is not * necessary */ @@ -1369,7 +1369,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, * is not empty. It is more elegant, but eats cycles, * unfortunately. */ - if (skb_queue_len(&tp->ucopy.prequeue)) + if (!skb_queue_empty(&tp->ucopy.prequeue)) goto do_prequeue; /* __ Set realtime policy in scheduler __ */ @@ -1394,7 +1394,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } if (tp->rcv_nxt == tp->copied_seq && - skb_queue_len(&tp->ucopy.prequeue)) { + !skb_queue_empty(&tp->ucopy.prequeue)) { do_prequeue: tcp_prequeue_process(sk); @@ -1476,7 +1476,7 @@ skip_copy: } while (len > 0); if (user_recv) { - if (skb_queue_len(&tp->ucopy.prequeue)) { + if (!skb_queue_empty(&tp->ucopy.prequeue)) { int chunk; tp->ucopy.len = copied > 0 ? len : 0; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 8de2f1071c2b..53a8a5399f1e 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2802,7 +2802,7 @@ static void tcp_sack_remove(struct tcp_sock *tp) int this_sack; /* Empty ofo queue, hence, all the SACKs are eaten. Clear. */ - if (skb_queue_len(&tp->out_of_order_queue) == 0) { + if (skb_queue_empty(&tp->out_of_order_queue)) { tp->rx_opt.num_sacks = 0; tp->rx_opt.eff_sacks = tp->rx_opt.dsack; return; @@ -2935,13 +2935,13 @@ queue_and_out: if(th->fin) tcp_fin(skb, sk, th); - if (skb_queue_len(&tp->out_of_order_queue)) { + if (!skb_queue_empty(&tp->out_of_order_queue)) { tcp_ofo_queue(sk); /* RFC2581. 4.2. SHOULD send immediate ACK, when * gap in queue is filled. */ - if (!skb_queue_len(&tp->out_of_order_queue)) + if (skb_queue_empty(&tp->out_of_order_queue)) tp->ack.pingpong = 0; } @@ -3249,9 +3249,8 @@ static int tcp_prune_queue(struct sock *sk) * This must not ever occur. */ /* First, purge the out_of_order queue. */ - if (skb_queue_len(&tp->out_of_order_queue)) { - NET_ADD_STATS_BH(LINUX_MIB_OFOPRUNED, - skb_queue_len(&tp->out_of_order_queue)); + if (!skb_queue_empty(&tp->out_of_order_queue)) { + NET_INC_STATS_BH(LINUX_MIB_OFOPRUNED); __skb_queue_purge(&tp->out_of_order_queue); /* Reset SACK state. A conforming SACK implementation will diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index b127b4498565..0084227438c2 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -231,11 +231,10 @@ static void tcp_delack_timer(unsigned long data) } tp->ack.pending &= ~TCP_ACK_TIMER; - if (skb_queue_len(&tp->ucopy.prequeue)) { + if (!skb_queue_empty(&tp->ucopy.prequeue)) { struct sk_buff *skb; - NET_ADD_STATS_BH(LINUX_MIB_TCPSCHEDULERFAILED, - skb_queue_len(&tp->ucopy.prequeue)); + NET_INC_STATS_BH(LINUX_MIB_TCPSCHEDULERFAILED); while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) sk->sk_backlog_rcv(sk, skb); diff --git a/net/irda/irlap.c b/net/irda/irlap.c index 046ad0750e48..7029618f5719 100644 --- a/net/irda/irlap.c +++ b/net/irda/irlap.c @@ -445,9 +445,8 @@ void irlap_disconnect_request(struct irlap_cb *self) IRDA_ASSERT(self->magic == LAP_MAGIC, return;); /* Don't disconnect until all data frames are successfully sent */ - if (skb_queue_len(&self->txq) > 0) { + if (!skb_queue_empty(&self->txq)) { self->disconnect_pending = TRUE; - return; } diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c index 1cd89f5f3b75..a505b5457608 100644 --- a/net/irda/irlap_event.c +++ b/net/irda/irlap_event.c @@ -191,7 +191,7 @@ static void irlap_start_poll_timer(struct irlap_cb *self, int timeout) * Send out the RR frames faster if our own transmit queue is empty, or * if the peer is busy. The effect is a much faster conversation */ - if ((skb_queue_len(&self->txq) == 0) || (self->remote_busy)) { + if (skb_queue_empty(&self->txq) || self->remote_busy) { if (self->fast_RR == TRUE) { /* * Assert that the fast poll timer has not reached the @@ -263,7 +263,7 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, IRDA_DEBUG(2, "%s() : queue len = %d\n", __FUNCTION__, skb_queue_len(&self->txq)); - if (skb_queue_len(&self->txq)) { + if (!skb_queue_empty(&self->txq)) { /* Prevent race conditions with irlap_data_request() */ self->local_busy = TRUE; @@ -1074,7 +1074,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event, #else /* CONFIG_IRDA_DYNAMIC_WINDOW */ /* Window has been adjusted for the max packet * size, so much simpler... - Jean II */ - nextfit = (skb_queue_len(&self->txq) > 0); + nextfit = !skb_queue_empty(&self->txq); #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ /* * Send data with poll bit cleared only if window > 1 @@ -1814,7 +1814,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event, #else /* CONFIG_IRDA_DYNAMIC_WINDOW */ /* Window has been adjusted for the max packet * size, so much simpler... - Jean II */ - nextfit = (skb_queue_len(&self->txq) > 0); + nextfit = !skb_queue_empty(&self->txq); #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ /* * Send data with final bit cleared only if window > 1 @@ -1937,7 +1937,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, irlap_data_indication(self, skb, FALSE); /* Any pending data requests? */ - if ((skb_queue_len(&self->txq) > 0) && + if (!skb_queue_empty(&self->txq) && (self->window > 0)) { self->ack_required = TRUE; @@ -2038,7 +2038,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, /* * Any pending data requests? */ - if ((skb_queue_len(&self->txq) > 0) && + if (!skb_queue_empty(&self->txq) && (self->window > 0) && !self->remote_busy) { irlap_data_indication(self, skb, TRUE); @@ -2069,7 +2069,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, */ nr_status = irlap_validate_nr_received(self, info->nr); if (nr_status == NR_EXPECTED) { - if ((skb_queue_len( &self->txq) > 0) && + if (!skb_queue_empty(&self->txq) && (self->window > 0)) { self->remote_busy = FALSE; diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index 040abe714aa3..6dafbb43b529 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c @@ -1018,11 +1018,10 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command) /* * We can now fill the window with additional data frames */ - while (skb_queue_len( &self->txq) > 0) { + while (!skb_queue_empty(&self->txq)) { IRDA_DEBUG(0, "%s(), sending additional frames!\n", __FUNCTION__); - if ((skb_queue_len( &self->txq) > 0) && - (self->window > 0)) { + if (self->window > 0) { skb = skb_dequeue( &self->txq); IRDA_ASSERT(skb != NULL, return;); @@ -1031,8 +1030,7 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command) * bit cleared */ if ((self->window > 1) && - skb_queue_len(&self->txq) > 0) - { + !skb_queue_empty(&self->txq)) { irlap_send_data_primary(self, skb); } else { irlap_send_data_primary_poll(self, skb); diff --git a/net/irda/irttp.c b/net/irda/irttp.c index d091ccf773b3..6602d901f8b1 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -1513,7 +1513,7 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, /* * Check if there is still data segments in the transmit queue */ - if (skb_queue_len(&self->tx_queue) > 0) { + if (!skb_queue_empty(&self->tx_queue)) { if (priority == P_HIGH) { /* * No need to send the queued data, if we are diff --git a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c index cd130c3b72bc..d5bdb53a348f 100644 --- a/net/llc/llc_c_ev.c +++ b/net/llc/llc_c_ev.c @@ -84,7 +84,7 @@ static u16 llc_util_nr_inside_tx_window(struct sock *sk, u8 nr) if (llc->dev->flags & IFF_LOOPBACK) goto out; rc = 1; - if (!skb_queue_len(&llc->pdu_unack_q)) + if (skb_queue_empty(&llc->pdu_unack_q)) goto out; skb = skb_peek(&llc->pdu_unack_q); pdu = llc_pdu_sn_hdr(skb); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index fc456a7aaec3..3405fdf41b93 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -858,7 +858,7 @@ static inline void netlink_rcv_wake(struct sock *sk) { struct netlink_sock *nlk = nlk_sk(sk); - if (!skb_queue_len(&sk->sk_receive_queue)) + if (skb_queue_empty(&sk->sk_receive_queue)) clear_bit(0, &nlk->state); if (!test_bit(0, &nlk->state)) wake_up_interruptible(&nlk->wait); diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 664d0e47374f..7845d045eec4 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -385,7 +385,7 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt) memcpy(q->Stab, RTA_DATA(tb[TCA_RED_STAB-1]), 256); q->qcount = -1; - if (skb_queue_len(&sch->q) == 0) + if (skb_queue_empty(&sch->q)) PSCHED_SET_PASTPERFECT(q->qidlestart); sch_tree_unlock(sch); return 0; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index c420eba4876b..d403e34088ad 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -302,7 +302,7 @@ static void unix_write_space(struct sock *sk) * may receive messages only from that peer. */ static void unix_dgram_disconnected(struct sock *sk, struct sock *other) { - if (skb_queue_len(&sk->sk_receive_queue)) { + if (!skb_queue_empty(&sk->sk_receive_queue)) { skb_queue_purge(&sk->sk_receive_queue); wake_up_interruptible_all(&unix_sk(sk)->peer_wait); @@ -1619,7 +1619,7 @@ static long unix_stream_data_wait(struct sock * sk, long timeo) for (;;) { prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - if (skb_queue_len(&sk->sk_receive_queue) || + if (!skb_queue_empty(&sk->sk_receive_queue) || sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN) || signal_pending(current) || -- cgit v1.2.3 From 6345fdfd190659a2316d18065871245e3a1e0f84 Mon Sep 17 00:00:00 2001 From: Luca T Date: Mon, 11 Jul 2005 01:08:40 -0500 Subject: Input: HID - add a quirk for Aashima Trust (06d6:0025) gamepad Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/usb/input/hid-core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 100b49bd1d3e..271f5bdb8bb3 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1372,6 +1372,9 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_A4TECH 0x09da #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 +#define USB_VENDOR_ID_AASHIMA 0x06D6 +#define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025 + #define USB_VENDOR_ID_CYPRESS 0x04b4 #define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 #define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500 @@ -1524,6 +1527,7 @@ static struct hid_blacklist { { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, + { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, -- cgit v1.2.3 From bc5d04822bd9f34ea93a681f05f5e5683935d574 Mon Sep 17 00:00:00 2001 From: Adam Kropelin Date: Mon, 11 Jul 2005 01:09:32 -0500 Subject: Input: HID - only report events coming from interrupts to hiddev Currently hid-core follows the same code path for input reports regardless of whether they are a result of interrupt transfers or control transfers. That leads to interrupt events erroneously being reported to hiddev for regular control transfers. Prior to 2.6.12 the problem was mitigated by the fact that reporting to hiddev is supressed if the field value has not changed, which is often the case. Said filtering was removed in 2.6.12-rc1 which means any input reports fetched via control transfers result in hiddev interrupt events. This behavior can quickly lead to a feedback loop where a userspace app, in response to interrupt events, issues control transfers which in turn create more interrupt events. This patch prevents input reports that arrive via control transfers from being reported to hiddev as interrupt events. Signed-off-by: Adam Kropelin Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/usb/input/hid-core.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 271f5bdb8bb3..30b1b2dae731 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -789,12 +789,12 @@ static __inline__ int search(__s32 *array, __s32 value, unsigned n) return -1; } -static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs) +static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt, struct pt_regs *regs) { hid_dump_input(usage, value); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_hid_event(hid, field, usage, value, regs); - if (hid->claimed & HID_CLAIMED_HIDDEV) + if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt) hiddev_hid_event(hid, field, usage, value, regs); } @@ -804,7 +804,7 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s * reporting to the layer). */ -static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, struct pt_regs *regs) +static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt, struct pt_regs *regs) { unsigned n; unsigned count = field->report_count; @@ -831,19 +831,19 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u for (n = 0; n < count; n++) { if (HID_MAIN_ITEM_VARIABLE & field->flags) { - hid_process_event(hid, field, &field->usage[n], value[n], regs); + hid_process_event(hid, field, &field->usage[n], value[n], interrupt, regs); continue; } if (field->value[n] >= min && field->value[n] <= max && field->usage[field->value[n] - min].hid && search(value, field->value[n], count)) - hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, regs); + hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt, regs); if (value[n] >= min && value[n] <= max && field->usage[value[n] - min].hid && search(field->value, value[n], count)) - hid_process_event(hid, field, &field->usage[value[n] - min], 1, regs); + hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt, regs); } memcpy(field->value, value, count * sizeof(__s32)); @@ -851,7 +851,7 @@ exit: kfree(value); } -static int hid_input_report(int type, struct urb *urb, struct pt_regs *regs) +static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_regs *regs) { struct hid_device *hid = urb->context; struct hid_report_enum *report_enum = hid->report_enum + type; @@ -899,7 +899,7 @@ static int hid_input_report(int type, struct urb *urb, struct pt_regs *regs) hiddev_report_event(hid, report); for (n = 0; n < report->maxfield; n++) - hid_input_field(hid, report->field[n], data, regs); + hid_input_field(hid, report->field[n], data, interrupt, regs); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_report_event(hid, report); @@ -918,7 +918,7 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs) switch (urb->status) { case 0: /* success */ - hid_input_report(HID_INPUT_REPORT, urb, regs); + hid_input_report(HID_INPUT_REPORT, urb, 1, regs); break; case -ECONNRESET: /* unlink */ case -ENOENT: @@ -1142,7 +1142,7 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs) switch (urb->status) { case 0: /* success */ if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) - hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, regs); + hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs); case -ESHUTDOWN: /* unplug */ case -EILSEQ: /* unplug timectrl on uhci */ unplug = 1; -- cgit v1.2.3 From d58da590451cf6ae75379a2ebf96d3afb8d810d8 Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Fri, 18 Mar 2005 16:43:54 -0500 Subject: [ACPI] S3 Suspend to RAM: fix driver suspend/resume methods Drivers should do this: .suspend() pci_disable_device() .resume() pci_enable_device() http://bugzilla.kernel.org/show_bug.cgi?id=3469 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/net/b44.c | 3 +++ drivers/net/ne2k-pci.c | 3 +++ drivers/pcmcia/yenta_socket.c | 3 +++ drivers/usb/core/hcd-pci.c | 1 + 4 files changed, 10 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 3fe8ba992c38..38844d003e44 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1927,6 +1927,7 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) b44_free_rings(bp); spin_unlock_irq(&bp->lock); + pci_disable_device(pdev); return 0; } @@ -1936,6 +1937,8 @@ static int b44_resume(struct pci_dev *pdev) struct b44 *bp = netdev_priv(dev); pci_restore_state(pdev); + pci_enable_device(pdev); + pci_set_master(pdev); if (!netif_running(dev)) return 0; diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index a1a6c08e7dcf..f1c01ac29102 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -660,6 +660,7 @@ static int ne2k_pci_suspend (struct pci_dev *pdev, pm_message_t state) netif_device_detach(dev); pci_save_state(pdev); + pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; @@ -671,6 +672,8 @@ static int ne2k_pci_resume (struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); + pci_enable_device(pdev); + pci_set_master(pdev); NS8390_init(dev, 1); netif_device_attach(dev); diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 6404d97a12eb..caf7159a54be 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1032,6 +1032,7 @@ static int yenta_dev_suspend (struct pci_dev *dev, pm_message_t state) pci_save_state(dev); pci_read_config_dword(dev, 16*4, &socket->saved_state[0]); pci_read_config_dword(dev, 17*4, &socket->saved_state[1]); + pci_disable_device(dev); /* * Some laptops (IBM T22) do not like us putting the Cardbus @@ -1055,6 +1056,8 @@ static int yenta_dev_resume (struct pci_dev *dev) pci_restore_state(dev); pci_write_config_dword(dev, 16*4, socket->saved_state[0]); pci_write_config_dword(dev, 17*4, socket->saved_state[1]); + pci_enable_device(dev); + pci_set_master(dev); if (socket->type && socket->type->restore_state) socket->type->restore_state(socket); diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 71b4a8d66318..fc056062c960 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -380,6 +380,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev) usb_hc_died (hcd); } + pci_enable_device(dev); return retval; } EXPORT_SYMBOL (usb_hcd_pci_resume); -- cgit v1.2.3 From cf5910bbae81b95bdf120e01fd365ad7b939b143 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 29 Jun 2005 16:53:29 -0700 Subject: [PATCH] USB: add bMaxPacketSize0 attribute to sysfs For some reason this was not there... Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 740cb4c668df..00297f113849 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -196,6 +196,7 @@ usb_descriptor_attr (bDeviceClass, "%02x\n") usb_descriptor_attr (bDeviceSubClass, "%02x\n") usb_descriptor_attr (bDeviceProtocol, "%02x\n") usb_descriptor_attr (bNumConfigurations, "%d\n") +usb_descriptor_attr (bMaxPacketSize0, "%d\n") static struct attribute *dev_attrs[] = { /* current configuration's attributes */ @@ -211,6 +212,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_bDeviceSubClass.attr, &dev_attr_bDeviceProtocol.attr, &dev_attr_bNumConfigurations.attr, + &dev_attr_bMaxPacketSize0.attr, &dev_attr_speed.attr, &dev_attr_devnum.attr, &dev_attr_version.attr, -- cgit v1.2.3 From e8116e84b56f8fa4f091b967a045f47c55095c68 Mon Sep 17 00:00:00 2001 From: Phil Dibowitz Date: Wed, 22 Jun 2005 22:47:13 -0700 Subject: [PATCH] USB Storage: Remove unneeded SC/P This patch removes an unneeded subclass and protocol from the 07af/0005/100 entry in unsual_devs.h as reported by Alfred Ganz . Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 9fcc7bd1fbe4..bd0ab3039bdd 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -697,7 +697,7 @@ UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133, UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100, "Microtech", "USB-SCSI-HD50", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, + US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG ), #ifdef CONFIG_USB_STORAGE_DPCM -- cgit v1.2.3 From 9c8d61783e5bb5e29744b6481a1c67c6e4e8e135 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Mon, 20 Jun 2005 14:29:58 -0700 Subject: [PATCH] USB: khubd: use kthread API Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 32ff32181852..c3e46d24a37e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -47,8 +48,7 @@ static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */ /* Wakes up khubd */ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); -static pid_t khubd_pid = 0; /* PID of khubd */ -static DECLARE_COMPLETION(khubd_exited); +static struct task_struct *khubd_task; /* cycle leds on hubs that aren't blinking for attention */ static int blinkenlights = 0; @@ -2807,23 +2807,16 @@ loop: static int hub_thread(void *__unused) { - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources - */ - - daemonize("khubd"); - allow_signal(SIGKILL); - - /* Send me a signal to get me die (for debugging) */ do { hub_events(); - wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); + wait_event_interruptible(khubd_wait, + !list_empty(&hub_event_list) || + kthread_should_stop()); try_to_freeze(); - } while (!signal_pending(current)); + } while (!kthread_should_stop() || !list_empty(&hub_event_list)); - pr_debug ("%s: khubd exiting\n", usbcore_name); - complete_and_exit(&khubd_exited, 0); + pr_debug("%s: khubd exiting\n", usbcore_name); + return 0; } static struct usb_device_id hub_id_table [] = { @@ -2849,20 +2842,15 @@ static struct usb_driver hub_driver = { int usb_hub_init(void) { - pid_t pid; - if (usb_register(&hub_driver) < 0) { printk(KERN_ERR "%s: can't register hub driver\n", usbcore_name); return -1; } - pid = kernel_thread(hub_thread, NULL, CLONE_KERNEL); - if (pid >= 0) { - khubd_pid = pid; - + khubd_task = kthread_run(hub_thread, NULL, "khubd"); + if (!IS_ERR(khubd_task)) return 0; - } /* Fall through if kernel_thread failed */ usb_deregister(&hub_driver); @@ -2873,12 +2861,7 @@ int usb_hub_init(void) void usb_hub_cleanup(void) { - int ret; - - /* Kill the thread */ - ret = kill_proc(khubd_pid, SIGKILL, 1); - - wait_for_completion(&khubd_exited); + kthread_stop(khubd_task); /* * Hub resources are freed for us by usb_deregister. It calls @@ -2890,7 +2873,6 @@ void usb_hub_cleanup(void) usb_deregister(&hub_driver); } /* usb_hub_cleanup() */ - static int config_descriptors_changed(struct usb_device *udev) { unsigned index; -- cgit v1.2.3 From 8f977e4201fcc0bd512eb01e775894e0a9c34a39 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Mon, 20 Jun 2005 16:45:42 +0100 Subject: [PATCH] USB ftdi_sio: reduce device id table clutter ftdi_sio: Use a single usb_device_id table and detect the type of chip programatically. The table also flags devices requiring special initialization. The patch makes the driver about 10K smaller and makes it easier to add new device IDs. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 707 +++++++++--------------------------------- 1 file changed, 144 insertions(+), 563 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d882fa3ad19a..f843f7358867 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -264,16 +264,26 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.4.2" +#define DRIVER_VERSION "v1.4.3" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober " #define DRIVER_DESC "USB FTDI Serial Converters Driver" static int debug; -static struct usb_device_id id_table_sio [] = { - { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, - { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, - { } /* Terminating entry */ +/* struct ftdi_sio_quirk is used by devices requiring special attention. */ +struct ftdi_sio_quirk { + void (*setup)(struct usb_serial *); /* Special settings during startup. */ +}; + +static void ftdi_USB_UIRT_setup (struct usb_serial *serial); +static void ftdi_HE_TIRA1_setup (struct usb_serial *serial); + +static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { + .setup = ftdi_USB_UIRT_setup, +}; + +static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { + .setup = ftdi_HE_TIRA1_setup, }; /* @@ -288,237 +298,11 @@ static struct usb_device_id id_table_sio [] = { * the bcdDevice value is used to differentiate FT232BM and FT245BM from * the earlier FT8U232AM and FT8U232BM. For now, include all known VID/PID * combinations in both tables. - * FIXME: perhaps bcdDevice can also identify 12MHz devices, but I don't know - * if those ever went into mass production. [Ian Abbott] + * FIXME: perhaps bcdDevice can also identify 12MHz FT8U232AM devices, + * but I don't know if those ever went into mass production. [Ian Abbott] */ -static struct usb_device_id id_table_8U232AM [] = { - { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) }, - { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, - { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, - { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_547_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_633_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_631_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_635_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_640_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(OCT_VID, OCT_US101_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_1, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0, 0x3ff) }, - { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID, 0, 0x3ff) }, - { } /* Terminating entry */ -}; - - -static struct usb_device_id id_table_FT232BM [] = { - { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_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) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_547_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_633_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_631_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_635_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_640_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_PIEGROUP_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(OCT_VID, OCT_US101_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_1, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, - { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0x400, 0xffff) }, - { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID, 0x400, 0xffff) }, - { } /* Terminating entry */ -}; - - -static struct usb_device_id id_table_USB_UIRT [] = { - { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) }, - { } /* Terminating entry */ -}; - - -static struct usb_device_id id_table_HE_TIRA1 [] = { - { USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) }, - { } /* Terminating entry */ -}; - - -static struct usb_device_id id_table_FT2232C[] = { - { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, - { } /* Terminating entry */ -}; - static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, @@ -540,14 +324,14 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, @@ -597,35 +381,37 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) }, { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) }, { USB_DEVICE(OCT_VID, OCT_US101_PID) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) }, - { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID), + .driver_info = (kernel_ulong_t)&ftdi_HE_TIRA1_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID), + .driver_info = (kernel_ulong_t)&ftdi_USB_UIRT_quirk }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) }, { USB_DEVICE(FTDI_VID, PROTEGO_R2X0) }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) }, - { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, + { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, @@ -642,7 +428,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, { } /* Terminating entry */ }; @@ -705,12 +491,8 @@ struct ftdi_private { ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP ) /* function prototypes for a FTDI serial converter */ -static int ftdi_SIO_startup (struct usb_serial *serial); -static int ftdi_8U232AM_startup (struct usb_serial *serial); -static int ftdi_FT232BM_startup (struct usb_serial *serial); -static int ftdi_FT2232C_startup (struct usb_serial *serial); -static int ftdi_USB_UIRT_startup (struct usb_serial *serial); -static int ftdi_HE_TIRA1_startup (struct usb_serial *serial); +static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id); +static int ftdi_sio_attach (struct usb_serial *serial); static void ftdi_shutdown (struct usb_serial *serial); static int ftdi_open (struct usb_serial_port *port, struct file *filp); static void ftdi_close (struct usb_serial_port *port, struct file *filp); @@ -733,66 +515,16 @@ static unsigned short int ftdi_232am_baud_to_divisor (int baud); static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base); static __u32 ftdi_232bm_baud_to_divisor (int baud); -static struct usb_serial_device_type ftdi_SIO_device = { - .owner = THIS_MODULE, - .name = "FTDI SIO", - .id_table = id_table_sio, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_SIO_startup, - .shutdown = ftdi_shutdown, -}; - -static struct usb_serial_device_type ftdi_8U232AM_device = { - .owner = THIS_MODULE, - .name = "FTDI 8U232AM Compatible", - .id_table = id_table_8U232AM, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_8U232AM_startup, - .shutdown = ftdi_shutdown, -}; - -static struct usb_serial_device_type ftdi_FT232BM_device = { +static struct usb_serial_device_type ftdi_sio_device = { .owner = THIS_MODULE, - .name = "FTDI FT232BM Compatible", - .id_table = id_table_FT232BM, + .name = "FTDI USB Serial Device", + .short_name = "ftdi_sio", + .id_table = id_table_combined, .num_interrupt_in = 0, .num_bulk_in = 1, .num_bulk_out = 1, .num_ports = 1, + .probe = ftdi_sio_probe, .open = ftdi_open, .close = ftdi_close, .throttle = ftdi_throttle, @@ -807,91 +539,10 @@ static struct usb_serial_device_type ftdi_FT232BM_device = { .ioctl = ftdi_ioctl, .set_termios = ftdi_set_termios, .break_ctl = ftdi_break_ctl, - .attach = ftdi_FT232BM_startup, + .attach = ftdi_sio_attach, .shutdown = ftdi_shutdown, }; -static struct usb_serial_device_type ftdi_FT2232C_device = { - .owner = THIS_MODULE, - .name = "FTDI FT2232C Compatible", - .id_table = id_table_FT2232C, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_FT2232C_startup, - .shutdown = ftdi_shutdown, -}; - -static struct usb_serial_device_type ftdi_USB_UIRT_device = { - .owner = THIS_MODULE, - .name = "USB-UIRT Infrared Tranceiver", - .id_table = id_table_USB_UIRT, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_USB_UIRT_startup, - .shutdown = ftdi_shutdown, -}; - -/* The TIRA1 is based on a FT232BM which requires a fixed baud rate of 100000 - * and which requires RTS-CTS to be enabled. */ -static struct usb_serial_device_type ftdi_HE_TIRA1_device = { - .owner = THIS_MODULE, - .name = "Home-Electronics TIRA-1 IR Transceiver", - .id_table = id_table_HE_TIRA1, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_HE_TIRA1_startup, - .shutdown = ftdi_shutdown, -}; - - #define WDR_TIMEOUT 5000 /* default urb timeout */ @@ -1212,6 +863,59 @@ check_and_exit: } /* set_serial_info */ +/* Determine type of FTDI chip based on USB config and descriptor. */ +static void ftdi_determine_type(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + struct usb_device *udev = serial->dev; + unsigned version; + unsigned interfaces; + + /* Assume it is not the original SIO device for now. */ + priv->baud_base = 48000000 / 16; + priv->write_offset = 0; + + version = le16_to_cpu(udev->descriptor.bcdDevice); + interfaces = udev->actconfig->desc.bNumInterfaces; + dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __FUNCTION__, + version, interfaces); + if (interfaces > 1) { + int inter; + + /* Multiple interfaces. Assume FT2232C. */ + priv->chip_type = FT2232C; + /* Determine interface code. */ + inter = serial->interface->altsetting->desc.bInterfaceNumber; + if (inter == 0) { + priv->interface = PIT_SIOA; + } else { + priv->interface = PIT_SIOB; + } + /* BM-type devices have a bug where bcdDevice gets set + * to 0x200 when iSerialNumber is 0. */ + if (version < 0x500) { + dbg("%s: something fishy - bcdDevice too low for multi-interface device", + __FUNCTION__); + } + } else if (version < 0x200) { + /* Old device. Assume its the original SIO. */ + priv->chip_type = SIO; + priv->baud_base = 12000000 / 16; + priv->write_offset = 1; + } else if (version < 0x400) { + /* Assume its an FT8U232AM (or FT8U245AM) */ + /* (It might be a BM because of the iSerialNumber bug, + * but it will still work as an AM device.) */ + priv->chip_type = FT8U232AM; + } else { + /* Assume its an FT232BM (or FT245BM) */ + priv->chip_type = FT232BM; + } + info("Detected %s", ftdi_chip_name[priv->chip_type]); +} + + /* * *************************************************************************** * Sysfs Attribute @@ -1355,12 +1059,20 @@ static void remove_sysfs_attrs(struct usb_serial *serial) * *************************************************************************** */ -/* Common startup subroutine */ -/* Called from ftdi_SIO_startup, etc. */ -static int ftdi_common_startup (struct usb_serial *serial) +/* Probe function to check for special devices */ +static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id) +{ + usb_set_serial_data(serial, (void *)id->driver_info); + + return (0); +} + +/* attach subroutine */ +static int ftdi_sio_attach (struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; struct ftdi_private *priv; + struct ftdi_sio_quirk *quirk; dbg("%s",__FUNCTION__); @@ -1400,150 +1112,49 @@ static int ftdi_common_startup (struct usb_serial *serial) port->bulk_out_buffer = NULL; usb_set_serial_port_data(serial->port[0], priv); - - return (0); -} - - -/* Startup for the SIO chip */ -/* Called from usbserial:serial_probe */ -static int ftdi_SIO_startup (struct usb_serial *serial) -{ - struct ftdi_private *priv; - int err; - dbg("%s",__FUNCTION__); - - err = ftdi_common_startup(serial); - if (err){ - return (err); - } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chip_type = SIO; - priv->baud_base = 12000000 / 16; - priv->write_offset = 1; - - return (0); -} - -/* Startup for the 8U232AM chip */ -/* Called from usbserial:serial_probe */ -static int ftdi_8U232AM_startup (struct usb_serial *serial) -{ /* ftdi_8U232AM_startup */ - struct ftdi_private *priv; - int err; - - dbg("%s",__FUNCTION__); - err = ftdi_common_startup(serial); - if (err){ - return (err); - } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chip_type = FT8U232AM; - priv->baud_base = 48000000 / 2; /* Would be / 16, but FTDI supports 0.125, 0.25 and 0.5 divisor fractions! */ - + ftdi_determine_type (serial->port[0]); create_sysfs_attrs(serial); - - return (0); -} /* ftdi_8U232AM_startup */ -/* Startup for the FT232BM chip */ -/* Called from usbserial:serial_probe */ -static int ftdi_FT232BM_startup (struct usb_serial *serial) -{ /* ftdi_FT232BM_startup */ - struct ftdi_private *priv; - int err; - - dbg("%s",__FUNCTION__); - err = ftdi_common_startup(serial); - if (err){ - return (err); + /* Check for device requiring special set up. */ + quirk = (struct ftdi_sio_quirk *)usb_get_serial_data(serial); + if (quirk && quirk->setup) { + quirk->setup(serial); } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chip_type = FT232BM; - priv->baud_base = 48000000 / 2; /* Would be / 16, but FT232BM supports multiple of 0.125 divisor fractions! */ - create_sysfs_attrs(serial); - return (0); -} /* ftdi_FT232BM_startup */ +} /* ftdi_sio_attach */ -/* Startup for the FT2232C chip */ -/* Called from usbserial:serial_probe */ -static int ftdi_FT2232C_startup (struct usb_serial *serial) -{ /* ftdi_FT2232C_startup */ - struct ftdi_private *priv; - int err; - int inter; - - dbg("%s",__FUNCTION__); - err = ftdi_common_startup(serial); - if (err){ - return (err); - } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chip_type = FT2232C; - inter = serial->interface->altsetting->desc.bInterfaceNumber; - - if (inter) { - priv->interface = PIT_SIOB; - } - else { - priv->interface = PIT_SIOA; - } - priv->baud_base = 48000000 / 2; /* Would be / 16, but FT2232C supports multiple of 0.125 divisor fractions! */ - - create_sysfs_attrs(serial); - - return (0); -} /* ftdi_FT2232C_startup */ -/* Startup for the USB-UIRT device, which requires hardwired baudrate (38400 gets mapped to 312500) */ +/* Setup for the USB-UIRT device, which requires hardwired + * baudrate (38400 gets mapped to 312500) */ /* Called from usbserial:serial_probe */ -static int ftdi_USB_UIRT_startup (struct usb_serial *serial) -{ /* ftdi_USB_UIRT_startup */ +static void ftdi_USB_UIRT_setup (struct usb_serial *serial) +{ struct ftdi_private *priv; - int err; dbg("%s",__FUNCTION__); - err = ftdi_8U232AM_startup(serial); - if (err){ - return (err); - } priv = usb_get_serial_port_data(serial->port[0]); priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 77; priv->force_baud = B38400; - - return (0); -} /* ftdi_USB_UIRT_startup */ +} /* ftdi_USB_UIRT_setup */ -/* Startup for the HE-TIRA1 device, which requires hardwired - * baudrate (38400 gets mapped to 100000) */ -static int ftdi_HE_TIRA1_startup (struct usb_serial *serial) -{ /* ftdi_HE_TIRA1_startup */ +/* Setup for the HE-TIRA1 device, which requires hardwired + * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled. */ +static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) +{ struct ftdi_private *priv; - int err; dbg("%s",__FUNCTION__); - err = ftdi_FT232BM_startup(serial); - if (err){ - return (err); - } priv = usb_get_serial_port_data(serial->port[0]); priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 240; priv->force_baud = B38400; priv->force_rtscts = 1; - - return (0); -} /* ftdi_HE_TIRA1_startup */ +} /* ftdi_HE_TIRA1_setup */ /* ftdi_shutdown is called from usbserial:usb_serial_disconnect @@ -2516,24 +2127,9 @@ static int __init ftdi_init (void) int retval; dbg("%s", __FUNCTION__); - retval = usb_serial_register(&ftdi_SIO_device); - if (retval) - goto failed_SIO_register; - retval = usb_serial_register(&ftdi_8U232AM_device); - if (retval) - goto failed_8U232AM_register; - retval = usb_serial_register(&ftdi_FT232BM_device); - if (retval) - goto failed_FT232BM_register; - retval = usb_serial_register(&ftdi_FT2232C_device); - if (retval) - goto failed_FT2232C_register; - retval = usb_serial_register(&ftdi_USB_UIRT_device); - if (retval) - goto failed_USB_UIRT_register; - retval = usb_serial_register(&ftdi_HE_TIRA1_device); + retval = usb_serial_register(&ftdi_sio_device); if (retval) - goto failed_HE_TIRA1_register; + goto failed_sio_register; retval = usb_register(&ftdi_driver); if (retval) goto failed_usb_register; @@ -2541,18 +2137,8 @@ static int __init ftdi_init (void) info(DRIVER_VERSION ":" DRIVER_DESC); return 0; failed_usb_register: - usb_serial_deregister(&ftdi_HE_TIRA1_device); -failed_HE_TIRA1_register: - usb_serial_deregister(&ftdi_USB_UIRT_device); -failed_USB_UIRT_register: - usb_serial_deregister(&ftdi_FT2232C_device); -failed_FT2232C_register: - usb_serial_deregister(&ftdi_FT232BM_device); -failed_FT232BM_register: - usb_serial_deregister(&ftdi_8U232AM_device); -failed_8U232AM_register: - usb_serial_deregister(&ftdi_SIO_device); -failed_SIO_register: + usb_serial_deregister(&ftdi_sio_device); +failed_sio_register: return retval; } @@ -2563,12 +2149,7 @@ static void __exit ftdi_exit (void) dbg("%s", __FUNCTION__); usb_deregister (&ftdi_driver); - usb_serial_deregister (&ftdi_HE_TIRA1_device); - usb_serial_deregister (&ftdi_USB_UIRT_device); - usb_serial_deregister (&ftdi_FT2232C_device); - usb_serial_deregister (&ftdi_FT232BM_device); - usb_serial_deregister (&ftdi_8U232AM_device); - usb_serial_deregister (&ftdi_SIO_device); + usb_serial_deregister (&ftdi_sio_device); } -- cgit v1.2.3 From 7e33ae67815372a93e8e77624fd47e39a986415d Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Mon, 20 Jun 2005 17:10:19 +0100 Subject: [PATCH] USB ftdi_sio: remove redundant TIOCMBIS and TIOCMBIC code ftdi_sio: Remove redundant handling of TIOCMBIS and TIOCMBIC ioctls as they are handled in the tty layer and never reach this driver. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 47 ------------------------------------------- 1 file changed, 47 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index f843f7358867..aad2f4d0e09c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1985,53 +1985,6 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne /* Based on code from acm.c and others */ switch (cmd) { - case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */ - dbg("%s TIOCMBIS", __FUNCTION__); - if (get_user(mask, (unsigned long __user *) arg)) - return -EFAULT; - if (mask & TIOCM_DTR){ - if ((ret = set_dtr(port, HIGH)) < 0) { - err("Urb to set DTR failed"); - return(ret); - } - } - if (mask & TIOCM_RTS) { - if ((ret = set_rts(port, HIGH)) < 0){ - err("Urb to set RTS failed"); - return(ret); - } - } - return(0); - break; - - case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */ - dbg("%s TIOCMBIC", __FUNCTION__); - if (get_user(mask, (unsigned long __user *) arg)) - return -EFAULT; - if (mask & TIOCM_DTR){ - if ((ret = set_dtr(port, LOW)) < 0){ - err("Urb to unset DTR failed"); - return(ret); - } - } - if (mask & TIOCM_RTS) { - if ((ret = set_rts(port, LOW)) < 0){ - err("Urb to unset RTS failed"); - return(ret); - } - } - return(0); - break; - - /* - * I had originally implemented TCSET{A,S}{,F,W} and - * TCGET{A,S} here separately, however when testing I - * found that the higher layers actually do the termios - * conversions themselves and pass the call onto - * ftdi_sio_set_termios. - * - */ - case TIOCGSERIAL: /* gets serial port data */ return get_serial_info(port, (struct serial_struct __user *) arg); -- cgit v1.2.3 From 16966f2ab7db7366855d1267071a3138ae127ff6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 29 Jun 2005 16:53:29 -0700 Subject: [PATCH] USB: fix ftdi_sio compiler warnings Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index aad2f4d0e09c..0b03ddab53d9 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1978,8 +1978,6 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne { struct ftdi_private *priv = usb_get_serial_port_data(port); - int ret, mask; - dbg("%s cmd 0x%04x", __FUNCTION__, cmd); /* Based on code from acm.c and others */ -- cgit v1.2.3 From 322a95bc8eba889d2f9d7222936d682c9aad8294 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 23 Jun 2005 09:20:50 +0200 Subject: [PATCH] USB ATM: line speed measured in Kb not Kib Spotted by David Woodhouse. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 2 +- drivers/usb/atm/speedtch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index cbd4a7d25d0b..8e184e2641cb 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -427,7 +427,7 @@ static void cxacru_poll_status(struct cxacru_data *instance) atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424; atm_dev->signal = ATM_PHY_SIG_FOUND; - dev_info(dev, "ADSL line: up (%d Kib/s down | %d Kib/s up)\n", + dev_info(dev, "ADSL line: up (%d kb/s down | %d kb/s up)\n", buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]); break; diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 6a6eaa2a3b1c..992db1c16838 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -480,7 +480,7 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) atm_dev->signal = ATM_PHY_SIG_FOUND; atm_info(usbatm, - "ADSL line is up (%d Kib/s down | %d Kib/s up)\n", + "ADSL line is up (%d kb/s down | %d kb/s up)\n", down_speed, up_speed); } break; -- cgit v1.2.3 From cd5c08fb7b0d960b7cd48bc977feee7b3bd8b046 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 23 Jun 2005 09:23:10 +0200 Subject: [PATCH] USB ATM: robustify poll throttling No functional change, but less likely to break in the future. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 992db1c16838..03a0e99a4267 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -430,13 +430,11 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) ret = speedtch_read_status(instance); if (ret < 0) { atm_warn(usbatm, "error %d fetching device status\n", ret); - if (instance->poll_delay < MAX_POLL_DELAY) - instance->poll_delay *= 2; + instance->poll_delay = min(2 * instance->poll_delay, MAX_POLL_DELAY); return; } - if (instance->poll_delay > MIN_POLL_DELAY) - instance->poll_delay /= 2; + instance->poll_delay = max(instance->poll_delay / 2, MIN_POLL_DELAY); atm_dbg(usbatm, "%s: line state %02x\n", __func__, buf[OFFSET_7]); -- cgit v1.2.3 From 1a7aad15ff93be104c8e0851a43b94f8ccd92225 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 23 Jun 2005 09:37:56 +0200 Subject: [PATCH] USB ATM: fix line resync logic We map states 0x00 and 0x10 to the ATM_PHY_SIG_LOST flag. The current logic fails to resync the line if we get state 0x10 followed by 0x00, since we only resync the line when the state is 0x00 and the flag changed. Doubly fixed by (1) always resyncing the line when the state is 0x00 even if the state didn't change, and (2) keeping track of the last state, not just the flag. We do (2) as well as (1) in order to get better log messages. This is a tweaked version of the original patch by Aurelio Arroyo. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 55 +++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 27 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 03a0e99a4267..d0cbbb7f0385 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -100,6 +100,8 @@ struct speedtch_instance_data { struct work_struct status_checker; + unsigned char last_status; + int poll_delay; /* milliseconds */ struct timer_list resubmit_timer; @@ -423,7 +425,8 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) struct usbatm_data *usbatm = instance->usbatm; struct atm_dev *atm_dev = usbatm->atm_dev; unsigned char *buf = instance->scratch_buffer; - int ret; + int down_speed, up_speed, ret; + unsigned char status; atm_dbg(usbatm, "%s entered\n", __func__); @@ -436,37 +439,34 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) instance->poll_delay = max(instance->poll_delay / 2, MIN_POLL_DELAY); - atm_dbg(usbatm, "%s: line state %02x\n", __func__, buf[OFFSET_7]); + status = buf[OFFSET_7]; - switch (buf[OFFSET_7]) { - case 0: - if (atm_dev->signal != ATM_PHY_SIG_LOST) { + atm_dbg(usbatm, "%s: line state %02x\n", __func__, status); + + if ((status != instance->last_status) || !status) { + switch (status) { + case 0: atm_dev->signal = ATM_PHY_SIG_LOST; - atm_info(usbatm, "ADSL line is down\n"); - /* It'll never resync again unless we ask it to... */ + if (instance->last_status) + atm_info(usbatm, "ADSL line is down\n"); + /* It may never resync again unless we ask it to... */ ret = speedtch_start_synchro(instance); - } - break; + break; - case 0x08: - if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) { + case 0x08: atm_dev->signal = ATM_PHY_SIG_UNKNOWN; atm_info(usbatm, "ADSL line is blocked?\n"); - } - break; + break; - case 0x10: - if (atm_dev->signal != ATM_PHY_SIG_LOST) { + case 0x10: atm_dev->signal = ATM_PHY_SIG_LOST; atm_info(usbatm, "ADSL line is synchronising\n"); - } - break; + break; - case 0x20: - if (atm_dev->signal != ATM_PHY_SIG_FOUND) { - int down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8) + case 0x20: + down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8) | (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24); - int up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8) + up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8) | (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24); if (!(down_speed & 0x0000ffff) && !(up_speed & 0x0000ffff)) { @@ -480,15 +480,15 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) atm_info(usbatm, "ADSL line is up (%d kb/s down | %d kb/s up)\n", down_speed, up_speed); - } - break; + break; - default: - if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) { + default: atm_dev->signal = ATM_PHY_SIG_UNKNOWN; - atm_info(usbatm, "Unknown line state %02x\n", buf[OFFSET_7]); + atm_info(usbatm, "Unknown line state %02x\n", status); + break; } - break; + + instance->last_status = status; } } @@ -728,6 +728,7 @@ static int speedtch_bind(struct usbatm_data *usbatm, instance->status_checker.timer.function = speedtch_status_poll; instance->status_checker.timer.data = (unsigned long)instance; + instance->last_status = 0xff; instance->poll_delay = MIN_POLL_DELAY; init_timer(&instance->resubmit_timer); -- cgit v1.2.3 From ead99eb00190a274e3b3666ecd431be12c2b7888 Mon Sep 17 00:00:00 2001 From: Thomas Winischhofer Date: Fri, 24 Jun 2005 18:44:20 +0200 Subject: [PATCH] USB: SiS USB Makefile fixes although 2.6.12 now contains the sisusb driver, it failes to build this driver due to a missing patch of the Makefile. From: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index d79cd218a551..284f95723eea 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_USB_RIO500) += misc/ obj-$(CONFIG_USB_TEST) += misc/ obj-$(CONFIG_USB_USS720) += misc/ obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ +obj-$(CONFIG_USB_SISUSBVGA) += misc/ obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ -- cgit v1.2.3 From ae0d6cceb20eec57e7196c22999c62c465ffd5bf Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Sat, 25 Jun 2005 14:32:59 -0700 Subject: [PATCH] USB: Patch to make usbmon to print control setup packets Make usbmon to print Setup packets of Control transfers. This is useful when debugging enumeration issues. This is a change to the trace format which is not fully compatible. A parser has to look at the data length word now. If that word is a character like 's', read setup packet before proceeding with data. I decided not to bump the API tag for this because not many such parsers exist at this point. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/usbmon.txt | 29 ++++++++++++++++++-------- drivers/usb/mon/mon_text.c | 48 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 13 deletions(-) (limited to 'drivers/usb') diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index 2f8431f92b77..f1896ee3bb2a 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt @@ -101,6 +101,13 @@ Here is the list of words, from left to right: or 3 and 2 positions, correspondingly. - URB Status. This field makes no sense for submissions, but is present to help scripts with parsing. In error case, it contains the error code. + In case of a setup packet, it contains a Setup Tag. If scripts read a number + in this field, the proceed to read Data Length. Otherwise, they read + the setup packet before reading the Data Length. +- Setup packet, if present, consists of 5 words: one of each for bmRequestType, + bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0. + These words are safe to decode if Setup Tag was 's'. Otherwise, the setup + packet was present, but not captured, and the fields contain filler. - Data Length. This is the actual length in the URB. - Data tag. The usbmon may not always capture data, even if length is nonzero. Only if tag is '=', the data words are present. @@ -125,25 +132,31 @@ class ParsedLine { String data_str = st.nextToken(); int len = data_str.length() / 2; int i; + int b; // byte is signed, apparently?! XXX for (i = 0; i < len; i++) { - data[data_len] = Byte.parseByte( - data_str.substring(i*2, i*2 + 2), - 16); + // data[data_len] = Byte.parseByte( + // data_str.substring(i*2, i*2 + 2), + // 16); + b = Integer.parseInt( + data_str.substring(i*2, i*2 + 2), + 16); + if (b >= 128) + b *= -1; + data[data_len] = (byte) b; data_len++; } } } } -This format is obviously deficient. For example, the setup packet for control -transfers is not delivered. This will change in the future. +This format may be changed in the future. Examples: -An input control transfer to get a port status: +An input control transfer to get a port status. -d74ff9a0 2640288196 S Ci:001:00 -115 4 < -d74ff9a0 2640288202 C Ci:001:00 0 4 = 01010100 +d5ea89a0 3575914555 S Ci:001:00 s a3 00 0000 0003 0004 4 < +d5ea89a0 3575914560 C Ci:001:00 0 4 = 01050000 An output bulk transfer to send a SCSI command 0x5E in a 31-byte Bulk wrapper to a storage device at address 5: diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 755a4570477f..26266b30028e 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -18,12 +18,17 @@ */ #define DATA_MAX 32 +/* + * Defined by USB 2.0 clause 9.3, table 9.2. + */ +#define SETUP_MAX 8 + /* * This limit exists to prevent OOMs when the user process stops reading. */ #define EVENT_MAX 25 -#define PRINTF_DFL 120 +#define PRINTF_DFL 130 struct mon_event_text { struct list_head e_link; @@ -33,7 +38,9 @@ struct mon_event_text { unsigned int tstamp; int length; /* Depends on type: xfer length or act length */ int status; + char setup_flag; char data_flag; + unsigned char setup[SETUP_MAX]; unsigned char data[DATA_MAX]; }; @@ -64,6 +71,22 @@ static void mon_text_dtor(void *, kmem_cache_t *, unsigned long); * This is called with the whole mon_bus locked, so no additional lock. */ +static inline char mon_text_get_setup(struct mon_event_text *ep, + struct urb *urb, char ev_type) +{ + + if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + return '-'; + + if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP) + return 'D'; + if (urb->setup_packet == NULL) + return 'Z'; /* '0' would be not as pretty. */ + + memcpy(ep->setup, urb->setup_packet, SETUP_MAX); + return 0; +} + static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, int len, char ev_type) { @@ -90,7 +113,6 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, /* * 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. */ @@ -144,6 +166,7 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, /* Collecting status makes debugging sense for submits, too */ ep->status = urb->status; + ep->setup_flag = mon_text_get_setup(ep, urb, ev_type); ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type); rp->nevents++; @@ -299,10 +322,25 @@ static ssize_t mon_text_read(struct file *file, char __user *buf, default: /* PIPE_BULK */ utype = 'B'; } cnt += snprintf(pbuf + cnt, limit - cnt, - "%lx %u %c %c%c:%03u:%02u %d %d", + "%lx %u %c %c%c:%03u:%02u", ep->id, ep->tstamp, ep->type, - utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe), - ep->status, ep->length); + utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + + if (ep->setup_flag == 0) { /* Setup packet is present and captured */ + cnt += snprintf(pbuf + cnt, limit - cnt, + " s %02x %02x %04x %04x %04x", + ep->setup[0], + ep->setup[1], + (ep->setup[3] << 8) | ep->setup[2], + (ep->setup[5] << 8) | ep->setup[4], + (ep->setup[7] << 8) | ep->setup[6]); + } else if (ep->setup_flag != '-') { /* Unable to capture setup packet */ + cnt += snprintf(pbuf + cnt, limit - cnt, + " %c __ __ ____ ____ ____", ep->setup_flag); + } else { /* No setup for this kind of URB */ + cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->status); + } + cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->length); if ((data_len = ep->length) > 0) { if (ep->data_flag == 0) { -- cgit v1.2.3 From 17f8bb7312fa9b00f80c3c0f8d5a5d698eb97bbd Mon Sep 17 00:00:00 2001 From: Olav Kongas Date: Thu, 23 Jun 2005 20:12:24 +0300 Subject: [PATCH] USB: isp116x-hcd cleanup Sorry that it took so long. Here comes a cleanup patch that addresses the remarks by Alexey Dobriyan about gregkh-usb-usb-isp116x-hcd-add.patch EXCEPT the remark about the typecasting of mem_flags argument for kcalloc; this will be addressed in a later patch. OlavCleanup of isp116x-hcd. Signed off by: Olav Kongas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp116x-hcd.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index ff0a168e8eed..3f2cea21efc5 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -17,7 +17,7 @@ * The driver basically works. A number of people have used it with a range * of devices. * - *The driver passes all usbtests 1-14. + * The driver passes all usbtests 1-14. * * Suspending/resuming of root hub via sysfs works. Remote wakeup works too. * And suspending/resuming of platform device works too. Suspend/resume @@ -229,7 +229,7 @@ static void preproc_atl_queue(struct isp116x *isp116x) struct isp116x_ep *ep; struct urb *urb; struct ptd *ptd; - u16 toggle, dir, len; + u16 toggle = 0, dir = PTD_DIR_SETUP, len; for (ep = isp116x->atl_active; ep; ep = ep->active) { BUG_ON(list_empty(&ep->hep->urb_list)); @@ -251,8 +251,6 @@ static void preproc_atl_queue(struct isp116x *isp116x) dir = PTD_DIR_OUT; break; case USB_PID_SETUP: - toggle = 0; - dir = PTD_DIR_SETUP; len = sizeof(struct usb_ctrlrequest); ep->data = urb->setup_packet; break; @@ -264,11 +262,9 @@ static void preproc_atl_queue(struct isp116x *isp116x) ? PTD_DIR_OUT : PTD_DIR_IN; break; default: - /* To please gcc */ - toggle = dir = 0; ERR("%s %d: ep->nextpid %d\n", __func__, __LINE__, ep->nextpid); - BUG_ON(1); + BUG(); } ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK | PTD_TOGGLE(toggle); @@ -1054,7 +1050,7 @@ static int isp116x_hub_control(struct usb_hcd *hcd, break; case GetHubStatus: DBG("GetHubStatus\n"); - *(__le32 *) buf = cpu_to_le32(0); + *(__le32 *) buf = 0; break; case GetPortStatus: DBG("GetPortStatus\n"); @@ -1810,9 +1806,9 @@ static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase) ret = usb_suspend_device(hcd->self.root_hub, state); if (!ret) { dev->power.power_state = state; - INFO("%s suspended\n", (char *)hcd_name); + INFO("%s suspended\n", hcd_name); } else - ERR("%s suspend failed\n", (char *)hcd_name); + ERR("%s suspend failed\n", hcd_name); return ret; } -- cgit v1.2.3 From 5db539e49fc7471e23bf3c94ca304f008cb7b7f3 Mon Sep 17 00:00:00 2001 From: Olav Kongas Date: Thu, 23 Jun 2005 20:25:36 +0300 Subject: [PATCH] USB: Fix kmalloc's flags type in USB Greg, This patch fixes the kmalloc() flags argument type in USB subsystem; hopefully all of its occurences. The patch was made against patch-2.6.12-git2 from Jun 20. Cleanup of flags for kmalloc() in USB subsystem. Signed-off-by: Olav Kongas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/buffer.c | 2 +- drivers/usb/core/hcd.c | 2 +- drivers/usb/core/hcd.h | 8 ++++---- drivers/usb/core/message.c | 2 +- drivers/usb/core/urb.c | 4 ++-- drivers/usb/core/usb.c | 2 +- drivers/usb/gadget/dummy_hcd.c | 9 +++++---- drivers/usb/gadget/ether.c | 18 +++++++++--------- drivers/usb/gadget/goku_udc.c | 6 +++--- drivers/usb/gadget/lh7a40x_udc.c | 6 +++--- drivers/usb/gadget/net2280.c | 6 +++--- drivers/usb/gadget/omap_udc.c | 6 +++--- drivers/usb/gadget/pxa2xx_udc.c | 6 +++--- drivers/usb/gadget/zero.c | 8 ++++---- drivers/usb/host/ehci-hcd.c | 2 +- drivers/usb/host/ehci-q.c | 2 +- drivers/usb/host/ehci-sched.c | 19 +++++++++++-------- drivers/usb/host/hc_crisv10.c | 10 ++++++---- drivers/usb/host/isp116x-hcd.c | 4 ++-- drivers/usb/host/ohci-hcd.c | 2 +- drivers/usb/host/ohci-mem.c | 4 ++-- drivers/usb/host/sl811-hcd.c | 2 +- drivers/usb/host/uhci-q.c | 2 +- drivers/usb/net/kaweth.c | 4 ++-- include/linux/usb.h | 8 ++++---- include/linux/usb_gadget.h | 12 ++++++------ 26 files changed, 81 insertions(+), 75 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index b7827df21f48..fc15b4acc8af 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -106,7 +106,7 @@ void hcd_buffer_destroy (struct usb_hcd *hcd) void *hcd_buffer_alloc ( struct usb_bus *bus, size_t size, - int mem_flags, + unsigned mem_flags, dma_addr_t *dma ) { diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 83e732a0d64a..8616356f55e8 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1112,7 +1112,7 @@ static void urb_unlink (struct urb *urb) * expects usb_submit_urb() to have sanity checked and conditioned all * inputs in the urb */ -static int hcd_submit_urb (struct urb *urb, int mem_flags) +static int hcd_submit_urb (struct urb *urb, unsigned mem_flags) { int status; struct usb_hcd *hcd = urb->dev->bus->hcpriv; diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 8dc13cde2f73..67db4a999b93 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -142,12 +142,12 @@ struct hcd_timeout { /* timeouts we allocate */ struct usb_operations { int (*get_frame_number) (struct usb_device *usb_dev); - int (*submit_urb) (struct urb *urb, int mem_flags); + int (*submit_urb) (struct urb *urb, unsigned mem_flags); int (*unlink_urb) (struct urb *urb, int status); /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */ void *(*buffer_alloc)(struct usb_bus *bus, size_t size, - int mem_flags, + unsigned mem_flags, dma_addr_t *dma); void (*buffer_free)(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); @@ -200,7 +200,7 @@ struct hc_driver { int (*urb_enqueue) (struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - int mem_flags); + unsigned mem_flags); int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); /* hw synch, freeing endpoint resources that urb_dequeue can't */ @@ -247,7 +247,7 @@ int hcd_buffer_create (struct usb_hcd *hcd); void hcd_buffer_destroy (struct usb_hcd *hcd); void *hcd_buffer_alloc (struct usb_bus *bus, size_t size, - int mem_flags, dma_addr_t *dma); + unsigned mem_flags, dma_addr_t *dma); void hcd_buffer_free (struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index f50aaf25c98e..a428ef479bd7 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -320,7 +320,7 @@ int usb_sg_init ( struct scatterlist *sg, int nents, size_t length, - int mem_flags + unsigned mem_flags ) { int i; diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 0faf18d511de..c0feee25ff0a 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -60,7 +60,7 @@ void usb_init_urb(struct urb *urb) * * The driver must call usb_free_urb() when it is finished with the urb. */ -struct urb *usb_alloc_urb(int iso_packets, int mem_flags) +struct urb *usb_alloc_urb(int iso_packets, unsigned mem_flags) { struct urb *urb; @@ -224,7 +224,7 @@ struct urb * usb_get_urb(struct urb *urb) * GFP_NOIO, unless b) or c) apply * */ -int usb_submit_urb(struct urb *urb, int mem_flags) +int usb_submit_urb(struct urb *urb, unsigned mem_flags) { int pipe, temp, max; struct usb_device *dev; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index a3c42203213a..7713a605fce7 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1129,7 +1129,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, void *usb_buffer_alloc ( struct usb_device *dev, size_t size, - int mem_flags, + unsigned mem_flags, dma_addr_t *dma ) { diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 4d692670f288..583db7c38cf1 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -470,7 +470,7 @@ static int dummy_disable (struct usb_ep *_ep) } static struct usb_request * -dummy_alloc_request (struct usb_ep *_ep, int mem_flags) +dummy_alloc_request (struct usb_ep *_ep, unsigned mem_flags) { struct dummy_ep *ep; struct dummy_request *req; @@ -507,7 +507,7 @@ dummy_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - int mem_flags + unsigned mem_flags ) { char *retval; struct dummy_ep *ep; @@ -540,7 +540,8 @@ fifo_complete (struct usb_ep *ep, struct usb_request *req) } static int -dummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags) +dummy_queue (struct usb_ep *_ep, struct usb_request *_req, + unsigned mem_flags) { struct dummy_ep *ep; struct dummy_request *req; @@ -998,7 +999,7 @@ static int dummy_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct dummy *dum; struct urbp *urbp; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 5bb53ae88969..00a5d2566265 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -945,11 +945,11 @@ config_buf (enum usb_device_speed speed, /*-------------------------------------------------------------------------*/ -static void eth_start (struct eth_dev *dev, int gfp_flags); -static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags); +static void eth_start (struct eth_dev *dev, unsigned gfp_flags); +static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags); static int -set_ether_config (struct eth_dev *dev, int gfp_flags) +set_ether_config (struct eth_dev *dev, unsigned gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1079,7 +1079,7 @@ static void eth_reset_config (struct eth_dev *dev) * that returns config descriptors, and altsetting code. */ static int -eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) +eth_set_config (struct eth_dev *dev, unsigned number, unsigned gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1596,7 +1596,7 @@ static void defer_kevent (struct eth_dev *dev, int flag) static void rx_complete (struct usb_ep *ep, struct usb_request *req); static int -rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) +rx_submit (struct eth_dev *dev, struct usb_request *req, unsigned gfp_flags) { struct sk_buff *skb; int retval = -ENOMEM; @@ -1722,7 +1722,7 @@ clean: } static int prealloc (struct list_head *list, struct usb_ep *ep, - unsigned n, int gfp_flags) + unsigned n, unsigned gfp_flags) { unsigned i; struct usb_request *req; @@ -1761,7 +1761,7 @@ extra: return 0; } -static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags) +static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags) { int status; @@ -1777,7 +1777,7 @@ fail: return status; } -static void rx_fill (struct eth_dev *dev, int gfp_flags) +static void rx_fill (struct eth_dev *dev, unsigned gfp_flags) { struct usb_request *req; unsigned long flags; @@ -2022,7 +2022,7 @@ static int rndis_control_ack (struct net_device *net) #endif /* RNDIS */ -static void eth_start (struct eth_dev *dev, int gfp_flags) +static void eth_start (struct eth_dev *dev, unsigned gfp_flags) { DEBUG (dev, "%s\n", __FUNCTION__); diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index ed773a9111de..eaab26f4ed37 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -269,7 +269,7 @@ static int goku_ep_disable(struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -goku_alloc_request(struct usb_ep *_ep, int gfp_flags) +goku_alloc_request(struct usb_ep *_ep, unsigned gfp_flags) { struct goku_request *req; @@ -327,7 +327,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req) */ static void * goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, int gfp_flags) + dma_addr_t *dma, unsigned gfp_flags) { void *retval; struct goku_ep *ep; @@ -789,7 +789,7 @@ finished: /*-------------------------------------------------------------------------*/ static int -goku_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +goku_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) { struct goku_request *req; struct goku_ep *ep; diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index df75ab65a5ec..4842577789c9 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -1106,7 +1106,7 @@ static int lh7a40x_ep_disable(struct usb_ep *_ep) } static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, - int gfp_flags) + unsigned gfp_flags) { struct lh7a40x_request *req; @@ -1134,7 +1134,7 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req) } static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes, - dma_addr_t * dma, int gfp_flags) + dma_addr_t * dma, unsigned gfp_flags) { char *retval; @@ -1158,7 +1158,7 @@ static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma, * NOTE: Sets INDEX register */ static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req, - int gfp_flags) + unsigned gfp_flags) { struct lh7a40x_request *req; struct lh7a40x_ep *ep; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 13a3dbc9949b..234a1a97b84e 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -376,7 +376,7 @@ static int net2280_disable (struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -net2280_alloc_request (struct usb_ep *_ep, int gfp_flags) +net2280_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) { struct net2280_ep *ep; struct net2280_request *req; @@ -463,7 +463,7 @@ net2280_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - int gfp_flags + unsigned gfp_flags ) { void *retval; @@ -897,7 +897,7 @@ done (struct net2280_ep *ep, struct net2280_request *req, int status) /*-------------------------------------------------------------------------*/ static int -net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +net2280_queue (struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) { struct net2280_request *req; struct net2280_ep *ep; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index a2b812af6e66..c906d675ef4b 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -269,7 +269,7 @@ static int omap_ep_disable(struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -omap_alloc_request(struct usb_ep *ep, int gfp_flags) +omap_alloc_request(struct usb_ep *ep, unsigned gfp_flags) { struct omap_req *req; @@ -298,7 +298,7 @@ omap_alloc_buffer( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - int gfp_flags + unsigned gfp_flags ) { void *retval; @@ -937,7 +937,7 @@ static void dma_channel_release(struct omap_ep *ep) /*-------------------------------------------------------------------------*/ static int -omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) { struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); struct omap_req *req = container_of(_req, struct omap_req, req); diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 6a0b957af335..1507738337c4 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -332,7 +332,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) * pxa2xx_ep_alloc_request - allocate a request data structure */ static struct usb_request * -pxa2xx_ep_alloc_request (struct usb_ep *_ep, int gfp_flags) +pxa2xx_ep_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) { struct pxa2xx_request *req; @@ -367,7 +367,7 @@ pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req) */ static void * pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, int gfp_flags) + dma_addr_t *dma, unsigned gfp_flags) { char *retval; @@ -874,7 +874,7 @@ done: /*-------------------------------------------------------------------------*/ static int -pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) { struct pxa2xx_request *req; struct pxa2xx_ep *ep; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index a6e035e24479..bb9b2d94eed5 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -612,7 +612,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) } static struct usb_request * -source_sink_start_ep (struct usb_ep *ep, int gfp_flags) +source_sink_start_ep (struct usb_ep *ep, unsigned gfp_flags) { struct usb_request *req; int status; @@ -640,7 +640,7 @@ source_sink_start_ep (struct usb_ep *ep, int gfp_flags) } static int -set_source_sink_config (struct zero_dev *dev, int gfp_flags) +set_source_sink_config (struct zero_dev *dev, unsigned gfp_flags) { int result = 0; struct usb_ep *ep; @@ -744,7 +744,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) } static int -set_loopback_config (struct zero_dev *dev, int gfp_flags) +set_loopback_config (struct zero_dev *dev, unsigned gfp_flags) { int result = 0; struct usb_ep *ep; @@ -845,7 +845,7 @@ static void zero_reset_config (struct zero_dev *dev) * by limiting configuration choices (like the pxa2xx). */ static int -zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags) +zero_set_config (struct zero_dev *dev, unsigned number, unsigned gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 35248a37b717..149b13fc0a71 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -960,7 +960,7 @@ static int ehci_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct list_head qtd_list; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 45d89a7083b1..d74b2d68a50e 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -898,7 +898,7 @@ submit_async ( struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, - int mem_flags + unsigned mem_flags ) { struct ehci_qtd *qtd; int epnum; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index c2104cad4033..9af4f64532a9 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -588,7 +588,7 @@ static int intr_submit ( struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, - int mem_flags + unsigned mem_flags ) { unsigned epnum; unsigned long flags; @@ -633,7 +633,7 @@ done: /* ehci_iso_stream ops work with both ITD and SITD */ static struct ehci_iso_stream * -iso_stream_alloc (int mem_flags) +iso_stream_alloc (unsigned mem_flags) { struct ehci_iso_stream *stream; @@ -846,7 +846,7 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) /* ehci_iso_sched ops can be ITD-only or SITD-only */ static struct ehci_iso_sched * -iso_sched_alloc (unsigned packets, int mem_flags) +iso_sched_alloc (unsigned packets, unsigned mem_flags) { struct ehci_iso_sched *iso_sched; int size = sizeof *iso_sched; @@ -919,7 +919,7 @@ itd_urb_transaction ( struct ehci_iso_stream *stream, struct ehci_hcd *ehci, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct ehci_itd *itd; @@ -1412,7 +1412,8 @@ itd_complete ( /*-------------------------------------------------------------------------*/ -static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, + unsigned mem_flags) { int status = -EINVAL; unsigned long flags; @@ -1523,7 +1524,7 @@ sitd_urb_transaction ( struct ehci_iso_stream *stream, struct ehci_hcd *ehci, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct ehci_sitd *sitd; @@ -1772,7 +1773,8 @@ sitd_complete ( } -static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, + unsigned mem_flags) { int status = -EINVAL; unsigned long flags; @@ -1822,7 +1824,8 @@ done: #else static inline int -sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +sitd_submit (struct ehci_hcd *ehci, struct urb *urb, + unsigned mem_flags) { ehci_dbg (ehci, "split iso support is disabled\n"); return -ENOSYS; diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index d9883d774d3a..81f8f6b7fdce 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -463,7 +463,8 @@ static void etrax_usb_free_epid(int epid); static int etrax_remove_from_sb_list(struct urb *urb); -static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma); +static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, + unsigned mem_flags, dma_addr_t *dma); static void etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid); @@ -476,7 +477,7 @@ static int etrax_usb_submit_ctrl_urb(struct urb *urb); static int etrax_usb_submit_intr_urb(struct urb *urb); static int etrax_usb_submit_isoc_urb(struct urb *urb); -static int etrax_usb_submit_urb(struct urb *urb, int mem_flags); +static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags); static int etrax_usb_unlink_urb(struct urb *urb, int status); static int etrax_usb_get_frame_number(struct usb_device *usb_dev); @@ -1262,7 +1263,7 @@ static int etrax_usb_allocate_epid(void) return -1; } -static int etrax_usb_submit_urb(struct urb *urb, int mem_flags) +static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags) { etrax_hc_t *hc; int ret = -EINVAL; @@ -4277,7 +4278,8 @@ etrax_usb_bulk_eot_timer_func(unsigned long dummy) } static void* -etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma) +etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, + unsigned mem_flags, dma_addr_t *dma) { return kmalloc(size, mem_flags); } diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 3f2cea21efc5..50b1970fe6b6 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -693,7 +693,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load) static int isp116x_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, struct urb *urb, - int mem_flags) + unsigned mem_flags) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct usb_device *udev = urb->dev; @@ -715,7 +715,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, } /* avoid all allocations within spinlocks: request or endpoint */ if (!hep->hcpriv) { - ep = kcalloc(1, sizeof *ep, (__force unsigned)mem_flags); + ep = kcalloc(1, sizeof *ep, mem_flags); if (!ep) return -ENOMEM; } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 13cd2177b557..0375097850ee 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -180,7 +180,7 @@ static int ohci_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ed *ed; diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index 23735a36af00..fd3c4d3714bd 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -84,7 +84,7 @@ dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) /* TDs ... */ static struct td * -td_alloc (struct ohci_hcd *hc, int mem_flags) +td_alloc (struct ohci_hcd *hc, unsigned mem_flags) { dma_addr_t dma; struct td *td; @@ -118,7 +118,7 @@ td_free (struct ohci_hcd *hc, struct td *td) /* EDs ... */ static struct ed * -ed_alloc (struct ohci_hcd *hc, int mem_flags) +ed_alloc (struct ohci_hcd *hc, unsigned mem_flags) { dma_addr_t dma; struct ed *ed; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 6c3f910bc307..7a890a65f55d 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -815,7 +815,7 @@ static int sl811h_urb_enqueue( struct usb_hcd *hcd, struct usb_host_endpoint *hep, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct sl811 *sl811 = hcd_to_sl811(hcd); struct usb_device *udev = urb->dev; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 5f18084a116d..bbb36cd6ed61 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1164,7 +1164,7 @@ static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) static int uhci_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, - struct urb *urb, int mem_flags) + struct urb *urb, unsigned mem_flags) { int ret; struct uhci_hcd *uhci = hcd_to_uhci(hcd); diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index fd6ff4cb2c62..7ffa99b9760f 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -477,7 +477,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) } static void kaweth_usb_receive(struct urb *, struct pt_regs *regs); -static int kaweth_resubmit_rx_urb(struct kaweth_device *, int); +static int kaweth_resubmit_rx_urb(struct kaweth_device *, unsigned); /**************************************************************** int_callback @@ -550,7 +550,7 @@ static void kaweth_resubmit_tl(void *d) * kaweth_resubmit_rx_urb ****************************************************************/ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, - int mem_flags) + unsigned mem_flags) { int result; diff --git a/include/linux/usb.h b/include/linux/usb.h index eb282b581546..724637792996 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -938,17 +938,17 @@ static inline void usb_fill_int_urb (struct urb *urb, } extern void usb_init_urb(struct urb *urb); -extern struct urb *usb_alloc_urb(int iso_packets, int mem_flags); +extern struct urb *usb_alloc_urb(int iso_packets, unsigned mem_flags); extern void usb_free_urb(struct urb *urb); #define usb_put_urb usb_free_urb extern struct urb *usb_get_urb(struct urb *urb); -extern int usb_submit_urb(struct urb *urb, int mem_flags); +extern int usb_submit_urb(struct urb *urb, unsigned mem_flags); extern int usb_unlink_urb(struct urb *urb); extern void usb_kill_urb(struct urb *urb); #define HAVE_USB_BUFFERS void *usb_buffer_alloc (struct usb_device *dev, size_t size, - int mem_flags, dma_addr_t *dma); + unsigned mem_flags, dma_addr_t *dma); void usb_buffer_free (struct usb_device *dev, size_t size, void *addr, dma_addr_t dma); @@ -1055,7 +1055,7 @@ int usb_sg_init ( struct scatterlist *sg, int nents, size_t length, - int mem_flags + unsigned mem_flags ); void usb_sg_cancel (struct usb_sg_request *io); void usb_sg_wait (struct usb_sg_request *io); diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index b00f127cb447..71e608607324 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -107,18 +107,18 @@ struct usb_ep_ops { int (*disable) (struct usb_ep *ep); struct usb_request *(*alloc_request) (struct usb_ep *ep, - int gfp_flags); + unsigned gfp_flags); void (*free_request) (struct usb_ep *ep, struct usb_request *req); void *(*alloc_buffer) (struct usb_ep *ep, unsigned bytes, - dma_addr_t *dma, int gfp_flags); + dma_addr_t *dma, unsigned gfp_flags); void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned bytes); // NOTE: on 2.6, drivers may also use dma_map() and // dma_sync_single_*() to directly manage dma overhead. int (*queue) (struct usb_ep *ep, struct usb_request *req, - int gfp_flags); + unsigned gfp_flags); int (*dequeue) (struct usb_ep *ep, struct usb_request *req); int (*set_halt) (struct usb_ep *ep, int value); @@ -214,7 +214,7 @@ usb_ep_disable (struct usb_ep *ep) * Returns the request, or null if one could not be allocated. */ static inline struct usb_request * -usb_ep_alloc_request (struct usb_ep *ep, int gfp_flags) +usb_ep_alloc_request (struct usb_ep *ep, unsigned gfp_flags) { return ep->ops->alloc_request (ep, gfp_flags); } @@ -254,7 +254,7 @@ usb_ep_free_request (struct usb_ep *ep, struct usb_request *req) */ static inline void * usb_ep_alloc_buffer (struct usb_ep *ep, unsigned len, dma_addr_t *dma, - int gfp_flags) + unsigned gfp_flags) { return ep->ops->alloc_buffer (ep, len, dma, gfp_flags); } @@ -330,7 +330,7 @@ usb_ep_free_buffer (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned len) * reported when the usb peripheral is disconnected. */ static inline int -usb_ep_queue (struct usb_ep *ep, struct usb_request *req, int gfp_flags) +usb_ep_queue (struct usb_ep *ep, struct usb_request *req, unsigned gfp_flags) { return ep->ops->queue (ep, req, gfp_flags); } -- cgit v1.2.3 From 30e695986679ac2d2354fc1634e8cb931bb47785 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 26 Jun 2005 17:18:46 -0700 Subject: [PATCH] USB: net2280 warning fix drivers/usb/gadget/net2280.c: In function 'show_registers': drivers/usb/gadget/net2280.c:1501: warning: assignment discards qualifiers from pointer target type Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/net2280.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 234a1a97b84e..477fab2e74d1 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1490,7 +1490,7 @@ show_registers (struct device *_dev, struct device_attribute *attr, char *buf) unsigned long flags; int i; u32 t1, t2; - char *s; + const char *s; dev = dev_get_drvdata (_dev); next = buf; -- cgit v1.2.3 From 99f83c9c9ac994c844ecf3e64e848c2f8dd7dfe0 Mon Sep 17 00:00:00 2001 From: Michael Downey Date: Mon, 27 Jun 2005 11:48:26 -0600 Subject: [PATCH] USB: add driver for Keyspan Digital Remote This driver is a basic keypress input driver for the Keyspan Digital Remote with part number UIA-11. Currently there is an older remote with part number UIA-10 which isn't supported by this driver. Support for the older UIA-10 could be added but a binary file is required to be download to the device, and I don't have that file. I also don't have a UIA-10 device so I wouldn't be able to test any of the changes. Signed-off-by: Michael Downey Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/Kconfig | 13 + drivers/usb/input/Makefile | 1 + drivers/usb/input/keyspan_remote.c | 633 +++++++++++++++++++++++++++++++++++++ 3 files changed, 647 insertions(+) create mode 100644 drivers/usb/input/keyspan_remote.c (limited to 'drivers/usb') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index fd59f6bdd67f..298e4a25e3d3 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -259,3 +259,16 @@ config USB_ATI_REMOTE To compile this driver as a module, choose M here: the module will be called ati_remote. +config USB_KEYSPAN_REMOTE + tristate "Keyspan DMR USB remote control (EXPERIMENTAL)" + depends on USB && INPUT && EXPERIMENTAL + ---help--- + Say Y here if you want to use a Keyspan DMR USB remote control. + Currently only the UIA-11 type of receiver has been tested. The tag + on the receiver that connects to the USB port should have a P/N that + will tell you what type of DMR you have. The UIA-10 type is not + supported at this time. This driver maps all buttons to keypress + events. + + To compile this driver as a module, choose M here: the module will + be called keyspan_remote. diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 831b2b0f1f05..f1547be632d4 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_USB_HID) += usbhid.o obj-$(CONFIG_USB_KBD) += usbkbd.o obj-$(CONFIG_USB_KBTAB) += kbtab.o +obj-$(CONFIG_USB_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c new file mode 100644 index 000000000000..67dc93685203 --- /dev/null +++ b/drivers/usb/input/keyspan_remote.c @@ -0,0 +1,633 @@ +/* + * keyspan_remote: USB driver for the Keyspan DMR + * + * Copyright (C) 2005 Zymeta Corporation - Michael Downey (downey@zymeta.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + * This driver has been put together with the support of Innosys, Inc. + * and Keyspan, Inc the manufacturers of the Keyspan USB DMR product. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "v0.1" +#define DRIVER_AUTHOR "Michael Downey " +#define DRIVER_DESC "Driver for the USB Keyspan remote control." +#define DRIVER_LICENSE "GPL" + +/* Parameters that can be passed to the driver. */ +static int debug; +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); + +/* Vendor and product ids */ +#define USB_KEYSPAN_VENDOR_ID 0x06CD +#define USB_KEYSPAN_PRODUCT_UIA11 0x0202 + +/* Defines for converting the data from the remote. */ +#define ZERO 0x18 +#define ZERO_MASK 0x1F /* 5 bits for a 0 */ +#define ONE 0x3C +#define ONE_MASK 0x3F /* 6 bits for a 1 */ +#define SYNC 0x3F80 +#define SYNC_MASK 0x3FFF /* 14 bits for a SYNC sequence */ +#define STOP 0x00 +#define STOP_MASK 0x1F /* 5 bits for the STOP sequence */ +#define GAP 0xFF + +#define RECV_SIZE 8 /* The UIA-11 type have a 8 byte limit. */ + +/* table of devices that work with this driver */ +static struct usb_device_id keyspan_table[] = { + { USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) }, + { } /* Terminating entry */ +}; + +/* Structure to store all the real stuff that a remote sends to us. */ +struct keyspan_message { + u16 system; + u8 button; + u8 toggle; +}; + +/* Structure used for all the bit testing magic needed to be done. */ +struct bit_tester { + u32 tester; + int len; + int pos; + int bits_left; + u8 buffer[32]; +}; + +/* Structure to hold all of our driver specific stuff */ +struct usb_keyspan { + char name[128]; + char phys[64]; + struct usb_device* udev; + struct input_dev input; + struct usb_interface* interface; + struct usb_endpoint_descriptor* in_endpoint; + struct urb* irq_urb; + int open; + dma_addr_t in_dma; + unsigned char* in_buffer; + + /* variables used to parse messages from remote. */ + struct bit_tester data; + int stage; + int toggle; +}; + +/* + * Table that maps the 31 possible keycodes to input keys. + * Currently there are 15 and 17 button models so RESERVED codes + * are blank areas in the mapping. + */ +static int keyspan_key_table[] = { + KEY_RESERVED, /* 0 is just a place holder. */ + KEY_RESERVED, + KEY_STOP, + KEY_PLAYCD, + KEY_RESERVED, + KEY_PREVIOUSSONG, + KEY_REWIND, + KEY_FORWARD, + KEY_NEXTSONG, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_PAUSE, + KEY_VOLUMEUP, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_VOLUMEDOWN, + KEY_RESERVED, + KEY_UP, + KEY_RESERVED, + KEY_MUTE, + KEY_LEFT, + KEY_ENTER, + KEY_RIGHT, + KEY_RESERVED, + KEY_RESERVED, + KEY_DOWN, + KEY_RESERVED, + KEY_KPASTERISK, + KEY_RESERVED, + KEY_MENU +}; + +static struct usb_driver keyspan_driver; + +/* + * Debug routine that prints out what we've received from the remote. + */ +static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/ +{ + char codes[4*RECV_SIZE]; + int i; + + for (i = 0; i < RECV_SIZE; i++) { + snprintf(codes+i*3, 4, "%02x ", dev->in_buffer[i]); + } + + dev_info(&dev->udev->dev, "%s\n", codes); +} + +/* + * Routine that manages the bit_tester structure. It makes sure that there are + * at least bits_needed bits loaded into the tester. + */ +static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) +{ + if (dev->data.bits_left >= bits_needed) + return(0); + + /* + * Somehow we've missed the last message. The message will be repeated + * though so it's not too big a deal + */ + if (dev->data.pos >= dev->data.len) { + dev_dbg(&dev->udev, "%s - Error ran out of data. pos: %d, len: %d\n", + __FUNCTION__, dev->data.pos, dev->data.len); + return(-1); + } + + /* Load as much as we can into the tester. */ + while ((dev->data.bits_left + 7 < (sizeof(dev->data.tester) * 8)) && + (dev->data.pos < dev->data.len)) { + dev->data.tester += (dev->data.buffer[dev->data.pos++] << dev->data.bits_left); + dev->data.bits_left += 8; + } + + return(0); +} + +/* + * Routine that handles all the logic needed to parse out the message from the remote. + */ +static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs) +{ + int i; + int found = 0; + struct keyspan_message message; + + switch(remote->stage) { + case 0: + /* + * In stage 0 we want to find the start of a message. The remote sends a 0xFF as filler. + * So the first byte that isn't a FF should be the start of a new message. + */ + for (i = 0; i < RECV_SIZE && remote->in_buffer[i] == GAP; ++i); + + if (i < RECV_SIZE) { + memcpy(remote->data.buffer, remote->in_buffer, RECV_SIZE); + remote->data.len = RECV_SIZE; + remote->data.pos = 0; + remote->data.tester = 0; + remote->data.bits_left = 0; + remote->stage = 1; + } + break; + + case 1: + /* + * Stage 1 we should have 16 bytes and should be able to detect a + * SYNC. The SYNC is 14 bits, 7 0's and then 7 1's. + */ + memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE); + remote->data.len += RECV_SIZE; + + found = 0; + while ((remote->data.bits_left >= 14 || remote->data.pos < remote->data.len) && !found) { + for (i = 0; i < 8; ++i) { + if (keyspan_load_tester(remote, 14) != 0) { + remote->stage = 0; + return; + } + + if ((remote->data.tester & SYNC_MASK) == SYNC) { + remote->data.tester = remote->data.tester >> 14; + remote->data.bits_left -= 14; + found = 1; + break; + } else { + remote->data.tester = remote->data.tester >> 1; + --remote->data.bits_left; + } + } + } + + if (!found) { + remote->stage = 0; + remote->data.len = 0; + } else { + remote->stage = 2; + } + break; + + case 2: + /* + * Stage 2 we should have 24 bytes which will be enough for a full + * message. We need to parse out the system code, button code, + * toggle code, and stop. + */ + memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE); + remote->data.len += RECV_SIZE; + + message.system = 0; + for (i = 0; i < 9; i++) { + keyspan_load_tester(remote, 6); + + if ((remote->data.tester & ZERO_MASK) == ZERO) { + message.system = message.system << 1; + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else if ((remote->data.tester & ONE_MASK) == ONE) { + message.system = (message.system << 1) + 1; + remote->data.tester = remote->data.tester >> 6; + remote->data.bits_left -= 6; + } else { + err("%s - Unknown sequence found in system data.\n", __FUNCTION__); + remote->stage = 0; + return; + } + } + + message.button = 0; + for (i = 0; i < 5; i++) { + keyspan_load_tester(remote, 6); + + if ((remote->data.tester & ZERO_MASK) == ZERO) { + message.button = message.button << 1; + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else if ((remote->data.tester & ONE_MASK) == ONE) { + message.button = (message.button << 1) + 1; + remote->data.tester = remote->data.tester >> 6; + remote->data.bits_left -= 6; + } else { + err("%s - Unknown sequence found in button data.\n", __FUNCTION__); + remote->stage = 0; + return; + } + } + + keyspan_load_tester(remote, 6); + if ((remote->data.tester & ZERO_MASK) == ZERO) { + message.toggle = 0; + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else if ((remote->data.tester & ONE_MASK) == ONE) { + message.toggle = 1; + remote->data.tester = remote->data.tester >> 6; + remote->data.bits_left -= 6; + } else { + err("%s - Error in message, invalid toggle.\n", __FUNCTION__); + } + + keyspan_load_tester(remote, 5); + if ((remote->data.tester & STOP_MASK) == STOP) { + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else { + err("Bad message recieved, no stop bit found.\n"); + } + + dev_dbg(&remote->udev, + "%s found valid message: system: %d, button: %d, toggle: %d\n", + __FUNCTION__, message.system, message.button, message.toggle); + + if (message.toggle != remote->toggle) { + input_regs(&remote->input, regs); + input_report_key(&remote->input, keyspan_key_table[message.button], 1); + input_report_key(&remote->input, keyspan_key_table[message.button], 0); + input_sync(&remote->input); + remote->toggle = message.toggle; + } + + remote->stage = 0; + break; + } +} + +/* + * Routine for sending all the initialization messages to the remote. + */ +static int keyspan_setup(struct usb_device* dev) +{ + int retval = 0; + + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0); + if (retval) { + dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n", + __FUNCTION__, retval); + return(retval); + } + + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x44, 0x40, 0x0, 0x0, NULL, 0, 0); + if (retval) { + dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n", + __FUNCTION__, retval); + return(retval); + } + + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x22, 0x40, 0x0, 0x0, NULL, 0, 0); + if (retval) { + dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n", + __FUNCTION__, retval); + return(retval); + } + + dev_dbg(&dev->dev, "%s - Setup complete.\n", __FUNCTION__); + return(retval); +} + +/* + * Routine used to handle a new message that has come in. + */ +static void keyspan_irq_recv(struct urb *urb, struct pt_regs *regs) +{ + struct usb_keyspan *dev = urb->context; + int retval; + + /* Check our status in case we need to bail out early. */ + switch (urb->status) { + case 0: + break; + + /* Device went away so don't keep trying to read from it. */ + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + + default: + goto resubmit; + break; + } + + if (debug) + keyspan_print(dev); + + keyspan_check_data(dev, regs); + +resubmit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err ("%s - usb_submit_urb failed with result: %d", __FUNCTION__, retval); +} + +static int keyspan_open(struct input_dev *dev) +{ + struct usb_keyspan *remote = dev->private; + + if (remote->open++) + return 0; + + remote->irq_urb->dev = remote->udev; + if (usb_submit_urb(remote->irq_urb, GFP_KERNEL)) { + remote->open--; + return -EIO; + } + + return 0; +} + +static void keyspan_close(struct input_dev *dev) +{ + struct usb_keyspan *remote = dev->private; + + if (!--remote->open) + usb_kill_urb(remote->irq_urb); +} + +/* + * Routine that sets up the driver to handle a specific USB device detected on the bus. + */ +static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + int i; + int retval = -ENOMEM; + char path[64]; + char *buf; + struct usb_keyspan *remote = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface)); + + /* See if the offered device matches what we can accept */ + if ((udev->descriptor.idVendor != USB_KEYSPAN_VENDOR_ID) || + (udev->descriptor.idProduct != USB_KEYSPAN_PRODUCT_UIA11) ) + return -ENODEV; + + /* allocate memory for our device state and initialize it */ + remote = kmalloc(sizeof(*remote), GFP_KERNEL); + if (remote == NULL) { + err("Out of memory\n"); + goto error; + } + memset(remote, 0x00, sizeof(*remote)); + + remote->udev = udev; + remote->interface = interface; + remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */ + + /* set up the endpoint information */ + /* use only the first in interrupt endpoint */ + iface_desc = interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (!remote->in_endpoint && + (endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + /* we found our interrupt in endpoint */ + remote->in_endpoint = endpoint; + + remote->in_buffer = usb_buffer_alloc(remote->udev, RECV_SIZE, SLAB_ATOMIC, &remote->in_dma); + if (!remote->in_buffer) { + retval = -ENOMEM; + goto error; + } + } + } + + if (!remote->in_endpoint) { + err("Could not find interrupt input endpoint.\n"); + retval = -ENODEV; + goto error; + } + + remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!remote->irq_urb) { + err("Failed to allocate urb.\n"); + retval = -ENOMEM; + goto error; + } + + retval = keyspan_setup(remote->udev); + if (retval) { + err("Failed to setup device.\n"); + retval = -ENODEV; + goto error; + } + + /* + * Setup the input system with the bits we are going to be reporting + */ + remote->input.evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */ + for (i = 0; i < 32; ++i) { + if (keyspan_key_table[i] != KEY_RESERVED) { + set_bit(keyspan_key_table[i], remote->input.keybit); + } + } + + remote->input.private = remote; + remote->input.open = keyspan_open; + remote->input.close = keyspan_close; + + usb_make_path(remote->udev, path, 64); + sprintf(remote->phys, "%s/input0", path); + + remote->input.name = remote->name; + remote->input.phys = remote->phys; + remote->input.id.bustype = BUS_USB; + remote->input.id.vendor = le16_to_cpu(remote->udev->descriptor.idVendor); + remote->input.id.product = le16_to_cpu(remote->udev->descriptor.idProduct); + remote->input.id.version = le16_to_cpu(remote->udev->descriptor.bcdDevice); + + if (!(buf = kmalloc(63, GFP_KERNEL))) { + usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); + kfree(remote); + return -ENOMEM; + } + + if (remote->udev->descriptor.iManufacturer && + usb_string(remote->udev, remote->udev->descriptor.iManufacturer, buf, 63) > 0) + strcat(remote->name, buf); + + if (remote->udev->descriptor.iProduct && + usb_string(remote->udev, remote->udev->descriptor.iProduct, buf, 63) > 0) + sprintf(remote->name, "%s %s", remote->name, buf); + + if (!strlen(remote->name)) + sprintf(remote->name, "USB Keyspan Remote %04x:%04x", + remote->input.id.vendor, remote->input.id.product); + + kfree(buf); + + /* + * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open() + */ + usb_fill_int_urb(remote->irq_urb, + remote->udev, usb_rcvintpipe(remote->udev, remote->in_endpoint->bEndpointAddress), + remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote, + remote->in_endpoint->bInterval); + remote->irq_urb->transfer_dma = remote->in_dma; + remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* we can register the device now, as it is ready */ + input_register_device(&remote->input); + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, remote); + + /* let the user know what node this device is now attached to */ + info("connected: %s on %s", remote->name, path); + return 0; + +error: + /* + * In case of error we need to clean up any allocated buffers + */ + if (remote->irq_urb) + usb_free_urb(remote->irq_urb); + + if (remote->in_buffer) + usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); + + if (remote) + kfree(remote); + + return retval; +} + +/* + * Routine called when a device is disconnected from the USB. + */ +static void keyspan_disconnect(struct usb_interface *interface) +{ + struct usb_keyspan *remote; + + /* prevent keyspan_open() from racing keyspan_disconnect() */ + lock_kernel(); + + remote = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + if (remote) { /* We have a valid driver structure so clean up everything we allocated. */ + input_unregister_device(&remote->input); + usb_kill_urb(remote->irq_urb); + usb_free_urb(remote->irq_urb); + usb_buffer_free(interface_to_usbdev(interface), RECV_SIZE, remote->in_buffer, remote->in_dma); + kfree(remote); + } + + unlock_kernel(); + + info("USB Keyspan now disconnected"); +} + +/* + * Standard driver set up sections + */ +static struct usb_driver keyspan_driver = +{ + .owner = THIS_MODULE, + .name = "keyspan_remote", + .probe = keyspan_probe, + .disconnect = keyspan_disconnect, + .id_table = keyspan_table +}; + +static int __init usb_keyspan_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + result = usb_register(&keyspan_driver); + if (result) + err("usb_register failed. Error number %d\n", result); + + return result; +} + +static void __exit usb_keyspan_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&keyspan_driver); +} + +module_init(usb_keyspan_init); +module_exit(usb_keyspan_exit); + +MODULE_DEVICE_TABLE(usb, keyspan_table); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); -- cgit v1.2.3 From b2134bcd2e1bf989e0566dd1b0e59a792722b671 Mon Sep 17 00:00:00 2001 From: "KAMBAROV, ZAUR" Date: Fri, 24 Jun 2005 22:20:35 -0700 Subject: [PATCH] USB: coverity: (desc->bitmap)[] overrun fix The length of the array desc->bitmap is 3, and not 4: Definitions involved: In drivers/usb/core/hcd.h 464 #define bitmap DeviceRemovable In drivers/usb/host/ohci-hub.c 395 struct usb_hub_descriptor *desc In drivers/usb/core/hub.h 130 struct usb_hub_descriptor { 131 __u8 bDescLength; 132 __u8 bDescriptorType; 133 __u8 bNbrPorts; 134 __u16 wHubCharacteristics; 135 __u8 bPwrOn2PwrGood; 136 __u8 bHubContrCurrent; 137 /* add 1 bit for hub status change; round to bytes */ 138 __u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8]; 139 __u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8]; 140 } __attribute__ ((packed)); In include/linux/usb.h 306 #define USB_MAXCHILDREN (16) This defect was found automatically by Coverity Prevent, a static analysis tool. (akpm: this code should be shot. Field `bitmap' doesn't exist in struct usb_hub_descriptor. And this .c file is #included in drivers/usb/host/ohci-hcd.c, and someone somewhere #defines `bitmap' to `DeviceRemovable'. >From a maintainability POV it would be better to memset the whole array beforehand - I changed the patch to do that) Signed-off-by: Zaur Kambarov Cc: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hub.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index e2fc4129dfc6..83ca4549a50e 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -419,10 +419,11 @@ ohci_hub_descriptor ( /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ rh = roothub_b (ohci); + memset(desc->bitmap, 0xff, sizeof(desc->bitmap)); desc->bitmap [0] = rh & RH_B_DR; if (ports > 7) { desc->bitmap [1] = (rh & RH_B_DR) >> 8; - desc->bitmap [2] = desc->bitmap [3] = 0xff; + desc->bitmap [2] = 0xff; } else desc->bitmap [1] = 0xff; } -- cgit v1.2.3 From 8fd6db47b90c7ecac32e3211f771849e148bdb07 Mon Sep 17 00:00:00 2001 From: Michael Hund Date: Mon, 27 Jun 2005 22:44:22 +0200 Subject: [PATCH] USB: add LD devices to hid blacklist below you will find one patch to hid-core.c, which lets usbhid ignore our HID devices. It would be nice, if you can apply it. Signed-off-by: Michael Hund Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 100b49bd1d3e..2350e7a5ad70 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1428,6 +1428,19 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_VERNIER_SKIP 0x0003 #define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 +#define USB_VENDOR_ID_LD 0x0f11 +#define USB_DEVICE_ID_CASSY 0x1000 +#define USB_DEVICE_ID_POCKETCASSY 0x1010 +#define USB_DEVICE_ID_MOBILECASSY 0x1020 +#define USB_DEVICE_ID_JWM 0x1080 +#define USB_DEVICE_ID_DMMP 0x1081 +#define USB_DEVICE_ID_UMIP 0x1090 +#define USB_DEVICE_ID_VIDEOCOM 0x1200 +#define USB_DEVICE_ID_COM3LAB 0x2000 +#define USB_DEVICE_ID_TELEPORT 0x2010 +#define USB_DEVICE_ID_NETWORKANALYSER 0x2020 +#define USB_DEVICE_ID_POWERCONTROL 0x2030 + /* * Alphabetically sorted blacklist by quirk type. @@ -1463,6 +1476,17 @@ static struct hid_blacklist { { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_CASSY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_POCKETCASSY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_MOBILECASSY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_JWM, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_DMMP, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_UMIP, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_VIDEOCOM, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_COM3LAB, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_TELEPORT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_NETWORKANALYSER, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_POWERCONTROL, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, -- cgit v1.2.3 From b9df978f1974fea373741367b5d79a2ed3b7dcf9 Mon Sep 17 00:00:00 2001 From: Luca Risolia Date: Sat, 25 Jun 2005 16:30:24 +0200 Subject: [PATCH] USB: SN9C10x driver updates SN9C10x driver updates. Changes: + new, - removed, * cleanup, @ bugfix @ Remove bad get_ctrl()'s * Documentation updates + Add 0x0c45/0x602d to the list of SN9C10x based devices + Add support for OV7630 image sensors Signed-off-by: Luca Risolia Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/sn9c102.txt | 4 + drivers/usb/media/Makefile | 2 +- drivers/usb/media/sn9c102.h | 2 +- drivers/usb/media/sn9c102_core.c | 2 +- drivers/usb/media/sn9c102_ov7630.c | 394 +++++++++++++++++++++++++++++++++ drivers/usb/media/sn9c102_sensor.h | 16 +- drivers/usb/media/sn9c102_tas5110c1b.c | 21 +- drivers/usb/media/sn9c102_tas5130d1b.c | 27 +-- 8 files changed, 417 insertions(+), 51 deletions(-) create mode 100644 drivers/usb/media/sn9c102_ov7630.c (limited to 'drivers/usb') diff --git a/Documentation/usb/sn9c102.txt b/Documentation/usb/sn9c102.txt index cf9a1187edce..3f8a119db31b 100644 --- a/Documentation/usb/sn9c102.txt +++ b/Documentation/usb/sn9c102.txt @@ -297,6 +297,7 @@ Vendor ID Product ID 0x0c45 0x602a 0x0c45 0x602b 0x0c45 0x602c +0x0c45 0x602d 0x0c45 0x6030 0x0c45 0x6080 0x0c45 0x6082 @@ -333,6 +334,7 @@ Model Manufacturer ----- ------------ HV7131D Hynix Semiconductor, Inc. MI-0343 Micron Technology, Inc. +OV7630 OmniVision Technologies, Inc. PAS106B PixArt Imaging, Inc. PAS202BCB PixArt Imaging, Inc. TAS5110C1B Taiwan Advanced Sensor Corporation @@ -470,9 +472,11 @@ order): - Luca Capello for the donation of a webcam; - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the donation of a webcam; +- Jon Hollstrom for the donation of a webcam; - Carlos Eduardo Medaglia Dyonisio, who added the support for the PAS202BCB image sensor; - Stefano Mozzi, who donated 45 EU; +- Andrew Pearce for the donation of a webcam; - Bertrik Sikken, who reverse-engineered and documented the Huffman compression algorithm used in the SN9C10x controllers and implemented the first decoder; - Mizuno Takafumi for the donation of a webcam; diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile index 2b76df7005fe..d83adffa925f 100644 --- a/drivers/usb/media/Makefile +++ b/drivers/usb/media/Makefile @@ -2,7 +2,7 @@ # Makefile for USB Media drivers # -sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o +sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_DSBR) += dsbr100.o diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h index 8b8a4c8743f8..e5cea0e2eb57 100644 --- a/drivers/usb/media/sn9c102.h +++ b/drivers/usb/media/sn9c102.h @@ -56,7 +56,7 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004-2005 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.24" +#define SN9C102_MODULE_VERSION "1:1.24a" #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 24) enum sn9c102_bridge { diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c index 31d57400d5be..cf8cfbabefde 100644 --- a/drivers/usb/media/sn9c102_core.c +++ b/drivers/usb/media/sn9c102_core.c @@ -429,7 +429,7 @@ sn9c102_i2c_try_read(struct sn9c102_device* cam, } -static int +int sn9c102_i2c_try_write(struct sn9c102_device* cam, struct sn9c102_sensor* sensor, u8 address, u8 value) { diff --git a/drivers/usb/media/sn9c102_ov7630.c b/drivers/usb/media/sn9c102_ov7630.c new file mode 100644 index 000000000000..d27c5aedeaf8 --- /dev/null +++ b/drivers/usb/media/sn9c102_ov7630.c @@ -0,0 +1,394 @@ +/*************************************************************************** + * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera * + * Controllers * + * * + * Copyright (C) 2005 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include "sn9c102_sensor.h" + + +static struct sn9c102_sensor ov7630; + + +static int ov7630_init(struct sn9c102_device* cam) +{ + int err = 0; + + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x0f, 0x18); + err += sn9c102_write_reg(cam, 0x50, 0x19); + + err += sn9c102_i2c_write(cam, 0x12, 0x8d); + err += sn9c102_i2c_write(cam, 0x11, 0x00); + err += sn9c102_i2c_write(cam, 0x15, 0x34); + err += sn9c102_i2c_write(cam, 0x16, 0x03); + err += sn9c102_i2c_write(cam, 0x17, 0x1c); + err += sn9c102_i2c_write(cam, 0x18, 0xbd); + err += sn9c102_i2c_write(cam, 0x19, 0x06); + err += sn9c102_i2c_write(cam, 0x1a, 0xf6); + err += sn9c102_i2c_write(cam, 0x1b, 0x04); + err += sn9c102_i2c_write(cam, 0x20, 0x44); + err += sn9c102_i2c_write(cam, 0x23, 0xee); + err += sn9c102_i2c_write(cam, 0x26, 0xa0); + err += sn9c102_i2c_write(cam, 0x27, 0x9a); + err += sn9c102_i2c_write(cam, 0x28, 0x20); + err += sn9c102_i2c_write(cam, 0x29, 0x30); + err += sn9c102_i2c_write(cam, 0x2f, 0x3d); + err += sn9c102_i2c_write(cam, 0x30, 0x24); + err += sn9c102_i2c_write(cam, 0x32, 0x86); + err += sn9c102_i2c_write(cam, 0x60, 0xa9); + err += sn9c102_i2c_write(cam, 0x61, 0x42); + err += sn9c102_i2c_write(cam, 0x65, 0x00); + err += sn9c102_i2c_write(cam, 0x69, 0x38); + err += sn9c102_i2c_write(cam, 0x6f, 0x88); + err += sn9c102_i2c_write(cam, 0x70, 0x0b); + err += sn9c102_i2c_write(cam, 0x71, 0x00); + err += sn9c102_i2c_write(cam, 0x74, 0x21); + err += sn9c102_i2c_write(cam, 0x7d, 0xf7); + + return err; +} + + +static int ov7630_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2); + err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03); + break; + case V4L2_CID_RED_BALANCE: + err += sn9c102_i2c_write(cam, 0x02, ctrl->value); + break; + case V4L2_CID_BLUE_BALANCE: + err += sn9c102_i2c_write(cam, 0x03, ctrl->value); + break; + case V4L2_CID_GAIN: + err += sn9c102_i2c_write(cam, 0x00, ctrl->value); + break; + case V4L2_CID_CONTRAST: + err += ctrl->value ? sn9c102_i2c_write(cam, 0x05, + (ctrl->value-1) | 0x20) + : sn9c102_i2c_write(cam, 0x05, 0x00); + break; + case V4L2_CID_BRIGHTNESS: + err += sn9c102_i2c_write(cam, 0x06, ctrl->value); + break; + case V4L2_CID_SATURATION: + err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4); + break; + case V4L2_CID_HUE: + err += ctrl->value ? sn9c102_i2c_write(cam, 0x04, + (ctrl->value-1) | 0x20) + : sn9c102_i2c_write(cam, 0x04, 0x00); + break; + case V4L2_CID_DO_WHITE_BALANCE: + err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); + break; + case V4L2_CID_WHITENESS: + err += sn9c102_i2c_write(cam, 0x0d, ctrl->value); + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x09); + break; + case V4L2_CID_AUTOGAIN: + err += sn9c102_i2c_write(cam, 0x13, ctrl->value); + break; + case V4L2_CID_VFLIP: + err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7)); + break; + case V4L2_CID_BLACK_LEVEL: + err += sn9c102_i2c_write(cam, 0x25, ctrl->value); + break; + case SN9C102_V4L2_CID_BRIGHT_LEVEL: + err += sn9c102_i2c_write(cam, 0x24, ctrl->value); + break; + case SN9C102_V4L2_CID_GAMMA: + err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80); + break; + case SN9C102_V4L2_CID_BAND_FILTER: + err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2); + break; + default: + return -EINVAL; + } + + return err ? -EIO : 0; +} + + +static int ov7630_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = &ov7630; + int err = 0; + u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; + + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + + +static int ov7630_set_pix_format(struct sn9c102_device* cam, + const struct v4l2_pix_format* pix) +{ + int err = 0; + + if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) + err += sn9c102_write_reg(cam, 0x20, 0x19); + else + err += sn9c102_write_reg(cam, 0x50, 0x19); + + return err; +} + + +static struct sn9c102_sensor ov7630 = { + .name = "OV7630", + .maintainer = "Luca Risolia ", + .sysfs_ops = SN9C102_I2C_WRITE, + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .i2c_slave_id = 0x21, + .init = &ov7630_init, + .qctrl = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0x3f, + .step = 0x01, + .default_value = 0x14, + .flags = 0, + }, + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "hue", + .minimum = 0x00, + .maximum = 0x1f+1, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "saturation", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x08, + .flags = 0, + }, + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "contrast", + .minimum = 0x00, + .maximum = 0x1f+1, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x000, + .maximum = 0x3ff, + .step = 0x001, + .default_value = 0x83<<2, + .flags = 0, + }, + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x3a, + .flags = 0, + }, + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x77, + .flags = 0, + }, + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "brightness", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0xa0, + .flags = 0, + }, + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "white balance background: blue", + .minimum = 0x00, + .maximum = 0x3f, + .step = 0x01, + .default_value = 0x20, + .flags = 0, + }, + { + .id = V4L2_CID_WHITENESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "white balance background: red", + .minimum = 0x00, + .maximum = 0x3f, + .step = 0x01, + .default_value = 0x20, + .flags = 0, + }, + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto white balance", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x01, + .flags = 0, + }, + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain & exposure mode", + .minimum = 0x00, + .maximum = 0x03, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x01, + .flags = 0, + }, + { + .id = V4L2_CID_BLACK_LEVEL, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "black pixel ratio", + .minimum = 0x01, + .maximum = 0x9a, + .step = 0x01, + .default_value = 0x8a, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_BRIGHT_LEVEL, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "bright pixel ratio", + .minimum = 0x01, + .maximum = 0x9a, + .step = 0x01, + .default_value = 0x10, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_BAND_FILTER, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "band filter", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_GAMMA, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "rgb gamma", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + }, + .set_ctrl = &ov7630_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &ov7630_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + }, + .set_pix_format = &ov7630_set_pix_format +}; + + +int sn9c102_probe_ov7630(struct sn9c102_device* cam) +{ + int err = 0; + + sn9c102_attach_sensor(cam, &ov7630); + + if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f && + le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c) + return -ENODEV; + + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x00, 0x01); + err += sn9c102_write_reg(cam, 0x28, 0x17); + + if (err) + return -EIO; + + err += sn9c102_i2c_write(cam, 0x0b, 0); + if (err) + return -ENODEV; + + return 0; +} diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h index 6a7adebcb4bf..a45166c3488c 100644 --- a/drivers/usb/media/sn9c102_sensor.h +++ b/drivers/usb/media/sn9c102_sensor.h @@ -64,6 +64,7 @@ struct sn9c102_sensor; */ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); +extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); @@ -80,6 +81,7 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \ &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \ &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \ &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \ + &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \ &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \ &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \ NULL, \ @@ -103,7 +105,8 @@ static const struct usb_device_id sn9c102_id_table[] = { \ { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \ { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */ \ { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \ - { USB_DEVICE(0x0c45, 0x602c), }, /* OV7620 */ \ + { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */ \ + { USB_DEVICE(0x0c45, 0x602d), }, \ { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \ { USB_DEVICE(0x0c45, 0x6080), }, \ { USB_DEVICE(0x0c45, 0x6082), }, /* MI0343 and MI0360 */ \ @@ -145,6 +148,8 @@ static const struct usb_device_id sn9c102_id_table[] = { \ */ /* The "try" I2C I/O versions are used when probing the sensor */ +extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, + u8 address, u8 value); extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, u8 address); @@ -201,6 +206,8 @@ enum sn9c102_i2c_interface { SN9C102_I2C_3WIRES, }; +#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 + struct sn9c102_sensor { char name[32], /* sensor name */ maintainer[64]; /* name of the mantainer */ @@ -243,7 +250,7 @@ struct sn9c102_sensor { sensor according to the default configuration structures below. */ - struct v4l2_queryctrl qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; + struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS]; /* Optional list of default controls, defined as indicated in the V4L2 API. Menu type controls are not handled by this interface. @@ -356,7 +363,7 @@ struct sn9c102_sensor { core module to store successfully updated values of the above settings, for rollbacks..etc..in case of errors during atomic I/O */ - struct v4l2_queryctrl _qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; + struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS]; struct v4l2_rect _rect; }; @@ -367,5 +374,8 @@ struct sn9c102_sensor { #define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1 #define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2 #define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3 +#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4 +#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5 +#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6 #endif /* _SN9C102_SENSOR_H_ */ diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c index 690d62192273..8775999b5aff 100644 --- a/drivers/usb/media/sn9c102_tas5110c1b.c +++ b/drivers/usb/media/sn9c102_tas5110c1b.c @@ -24,8 +24,6 @@ static struct sn9c102_sensor tas5110c1b; -static struct v4l2_control tas5110c1b_gain; - static int tas5110c1b_init(struct sn9c102_device* cam) { @@ -46,21 +44,6 @@ static int tas5110c1b_init(struct sn9c102_device* cam) } -static int tas5110c1b_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_GAIN: - ctrl->value = tas5110c1b_gain.value; - break; - default: - return -EINVAL; - } - - return 0; -} - - static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, const struct v4l2_control* ctrl) { @@ -68,8 +51,7 @@ static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, switch (ctrl->id) { case V4L2_CID_GAIN: - if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value))) - tas5110c1b_gain.value = ctrl->value; + err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); break; default: return -EINVAL; @@ -147,7 +129,6 @@ static struct sn9c102_sensor tas5110c1b = { .height = 288, }, }, - .get_ctrl = &tas5110c1b_get_ctrl, .set_crop = &tas5110c1b_set_crop, .pix_format = { .width = 352, diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c index b378e941bbe8..927eafdd8c73 100644 --- a/drivers/usb/media/sn9c102_tas5130d1b.c +++ b/drivers/usb/media/sn9c102_tas5130d1b.c @@ -24,8 +24,6 @@ static struct sn9c102_sensor tas5130d1b; -static struct v4l2_control tas5130d1b_gain, tas5130d1b_exposure; - static int tas5130d1b_init(struct sn9c102_device* cam) { @@ -44,24 +42,6 @@ static int tas5130d1b_init(struct sn9c102_device* cam) } -static int tas5130d1b_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_GAIN: - ctrl->value = tas5130d1b_gain.value; - break; - case V4L2_CID_EXPOSURE: - ctrl->value = tas5130d1b_exposure.value; - break; - default: - return -EINVAL; - } - - return 0; -} - - static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, const struct v4l2_control* ctrl) { @@ -69,12 +49,10 @@ static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, switch (ctrl->id) { case V4L2_CID_GAIN: - if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value))) - tas5130d1b_gain.value = ctrl->value; + err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); break; case V4L2_CID_EXPOSURE: - if (!(err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value))) - tas5130d1b_exposure.value = ctrl->value; + err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value); break; default: return -EINVAL; @@ -147,7 +125,6 @@ static struct sn9c102_sensor tas5130d1b = { .flags = 0, }, }, - .get_ctrl = &tas5130d1b_get_ctrl, .set_ctrl = &tas5130d1b_set_ctrl, .cropcap = { .bounds = { -- cgit v1.2.3 From 05f33400307cfe9d89dbeca659731b9055fefbf8 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 29 Jun 2005 10:15:32 +0100 Subject: [PATCH] USB: gadget/ether fixes Signed-off-by: Ian Campbell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 00a5d2566265..b5647b503360 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2428,7 +2428,7 @@ autoconf_fail: dev->req->complete = eth_setup_complete; /* ... and maybe likewise for status transfer */ -#ifdef DEV_CONFIG_CDC +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) if (dev->status_ep) { dev->stat_req = eth_req_alloc (dev->status_ep, STATUS_BYTECOUNT, GFP_KERNEL); -- cgit v1.2.3 From e828264ee797d40b1df99fe88c6acfc0f36df639 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 29 Jun 2005 10:20:29 +0100 Subject: [PATCH] USB: gadget/ether build fixes. I also needed the following on 2.6.13-rc1 without CONFIG_USB_ETH_RNDIS, symbol fs_status_desc isn't available in that case on PXA255. This builds both with and without ETH_RNDIS, but I haven't actually tested either. Signed-off-by: Ian Campbell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index b5647b503360..8509e955007d 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -954,6 +954,7 @@ set_ether_config (struct eth_dev *dev, unsigned gfp_flags) int result = 0; struct usb_gadget *gadget = dev->gadget; +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) /* status endpoint used for RNDIS and (optionally) CDC */ if (!subset_active(dev) && dev->status_ep) { dev->status = ep_desc (gadget, &hs_status_desc, @@ -967,6 +968,7 @@ set_ether_config (struct eth_dev *dev, unsigned gfp_flags) goto done; } } +#endif dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); dev->in_ep->driver_data = dev; -- cgit v1.2.3 From 1d7beee3d4b4ae7faa881ef05ff5d94a125ed8a6 Mon Sep 17 00:00:00 2001 From: "david-b@pacbell.net" Date: Wed, 29 Jun 2005 07:00:56 -0700 Subject: [PATCH] USB: omap_udc tweaks Minor OMAP updates that somehow got dropped from previous patches. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/omap_udc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index c906d675ef4b..ff5533e69560 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2908,6 +2908,7 @@ static int __exit omap_udc_remove(struct device *dev) * make host resumes and VBUS detection trigger OMAP wakeup events; that * may involve talking to an external transceiver (e.g. isp1301). */ + static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level) { u32 devstat; @@ -2936,8 +2937,6 @@ static int omap_udc_resume(struct device *dev, u32 level) return 0; DBG("resume + wakeup/SRP\n"); - udc->gadget.dev.parent->power.power_state = PMSG_ON; - udc->gadget.dev.power.power_state = PMSG_ON; omap_pullup(&udc->gadget, 1); /* maybe the host would enumerate us if we nudged it */ -- cgit v1.2.3 From b404a5b02abf84812e5333bda201af464925d7a6 Mon Sep 17 00:00:00 2001 From: "david-b@pacbell.net" Date: Wed, 29 Jun 2005 06:59:14 -0700 Subject: [PATCH] USB: ohci-omap pm updates The recent "pm_message_t" changes removed functionality from the Linux PM framework. This patch removes it from the OMAP OHCI too, removing the distinction between (previous) PM_SUSPEND_MEM and PM_SUSPEND_DISK state transitions ... now the only suspend semantics supportable are what was previously PM_SUSPEND_DISK (4) and is now "PMSG_SUSPEND" (3). From: Todd Poynor Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-omap.c | 53 +++++++++++++------------------------------- 1 file changed, 16 insertions(+), 37 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index b62d69937694..5cde76faab93 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -456,34 +456,22 @@ static int ohci_hcd_omap_drv_remove(struct device *dev) #ifdef CONFIG_PM -/* states match PCI usage, always suspending the root hub except that - * 4 ~= D3cold (ACPI D3) with clock off (resume sees reset). - * - * FIXME: above comment is not right, and code is wrong, too :-(. - */ - -static int ohci_omap_suspend(struct device *dev, pm_message_t state, u32 level) +static int ohci_omap_suspend(struct device *dev, pm_message_t message, u32 level) { struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); int status = -EINVAL; if (level != SUSPEND_POWER_DOWN) return 0; - if (state <= dev->power.power_state) - return 0; - dev_dbg(dev, "suspend to %d\n", state); down(&ohci_to_hcd(ohci)->self.root_hub->serialize); status = ohci_hub_suspend(ohci_to_hcd(ohci)); if (status == 0) { - if (state >= 4) { - omap_ohci_clock_power(0); - ohci_to_hcd(ohci)->self.root_hub->state = - USB_STATE_SUSPENDED; - state = 4; - } + omap_ohci_clock_power(0); + ohci_to_hcd(ohci)->self.root_hub->state = + USB_STATE_SUSPENDED; ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; - dev->power.power_state = state; + dev->power.power_state = PMSG_SUSPEND; } up(&ohci_to_hcd(ohci)->self.root_hub->serialize); return status; @@ -497,29 +485,20 @@ static int ohci_omap_resume(struct device *dev, u32 level) if (level != RESUME_POWER_ON) return 0; - switch (dev->power.power_state) { - case 0: - break; - case 4: - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - omap_ohci_clock_power(1); - /* FALLTHROUGH */ - default: - dev_dbg(dev, "resume from %d\n", dev->power.power_state); + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + omap_ohci_clock_power(1); #ifdef CONFIG_USB_SUSPEND - /* get extra cleanup even if remote wakeup isn't in use */ - status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub); + /* get extra cleanup even if remote wakeup isn't in use */ + status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub); #else - down(&ohci_to_hcd(ohci)->self.root_hub->serialize); - status = ohci_hub_resume(ohci_to_hcd(ohci)); - up(&ohci_to_hcd(ohci)->self.root_hub->serialize); + down(&ohci_to_hcd(ohci)->self.root_hub->serialize); + status = ohci_hub_resume(ohci_to_hcd(ohci)); + up(&ohci_to_hcd(ohci)->self.root_hub->serialize); #endif - if (status == 0) - dev->power.power_state = 0; - break; - } + if (status == 0) + dev->power.power_state = PMSG_ON; return status; } -- cgit v1.2.3 From edfd6aee1f073ae645bd3e60ef96090fc9f0957b Mon Sep 17 00:00:00 2001 From: "david-b@pacbell.net" Date: Wed, 29 Jun 2005 07:03:10 -0700 Subject: [PATCH] USB: fix ohci merge glitch A patch re-organizing some parts of root hub initialization deleted the code initializing the bus-neutral reboot/shutdown notifier for OHCI. This patch just restores that deleted code. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 0375097850ee..68decab280dd 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -673,8 +673,10 @@ retry: ohci_dump (ohci, 1); - if (ohci_to_hcd(ohci)->self.root_hub == NULL) + if (ohci_to_hcd(ohci)->self.root_hub == NULL) { + register_reboot_notifier (&ohci->reboot_notifier); create_debug_files (ohci); + } return 0; } -- cgit v1.2.3 From a3fdf4ebe016ba756de3ca29a2a6117e9acd721c Mon Sep 17 00:00:00 2001 From: "brian@murphy.dk" Date: Wed, 29 Jun 2005 16:53:29 -0700 Subject: [PATCH] USB: export usb_get_intf() and usb_put_intf() Export usb_get_intf and usb_put_intf so that modules can increase usb interface reference counts. Signed-off-by: brian@murphy.dk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7713a605fce7..99c85d2f92da 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1532,6 +1532,9 @@ EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_deregister); EXPORT_SYMBOL(usb_disabled); +EXPORT_SYMBOL_GPL(usb_get_intf); +EXPORT_SYMBOL_GPL(usb_put_intf); + EXPORT_SYMBOL(usb_alloc_dev); EXPORT_SYMBOL(usb_put_dev); EXPORT_SYMBOL(usb_get_dev); -- cgit v1.2.3 From 83ef344a7539aa55a787790bc036f0bf3466e191 Mon Sep 17 00:00:00 2001 From: "brian@murphy.dk" Date: Wed, 29 Jun 2005 16:53:29 -0700 Subject: [PATCH] USB: fix usb reference count bug in cdc-acm driver This increases the reference count on the usb cdc acm control interface which is referred to by the tty interface provided by the driver. This allows the deferred removal of the tty after the physical device is disconnected if the tty is held open at the time of disconnection. Signed-off-by: brian@murphy.dk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 69e859e0f51d..adff5a77e31f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -422,6 +422,17 @@ bail_out: return -EIO; } +static void acm_tty_unregister(struct acm *acm) +{ + tty_unregister_device(acm_tty_driver, acm->minor); + usb_put_intf(acm->control); + acm_table[acm->minor] = NULL; + usb_free_urb(acm->ctrlurb); + usb_free_urb(acm->readurb); + usb_free_urb(acm->writeurb); + kfree(acm); +} + static void acm_tty_close(struct tty_struct *tty, struct file *filp) { struct acm *acm = tty->driver_data; @@ -436,14 +447,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) usb_kill_urb(acm->ctrlurb); usb_kill_urb(acm->writeurb); usb_kill_urb(acm->readurb); - } else { - tty_unregister_device(acm_tty_driver, acm->minor); - acm_table[acm->minor] = NULL; - usb_free_urb(acm->ctrlurb); - usb_free_urb(acm->readurb); - usb_free_urb(acm->writeurb); - kfree(acm); - } + } else + acm_tty_unregister(acm); } up(&open_sem); } @@ -905,7 +910,8 @@ skip_normal_probe: usb_driver_claim_interface(&acm_driver, data_interface, acm); - tty_register_device(acm_tty_driver, minor, &intf->dev); + usb_get_intf(control_interface); + tty_register_device(acm_tty_driver, minor, &control_interface->dev); acm_table[minor] = acm; usb_set_intfdata (intf, acm); @@ -954,12 +960,7 @@ static void acm_disconnect(struct usb_interface *intf) usb_driver_release_interface(&acm_driver, acm->data); if (!acm->used) { - tty_unregister_device(acm_tty_driver, acm->minor); - acm_table[acm->minor] = NULL; - usb_free_urb(acm->ctrlurb); - usb_free_urb(acm->readurb); - usb_free_urb(acm->writeurb); - kfree(acm); + acm_tty_unregister(acm); up(&open_sem); return; } -- cgit v1.2.3 From 2824bd250f0be1551747cc3ed5ae07facc285b57 Mon Sep 17 00:00:00 2001 From: Michael Hund Date: Mon, 27 Jun 2005 22:44:22 +0200 Subject: [PATCH] USB: add ldusb driver The following driver provides complete interrupt-in and interrupt-out reports (raw data) to a user program. Until now it uses the HIDIOCGDEVINFO ioctl call, because I don't know better :-(. Perhaps, it will be ok for you - and I will be happy, if you assign 8 minor numbers. I have tested it in several environments and it works very well for me. However, it has a problem with two or more devices at the same hub, if the two or more devices need 1 ms interrupt-in transfers. Unfortunately more than one interrupt-in transfer every ms isn't possible (ehci driver?). This is why the min_interrupt_in_interval and min_interrupt_out_interval are increased to 2 ms (see the corresponding module parameters). This way, I can use two devices simultaneously at the same hub. Signed-off-by: Michael Hund Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + drivers/usb/misc/Kconfig | 10 + drivers/usb/misc/Makefile | 1 + drivers/usb/misc/ldusb.c | 794 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 806 insertions(+) create mode 100644 drivers/usb/misc/ldusb.c (limited to 'drivers/usb') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 284f95723eea..df014c2a7c54 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_USB_EMI26) += misc/ obj-$(CONFIG_USB_EMI62) += misc/ obj-$(CONFIG_USB_IDMOUSE) += misc/ obj-$(CONFIG_USB_LCD) += misc/ +obj-$(CONFIG_USB_LD) += misc/ obj-$(CONFIG_USB_LED) += misc/ obj-$(CONFIG_USB_LEGOTOWER) += misc/ obj-$(CONFIG_USB_RIO500) += misc/ diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 3a896954b3a9..6649531fa824 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -139,6 +139,16 @@ config USB_IDMOUSE source "drivers/usb/misc/sisusbvga/Kconfig" +config USB_LD + tristate "USB LD driver" + depends on USB && EXPERIMENTAL + help + This driver is for generic USB devices that use interrupt transfers, + like LD Didactic's USB devices. + + To compile this driver as a module, choose M here: the + module will be called ldusb. + config USB_TEST tristate "USB testing driver (DEVELOPMENT)" depends on USB && USB_DEVICEFS && EXPERIMENTAL diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 4a3814cbd48d..862e40a83689 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_LCD) += usblcd.o +obj-$(CONFIG_USB_LD) += ldusb.o obj-$(CONFIG_USB_LED) += usbled.o obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o obj-$(CONFIG_USB_PHIDGETKIT) += phidgetkit.o diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c new file mode 100644 index 000000000000..66ec88354b93 --- /dev/null +++ b/drivers/usb/misc/ldusb.c @@ -0,0 +1,794 @@ +/** + * Generic USB driver for report based interrupt in/out devices + * like LD Didactic's USB devices. LD Didactic's USB devices are + * HID devices which do not use HID report definitons (they use + * raw interrupt in and our reports only for communication). + * + * This driver uses a ring buffer for time critical reading of + * interrupt in reports and provides read and write methods for + * raw interrupt reports (similar to the Windows HID driver). + * Devices based on the book USB COMPLETE by Jan Axelson may need + * such a compatibility to the Windows HID driver. + * + * Copyright (C) 2005 Michael Hund + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Derived from Lego USB Tower driver + * Copyright (C) 2003 David Glance + * 2001-2004 Juergen Stuber + * + * V0.1 (mh) Initial version + * V0.11 (mh) Added raw support for HID 1.0 devices (no interrupt out endpoint) + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Define these values to match your devices */ +#define USB_VENDOR_ID_LD 0x0f11 /* USB Vendor ID of LD Didactic GmbH */ +#define USB_DEVICE_ID_CASSY 0x1000 /* USB Product ID for all CASSY-S modules */ +#define USB_DEVICE_ID_POCKETCASSY 0x1010 /* USB Product ID for Pocket-CASSY */ +#define USB_DEVICE_ID_MOBILECASSY 0x1020 /* USB Product ID for Mobile-CASSY */ +#define USB_DEVICE_ID_JWM 0x1080 /* USB Product ID for Joule and Wattmeter */ +#define USB_DEVICE_ID_DMMP 0x1081 /* USB Product ID for Digital Multimeter P (reserved) */ +#define USB_DEVICE_ID_UMIP 0x1090 /* USB Product ID for UMI P */ +#define USB_DEVICE_ID_VIDEOCOM 0x1200 /* USB Product ID for VideoCom */ +#define USB_DEVICE_ID_COM3LAB 0x2000 /* USB Product ID for COM3LAB */ +#define USB_DEVICE_ID_TELEPORT 0x2010 /* USB Product ID for Terminal Adapter */ +#define USB_DEVICE_ID_NETWORKANALYSER 0x2020 /* USB Product ID for Network Analyser */ +#define USB_DEVICE_ID_POWERCONTROL 0x2030 /* USB Product ID for Controlling device for Power Electronics */ + +#define USB_VENDOR_ID_VERNIER 0x08f7 +#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 +#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 +#define USB_DEVICE_ID_VERNIER_SKIP 0x0003 +#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 + + +#ifdef CONFIG_USB_DYNAMIC_MINORS +#define USB_LD_MINOR_BASE 0 +#else +#define USB_LD_MINOR_BASE 176 +#endif + +/* table of devices that work with this driver */ +static struct usb_device_id ld_usb_table [] = { + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_CASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_POCKETCASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_MOBILECASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_JWM) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_DMMP) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_UMIP) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_VIDEOCOM) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_COM3LAB) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_TELEPORT) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_NETWORKANALYSER) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_POWERCONTROL) }, + { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) }, + { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, + { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, + { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, ld_usb_table); +MODULE_VERSION("V0.11"); +MODULE_AUTHOR("Michael Hund "); +MODULE_DESCRIPTION("LD USB Driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("LD USB Devices"); + +#ifdef CONFIG_USB_DEBUG + static int debug = 1; +#else + static int debug = 0; +#endif + +/* Use our own dbg macro */ +#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) + +/* Module parameters */ +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +/* All interrupt in transfers are collected in a ring buffer to + * avoid racing conditions and get better performance of the driver. + */ +static int ring_buffer_size = 128; +module_param(ring_buffer_size, int, 0); +MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size in reports"); + +/* The write_buffer can contain more than one interrupt out transfer. + */ +static int write_buffer_size = 10; +module_param(write_buffer_size, int, 0); +MODULE_PARM_DESC(write_buffer_size, "Write buffer size in reports"); + +/* As of kernel version 2.6.4 ehci-hcd uses an + * "only one interrupt transfer per frame" shortcut + * to simplify the scheduling of periodic transfers. + * This conflicts with our standard 1ms intervals for in and out URBs. + * We use default intervals of 2ms for in and 2ms for out transfers, + * which should be fast enough. + * Increase the interval to allow more devices that do interrupt transfers, + * or set to 1 to use the standard interval from the endpoint descriptors. + */ +static int min_interrupt_in_interval = 2; +module_param(min_interrupt_in_interval, int, 0); +MODULE_PARM_DESC(min_interrupt_in_interval, "Minimum interrupt in interval in ms"); + +static int min_interrupt_out_interval = 2; +module_param(min_interrupt_out_interval, int, 0); +MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in ms"); + +/* Structure to hold all of our device specific stuff */ +struct ld_usb { + struct semaphore sem; /* locks this structure */ + struct usb_interface* intf; /* save off the usb interface pointer */ + + int open_count; /* number of times this port has been opened */ + + char* ring_buffer; + unsigned int ring_head; + unsigned int ring_tail; + + wait_queue_head_t read_wait; + wait_queue_head_t write_wait; + + char* interrupt_in_buffer; + struct usb_endpoint_descriptor* interrupt_in_endpoint; + struct urb* interrupt_in_urb; + int interrupt_in_interval; + size_t interrupt_in_endpoint_size; + int interrupt_in_running; + int interrupt_in_done; + + char* interrupt_out_buffer; + struct usb_endpoint_descriptor* interrupt_out_endpoint; + struct urb* interrupt_out_urb; + int interrupt_out_interval; + size_t interrupt_out_endpoint_size; + int interrupt_out_busy; +}; + +/* prevent races between open() and disconnect() */ +static DECLARE_MUTEX(disconnect_sem); + +static struct usb_driver ld_usb_driver; + +/** + * ld_usb_abort_transfers + * aborts transfers and frees associated data structures + */ +static void ld_usb_abort_transfers(struct ld_usb *dev) +{ + /* shutdown transfer */ + if (dev->interrupt_in_running) { + dev->interrupt_in_running = 0; + if (dev->intf) + usb_kill_urb(dev->interrupt_in_urb); + } + if (dev->interrupt_out_busy) + if (dev->intf) + usb_kill_urb(dev->interrupt_out_urb); +} + +/** + * ld_usb_delete + */ +static void ld_usb_delete(struct ld_usb *dev) +{ + ld_usb_abort_transfers(dev); + + /* free data structures */ + usb_free_urb(dev->interrupt_in_urb); + usb_free_urb(dev->interrupt_out_urb); + kfree(dev->ring_buffer); + kfree(dev->interrupt_in_buffer); + kfree(dev->interrupt_out_buffer); + kfree(dev); +} + +/** + * ld_usb_interrupt_in_callback + */ +static void ld_usb_interrupt_in_callback(struct urb *urb, struct pt_regs *regs) +{ + struct ld_usb *dev = urb->context; + size_t *actual_buffer; + unsigned int next_ring_head; + int retval; + + if (urb->status) { + if (urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN) { + goto exit; + } else { + dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n", + __FUNCTION__, urb->status); + goto resubmit; /* maybe we can recover */ + } + } + + if (urb->actual_length > 0) { + next_ring_head = (dev->ring_head+1) % ring_buffer_size; + if (next_ring_head != dev->ring_tail) { + actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_head*(sizeof(size_t)+dev->interrupt_in_endpoint_size)); + /* actual_buffer gets urb->actual_length + interrupt_in_buffer */ + *actual_buffer = urb->actual_length; + memcpy(actual_buffer+1, dev->interrupt_in_buffer, urb->actual_length); + dev->ring_head = next_ring_head; + dbg_info(&dev->intf->dev, "%s: received %d bytes\n", + __FUNCTION__, urb->actual_length); + } else + dev_warn(&dev->intf->dev, + "Ring buffer overflow, %d bytes dropped\n", + urb->actual_length); + } + +resubmit: + /* resubmit if we're still running */ + if (dev->interrupt_in_running && dev->intf) { + retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); + if (retval) + dev_err(&dev->intf->dev, + "usb_submit_urb failed (%d)\n", retval); + } + +exit: + dev->interrupt_in_done = 1; + wake_up_interruptible(&dev->read_wait); +} + +/** + * ld_usb_interrupt_out_callback + */ +static void ld_usb_interrupt_out_callback(struct urb *urb, struct pt_regs *regs) +{ + struct ld_usb *dev = urb->context; + + /* sync/async unlink faults aren't errors */ + if (urb->status && !(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) + dbg_info(&dev->intf->dev, + "%s - nonzero write interrupt status received: %d\n", + __FUNCTION__, urb->status); + + dev->interrupt_out_busy = 0; + wake_up_interruptible(&dev->write_wait); +} + +/** + * ld_usb_open + */ +static int ld_usb_open(struct inode *inode, struct file *file) +{ + struct ld_usb *dev; + int subminor; + int retval = 0; + struct usb_interface *interface; + + nonseekable_open(inode, file); + subminor = iminor(inode); + + down(&disconnect_sem); + + interface = usb_find_interface(&ld_usb_driver, subminor); + + if (!interface) { + err("%s - error, can't find device for minor %d\n", + __FUNCTION__, subminor); + retval = -ENODEV; + goto unlock_disconnect_exit; + } + + dev = usb_get_intfdata(interface); + + if (!dev) { + retval = -ENODEV; + goto unlock_disconnect_exit; + } + + /* lock this device */ + if (down_interruptible(&dev->sem)) { + retval = -ERESTARTSYS; + goto unlock_disconnect_exit; + } + + /* allow opening only once */ + if (dev->open_count) { + retval = -EBUSY; + goto unlock_exit; + } + dev->open_count = 1; + + /* initialize in direction */ + dev->ring_head = 0; + dev->ring_tail = 0; + usb_fill_int_urb(dev->interrupt_in_urb, + interface_to_usbdev(interface), + usb_rcvintpipe(interface_to_usbdev(interface), + dev->interrupt_in_endpoint->bEndpointAddress), + dev->interrupt_in_buffer, + dev->interrupt_in_endpoint_size, + ld_usb_interrupt_in_callback, + dev, + dev->interrupt_in_interval); + + dev->interrupt_in_running = 1; + dev->interrupt_in_done = 0; + + retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); + if (retval) { + dev_err(&interface->dev, "Couldn't submit interrupt_in_urb %d\n", retval); + dev->interrupt_in_running = 0; + dev->open_count = 0; + goto unlock_exit; + } + + /* save device in the file's private structure */ + file->private_data = dev; + +unlock_exit: + up(&dev->sem); + +unlock_disconnect_exit: + up(&disconnect_sem); + + return retval; +} + +/** + * ld_usb_release + */ +static int ld_usb_release(struct inode *inode, struct file *file) +{ + struct ld_usb *dev; + int retval = 0; + + dev = file->private_data; + + if (dev == NULL) { + retval = -ENODEV; + goto exit; + } + + if (down_interruptible(&dev->sem)) { + retval = -ERESTARTSYS; + goto exit; + } + + if (dev->open_count != 1) { + retval = -ENODEV; + goto unlock_exit; + } + if (dev->intf == NULL) { + /* the device was unplugged before the file was released */ + up(&dev->sem); + /* unlock here as ld_usb_delete frees dev */ + ld_usb_delete(dev); + goto exit; + } + + /* wait until write transfer is finished */ + if (dev->interrupt_out_busy) + wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy, 2 * HZ); + ld_usb_abort_transfers(dev); + dev->open_count = 0; + +unlock_exit: + up(&dev->sem); + +exit: + return retval; +} + +/** + * ld_usb_poll + */ +static unsigned int ld_usb_poll(struct file *file, poll_table *wait) +{ + struct ld_usb *dev; + unsigned int mask = 0; + + dev = file->private_data; + + poll_wait(file, &dev->read_wait, wait); + poll_wait(file, &dev->write_wait, wait); + + if (dev->ring_head != dev->ring_tail) + mask |= POLLIN | POLLRDNORM; + if (!dev->interrupt_out_busy) + mask |= POLLOUT | POLLWRNORM; + + return mask; +} + +/** + * ld_usb_read + */ +static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, + loff_t *ppos) +{ + struct ld_usb *dev; + size_t *actual_buffer; + size_t bytes_to_read; + int retval = 0; + + dev = file->private_data; + + /* verify that we actually have some data to read */ + if (count == 0) + goto exit; + + /* lock this object */ + if (down_interruptible(&dev->sem)) { + retval = -ERESTARTSYS; + goto exit; + } + + /* verify that the device wasn't unplugged */ + if (dev->intf == NULL) { + retval = -ENODEV; + err("No device or device unplugged %d\n", retval); + goto unlock_exit; + } + + /* wait for data */ + if (dev->ring_head == dev->ring_tail) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto unlock_exit; + } + retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done); + if (retval < 0) + goto unlock_exit; + } + + /* actual_buffer contains actual_length + interrupt_in_buffer */ + actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_tail*(sizeof(size_t)+dev->interrupt_in_endpoint_size)); + bytes_to_read = min(count, *actual_buffer); + if (bytes_to_read < *actual_buffer) + dev_warn(&dev->intf->dev, "Read buffer overflow, %d bytes dropped\n", + *actual_buffer-bytes_to_read); + + /* copy one interrupt_in_buffer from ring_buffer into userspace */ + if (copy_to_user(buffer, actual_buffer+1, bytes_to_read)) { + retval = -EFAULT; + goto unlock_exit; + } + dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size; + + retval = bytes_to_read; + +unlock_exit: + /* unlock the device */ + up(&dev->sem); + +exit: + return retval; +} + +/** + * ld_usb_write + */ +static ssize_t ld_usb_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct ld_usb *dev; + size_t bytes_to_write; + int retval = 0; + + dev = file->private_data; + + /* verify that we actually have some data to write */ + if (count == 0) + goto exit; + + /* lock this object */ + if (down_interruptible(&dev->sem)) { + retval = -ERESTARTSYS; + goto exit; + } + + /* verify that the device wasn't unplugged */ + if (dev->intf == NULL) { + retval = -ENODEV; + err("No device or device unplugged %d\n", retval); + goto unlock_exit; + } + + /* wait until previous transfer is finished */ + if (dev->interrupt_out_busy) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto unlock_exit; + } + retval = wait_event_interruptible(dev->write_wait, !dev->interrupt_out_busy); + if (retval < 0) { + goto unlock_exit; + } + } + + /* write the data into interrupt_out_buffer from userspace */ + bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size); + if (bytes_to_write < count) + dev_warn(&dev->intf->dev, "Write buffer overflow, %d bytes dropped\n",count-bytes_to_write); + dbg_info(&dev->intf->dev, "%s: count = %d, bytes_to_write = %d\n", __FUNCTION__, count, bytes_to_write); + + if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) { + retval = -EFAULT; + goto unlock_exit; + } + + if (dev->interrupt_out_endpoint == NULL) { + /* try HID_REQ_SET_REPORT=9 on control_endpoint instead of interrupt_out_endpoint */ + retval = usb_control_msg(interface_to_usbdev(dev->intf), + usb_sndctrlpipe(interface_to_usbdev(dev->intf), 0), + 9, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + 1 << 8, 0, + dev->interrupt_out_buffer, + bytes_to_write, + USB_CTRL_SET_TIMEOUT * HZ); + if (retval < 0) + err("Couldn't submit HID_REQ_SET_REPORT %d\n", retval); + goto unlock_exit; + } + + /* send off the urb */ + usb_fill_int_urb(dev->interrupt_out_urb, + interface_to_usbdev(dev->intf), + usb_sndintpipe(interface_to_usbdev(dev->intf), + dev->interrupt_out_endpoint->bEndpointAddress), + dev->interrupt_out_buffer, + bytes_to_write, + ld_usb_interrupt_out_callback, + dev, + dev->interrupt_out_interval); + + dev->interrupt_out_busy = 1; + wmb(); + + retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); + if (retval) { + dev->interrupt_out_busy = 0; + err("Couldn't submit interrupt_out_urb %d\n", retval); + goto unlock_exit; + } + retval = bytes_to_write; + +unlock_exit: + /* unlock the device */ + up(&dev->sem); + +exit: + return retval; +} + +/* file operations needed when we register this driver */ +static struct file_operations ld_usb_fops = { + .owner = THIS_MODULE, + .read = ld_usb_read, + .write = ld_usb_write, + .open = ld_usb_open, + .release = ld_usb_release, + .poll = ld_usb_poll, +}; + +/* + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with devfs and the driver core + */ +static struct usb_class_driver ld_usb_class = { + .name = "ldusb%d", + .fops = &ld_usb_fops, + .minor_base = USB_LD_MINOR_BASE, +}; + +/** + * ld_usb_probe + * + * Called by the usb core when a new device is connected that it thinks + * this driver might be interested in. + */ +static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct ld_usb *dev = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + char *buffer; + int i; + int retval = -ENOMEM; + + /* allocate memory for our device state and intialize it */ + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + dev_err(&intf->dev, "Out of memory\n"); + goto exit; + } + memset(dev, 0x00, sizeof(*dev)); + init_MUTEX(&dev->sem); + dev->intf = intf; + init_waitqueue_head(&dev->read_wait); + init_waitqueue_head(&dev->write_wait); + + /* workaround for early firmware versions on fast computers */ + if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VENDOR_ID_LD) && + ((le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_CASSY) || + (le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_COM3LAB)) && + (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x103)) { + buffer = kmalloc(256, GFP_KERNEL); + /* usb_string makes SETUP+STALL to leave always ControlReadLoop */ + usb_string(udev, 255, buffer, 256); + kfree(buffer); + } + + iface_desc = intf->cur_altsetting; + + /* set up the endpoint information */ + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + dev->interrupt_in_endpoint = endpoint; + } + + if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + dev->interrupt_out_endpoint = endpoint; + } + } + if (dev->interrupt_in_endpoint == NULL) { + dev_err(&intf->dev, "Interrupt in endpoint not found\n"); + goto error; + } + if (dev->interrupt_out_endpoint == NULL) + dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n"); + + dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize); + dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL); + if (!dev->ring_buffer) { + dev_err(&intf->dev, "Couldn't allocate ring_buffer\n"); + goto error; + } + dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); + if (!dev->interrupt_in_buffer) { + dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n"); + goto error; + } + dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->interrupt_in_urb) { + dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n"); + goto error; + } + dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) : + udev->descriptor.bMaxPacketSize0; + dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL); + if (!dev->interrupt_out_buffer) { + dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n"); + goto error; + } + dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->interrupt_out_urb) { + dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n"); + goto error; + } + dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; + if (dev->interrupt_out_endpoint) + dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; + + /* we can register the device now, as it is ready */ + usb_set_intfdata(intf, dev); + + retval = usb_register_dev(intf, &ld_usb_class); + if (retval) { + /* something prevented us from registering this driver */ + dev_err(&intf->dev, "Not able to get a minor for this device.\n"); + usb_set_intfdata(intf, NULL); + goto error; + } + + /* let the user know what node this device is now attached to */ + dev_info(&intf->dev, "LD USB Device #%d now attached to major %d minor %d\n", + (intf->minor - USB_LD_MINOR_BASE), USB_MAJOR, intf->minor); + +exit: + return retval; + +error: + ld_usb_delete(dev); + + return retval; +} + +/** + * ld_usb_disconnect + * + * Called by the usb core when the device is removed from the system. + */ +static void ld_usb_disconnect(struct usb_interface *intf) +{ + struct ld_usb *dev; + int minor; + + down(&disconnect_sem); + + dev = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + + down(&dev->sem); + + minor = intf->minor; + + /* give back our minor */ + usb_deregister_dev(intf, &ld_usb_class); + + /* if the device is not opened, then we clean up right now */ + if (!dev->open_count) { + up(&dev->sem); + ld_usb_delete(dev); + } else { + dev->intf = NULL; + up(&dev->sem); + } + + up(&disconnect_sem); + + dev_info(&intf->dev, "LD USB Device #%d now disconnected\n", + (minor - USB_LD_MINOR_BASE)); +} + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver ld_usb_driver = { + .owner = THIS_MODULE, + .name = "ldusb", + .probe = ld_usb_probe, + .disconnect = ld_usb_disconnect, + .id_table = ld_usb_table, +}; + +/** + * ld_usb_init + */ +static int __init ld_usb_init(void) +{ + int retval; + + /* register this driver with the USB subsystem */ + retval = usb_register(&ld_usb_driver); + if (retval) + err("usb_register failed for the "__FILE__" driver. Error number %d\n", retval); + + return retval; +} + +/** + * ld_usb_exit + */ +static void __exit ld_usb_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&ld_usb_driver); +} + +module_init(ld_usb_init); +module_exit(ld_usb_exit); + -- cgit v1.2.3 From ba460e48064edeb57e3398eb8972c58de33f11ea Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 14 Jul 2005 00:33:47 -0700 Subject: [PATCH] Option Card driver update, Maintainer entry This patch updates the Option Card driver: - remove a deadlock - add sponsor notice - add new card - renamed the device to what's usually printed on it - removed some dead code - clean up a bunch of irregular whitespace (end-of-line, tabs) Also add a MAINTAINERS entry for the Option Card driver. Signed-Off-By: Matthias Urlichs Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 6 ++ drivers/usb/serial/option.c | 228 ++++++++++++++++++++++---------------------- 2 files changed, 118 insertions(+), 116 deletions(-) (limited to 'drivers/usb') diff --git a/MAINTAINERS b/MAINTAINERS index 5d014725901c..f73381af4d5e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2420,6 +2420,12 @@ L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net S: Maintained +USB OPTION-CARD DRIVER +P: Matthias Urlichs +M: smurf@smurf.noris.de +L: linux-usb-devel@lists.sourceforge.net +S: Maintained + USB OV511 DRIVER P: Mark McClelland M: mmcclell@bigfoot.com diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index b722175f108f..e9256408757f 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -12,14 +12,25 @@ History: 2005-05-19 v0.1 Initial version, based on incomplete docs - and analysis of misbehavior of the standard driver + and analysis of misbehavior with the standard driver 2005-05-20 v0.2 Extended the input buffer to avoid losing random 64-byte chunks of data 2005-05-21 v0.3 implemented chars_in_buffer() turned on low_latency simplified the code somewhat + 2005-05-24 v0.4 option_write() sometimes deadlocked under heavy load + removed some dead code + added sponsor notice + coding style clean-up + 2005-06-20 v0.4.1 add missing braces :-/ + killed end-of-line whitespace + 2005-07-15 v0.4.2 rename WLAN product to FUSION, add FUSION2 + + Work sponsored by: Sigos GmbH, Germany + */ -#define DRIVER_VERSION "v0.3" + +#define DRIVER_VERSION "v0.4" #define DRIVER_AUTHOR "Matthias Urlichs " #define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver" @@ -44,7 +55,6 @@ static int option_write_room (struct usb_serial_port *port); static void option_instat_callback(struct urb *urb, struct pt_regs *regs); - static int option_write (struct usb_serial_port *port, const unsigned char *buf, int count); @@ -60,14 +70,17 @@ static int option_tiocmset (struct usb_serial_port *port, struct file *file, static int option_send_setup (struct usb_serial_port *port); /* Vendor and product IDs */ -#define OPTION_VENDOR_ID 0x0AF0 +#define OPTION_VENDOR_ID 0x0AF0 + +#define OPTION_PRODUCT_OLD 0x5000 +#define OPTION_PRODUCT_FUSION 0x6000 +#define OPTION_PRODUCT_FUSION2 0x6300 -#define OPTION_PRODUCT_OLD 0x5000 -#define OPTION_PRODUCT_WLAN 0x6000 static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_WLAN) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, { } /* Terminating entry */ }; @@ -85,58 +98,62 @@ static struct usb_driver option_driver = { * recognizes separately, thus num_port=1. */ static struct usb_serial_device_type option_3port_device = { - .owner = THIS_MODULE, - .name = "Option 3-port card", - .short_name = "option", - .id_table = option_ids, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = NUM_DONT_CARE, - .num_bulk_out = NUM_DONT_CARE, - .num_ports = 1, /* 3 */ - .open = option_open, - .close = option_close, - .write = option_write, - .write_room = option_write_room, - .chars_in_buffer = option_chars_in_buffer, - .throttle = option_rx_throttle, - .unthrottle = option_rx_unthrottle, - .ioctl = option_ioctl, - .set_termios = option_set_termios, - .break_ctl = option_break_ctl, - .tiocmget = option_tiocmget, - .tiocmset = option_tiocmset, - .attach = option_startup, - .shutdown = option_shutdown, - .read_int_callback = option_instat_callback, + .owner = THIS_MODULE, + .name = "Option 3G data card", + .short_name = "option", + .id_table = option_ids, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .num_ports = 1, /* 3, but the card reports its ports separately */ + .open = option_open, + .close = option_close, + .write = option_write, + .write_room = option_write_room, + .chars_in_buffer = option_chars_in_buffer, + .throttle = option_rx_throttle, + .unthrottle = option_rx_unthrottle, + .ioctl = option_ioctl, + .set_termios = option_set_termios, + .break_ctl = option_break_ctl, + .tiocmget = option_tiocmget, + .tiocmset = option_tiocmset, + .attach = option_startup, + .shutdown = option_shutdown, + .read_int_callback = option_instat_callback, }; +#ifdef CONFIG_USB_DEBUG static int debug; +#else +#define debug 0 +#endif + /* per port private data */ -#define N_IN_URB 4 -#define N_OUT_URB 1 -#define IN_BUFLEN 1024 -#define OUT_BUFLEN 1024 +#define N_IN_URB 4 +#define N_OUT_URB 1 +#define IN_BUFLEN 1024 +#define OUT_BUFLEN 128 struct option_port_private { /* Input endpoints and buffer for this port */ - struct urb *in_urbs[N_IN_URB]; - char in_buffer[N_IN_URB][IN_BUFLEN]; + struct urb *in_urbs[N_IN_URB]; + char in_buffer[N_IN_URB][IN_BUFLEN]; /* Output endpoints and buffer for this port */ - struct urb *out_urbs[N_OUT_URB]; - char out_buffer[N_OUT_URB][OUT_BUFLEN]; + struct urb *out_urbs[N_OUT_URB]; + char out_buffer[N_OUT_URB][OUT_BUFLEN]; /* Settings for the port */ - int rts_state; /* Handshaking pins (outputs) */ - int dtr_state; - int cts_state; /* Handshaking pins (inputs) */ - int dsr_state; - int dcd_state; - int ri_state; - // int break_on; - - unsigned long tx_start_time[N_OUT_URB]; + int rts_state; /* Handshaking pins (outputs) */ + int dtr_state; + int cts_state; /* Handshaking pins (inputs) */ + int dsr_state; + int dcd_state; + int ri_state; + + unsigned long tx_start_time[N_OUT_URB]; }; @@ -190,13 +207,13 @@ static void option_break_ctl (struct usb_serial_port *port, int break_state) { /* Unfortunately, I don't know how to send a break */ - dbg("%s", __FUNCTION__); + dbg("%s", __FUNCTION__); } static void option_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct termios *old_termios) { dbg("%s", __FUNCTION__); @@ -204,10 +221,10 @@ option_set_termios (struct usb_serial_port *port, } static int -option_tiocmget(struct usb_serial_port *port, struct file *file) +option_tiocmget (struct usb_serial_port *port, struct file *file) { - unsigned int value; - struct option_port_private *portdata; + unsigned int value; + struct option_port_private *portdata; portdata = usb_get_serial_port_data(port); @@ -225,7 +242,7 @@ static int option_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear) { - struct option_port_private *portdata; + struct option_port_private *portdata; portdata = usb_get_serial_port_data(port); @@ -250,71 +267,50 @@ option_ioctl (struct usb_serial_port *port, struct file *file, /* Write */ static int -option_write(struct usb_serial_port *port, - const unsigned char *buf, int count) +option_write (struct usb_serial_port *port, + const unsigned char *buf, int count) { - struct option_port_private *portdata; - int i; - int left, todo; - struct urb *this_urb = NULL; /* spurious */ - int err; + struct option_port_private *portdata; + int i; + int left, todo; + struct urb *this_urb = NULL; /* spurious */ + int err; portdata = usb_get_serial_port_data(port); dbg("%s: write (%d chars)", __FUNCTION__, count); -#if 0 - spin_lock(&port->lock); - if (port->write_urb_busy) { - spin_unlock(&port->lock); - dbg("%s: already writing", __FUNCTION__); - return 0; - } - port->write_urb_busy = 1; - spin_unlock(&port->lock); -#endif - i = 0; left = count; - while (left>0) { + for (i=0; left > 0 && i < N_OUT_URB; i++) { todo = left; if (todo > OUT_BUFLEN) todo = OUT_BUFLEN; - for (;i < N_OUT_URB; i++) { - /* Check we have a valid urb/endpoint before we use it... */ - this_urb = portdata->out_urbs[i]; - if (this_urb->status != -EINPROGRESS) - break; + this_urb = portdata->out_urbs[i]; + if (this_urb->status == -EINPROGRESS) { if (this_urb->transfer_flags & URB_ASYNC_UNLINK) continue; if (time_before(jiffies, portdata->tx_start_time[i] + 10 * HZ)) continue; this_urb->transfer_flags |= URB_ASYNC_UNLINK; usb_unlink_urb(this_urb); + continue; } - - if (i == N_OUT_URB) { - /* no bulk out free! */ - dbg("%s: no output urb -- left %d", __FUNCTION__,count-left); -#if 0 - port->write_urb_busy = 0; -#endif - return count-left; - } + if (this_urb->status != 0) + dbg("usb_write %p failed (err=%d)", this_urb, this_urb->status); dbg("%s: endpoint %d buf %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), i); + /* send the data */ memcpy (this_urb->transfer_buffer, buf, todo); - - /* send the data out the bulk port */ this_urb->transfer_buffer_length = todo; this_urb->transfer_flags &= ~URB_ASYNC_UNLINK; this_urb->dev = port->serial->dev; err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err) { - dbg("usb_submit_urb %p (write bulk) failed (%d,, has %d)", this_urb, err, this_urb->status); + dbg("usb_submit_urb %p (write bulk) failed (%d, has %d)", this_urb, err, this_urb->status); continue; } portdata->tx_start_time[i] = jiffies; @@ -323,9 +319,6 @@ option_write(struct usb_serial_port *port, } count -= left; -#if 0 - port->write_urb_busy = 0; -#endif dbg("%s: wrote (did %d)", __FUNCTION__, count); return count; } @@ -333,7 +326,7 @@ option_write(struct usb_serial_port *port, static void option_indat_callback (struct urb *urb, struct pt_regs *regs) { - int i, err; + int i, err; int endpoint; struct usb_serial_port *port; struct tty_struct *tty; @@ -444,10 +437,11 @@ option_write_room (struct usb_serial_port *port) portdata = usb_get_serial_port_data(port); - for (i=0; i < N_OUT_URB; i++) + for (i=0; i < N_OUT_URB; i++) { this_urb = portdata->out_urbs[i]; if (this_urb && this_urb->status != -EINPROGRESS) data_len += OUT_BUFLEN; + } dbg("%s: %d", __FUNCTION__, data_len); return data_len; @@ -464,11 +458,11 @@ option_chars_in_buffer (struct usb_serial_port *port) portdata = usb_get_serial_port_data(port); - for (i=0; i < N_OUT_URB; i++) + for (i=0; i < N_OUT_URB; i++) { this_urb = portdata->out_urbs[i]; if (this_urb && this_urb->status == -EINPROGRESS) data_len += this_urb->transfer_buffer_length; - + } dbg("%s: %d", __FUNCTION__, data_len); return data_len; } @@ -477,10 +471,10 @@ option_chars_in_buffer (struct usb_serial_port *port) static int option_open (struct usb_serial_port *port, struct file *filp) { - struct option_port_private *portdata; - struct usb_serial *serial = port->serial; - int i, err; - struct urb *urb; + struct option_port_private *portdata; + struct usb_serial *serial = port->serial; + int i, err; + struct urb *urb; portdata = usb_get_serial_port_data(port); @@ -528,7 +522,7 @@ option_open (struct usb_serial_port *port, struct file *filp) } static inline void -stop_urb(struct urb *urb) +stop_urb (struct urb *urb) { if (urb && urb->status == -EINPROGRESS) { urb->transfer_flags &= ~URB_ASYNC_UNLINK; @@ -537,11 +531,11 @@ stop_urb(struct urb *urb) } static void -option_close(struct usb_serial_port *port, struct file *filp) +option_close (struct usb_serial_port *port, struct file *filp) { - int i; - struct usb_serial *serial = port->serial; - struct option_port_private *portdata; + int i; + struct usb_serial *serial = port->serial; + struct option_port_private *portdata; dbg("%s", __FUNCTION__); portdata = usb_get_serial_port_data(port); @@ -589,11 +583,11 @@ option_setup_urb (struct usb_serial *serial, int endpoint, /* Setup urbs */ static void -option_setup_urbs(struct usb_serial *serial) +option_setup_urbs (struct usb_serial *serial) { - int j; - struct usb_serial_port *port; - struct option_port_private *portdata; + int j; + struct usb_serial_port *port; + struct option_port_private *portdata; dbg("%s", __FUNCTION__); @@ -617,7 +611,7 @@ option_setup_urbs(struct usb_serial *serial) static int -option_send_setup(struct usb_serial_port *port) +option_send_setup (struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct option_port_private *portdata; @@ -644,9 +638,9 @@ option_send_setup(struct usb_serial_port *port) static int option_startup (struct usb_serial *serial) { - int i, err; - struct usb_serial_port *port; - struct option_port_private *portdata; + int i, err; + struct usb_serial_port *port; + struct option_port_private *portdata; dbg("%s", __FUNCTION__); @@ -677,9 +671,9 @@ option_startup (struct usb_serial *serial) static void option_shutdown (struct usb_serial *serial) { - int i, j; - struct usb_serial_port *port; - struct option_port_private *portdata; + int i, j; + struct usb_serial_port *port; + struct option_port_private *portdata; dbg("%s", __FUNCTION__); @@ -724,6 +718,8 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); +#ifdef CONFIG_USB_DEBUG module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug messages"); +#endif -- cgit v1.2.3 From 86cf42e4e029b83110cf98692420239103363dbf Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Tue, 19 Jul 2005 13:57:17 -0700 Subject: [ATM]: [speedtch] cure atm_printk() macro gcc-2.95 compile error Signed-off-by: Duncan Sands Signed-off-by: Chas Williams Signed-off-by: David S. Miller --- drivers/usb/atm/speedtch.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index d0cbbb7f0385..6bd581e69afd 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -448,19 +448,19 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) case 0: atm_dev->signal = ATM_PHY_SIG_LOST; if (instance->last_status) - atm_info(usbatm, "ADSL line is down\n"); + atm_info(usbatm, "%s\n", "ADSL line is down"); /* It may never resync again unless we ask it to... */ ret = speedtch_start_synchro(instance); break; case 0x08: atm_dev->signal = ATM_PHY_SIG_UNKNOWN; - atm_info(usbatm, "ADSL line is blocked?\n"); + atm_info(usbatm, "%s\n", "ADSL line is blocked?"); break; case 0x10: atm_dev->signal = ATM_PHY_SIG_LOST; - atm_info(usbatm, "ADSL line is synchronising\n"); + atm_info(usbatm, "%s\n", "ADSL line is synchronising"); break; case 0x20: @@ -502,7 +502,7 @@ static void speedtch_status_poll(unsigned long data) if (instance->poll_delay < MAX_POLL_DELAY) mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(instance->poll_delay)); else - atm_warn(instance->usbatm, "Too many failures - disabling line status polling\n"); + atm_warn(instance->usbatm, "%s\n", "Too many failures - disabling line status polling"); } static void speedtch_resubmit_int(unsigned long data) @@ -545,9 +545,9 @@ static void speedtch_handle_int(struct urb *int_urb, struct pt_regs *regs) if ((count == 6) && !memcmp(up_int, instance->int_data, 6)) { del_timer(&instance->status_checker.timer); - atm_info(usbatm, "DSL line goes up\n"); + atm_info(usbatm, "%s\n", "DSL line goes up"); } else if ((count == 6) && !memcmp(down_int, instance->int_data, 6)) { - atm_info(usbatm, "DSL line goes down\n"); + atm_info(usbatm, "%s\n", "DSL line goes down"); } else { int i; -- cgit v1.2.3 From 52fbae2a392b6e084195bedc7a280991a94c14d0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 25 Jul 2005 19:54:35 -0700 Subject: [ATM]: speedtch: Revert 86cf42e4e029b83110cf98692420239103363dbf It was already fixed more sufficiently by Andrew Morton's change 843c944fb86e5e31ee7b319172e657ea22301322. Noted by Duncan Sands. Signed-off-by: David S. Miller --- drivers/usb/atm/speedtch.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 6bd581e69afd..d0cbbb7f0385 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -448,19 +448,19 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) case 0: atm_dev->signal = ATM_PHY_SIG_LOST; if (instance->last_status) - atm_info(usbatm, "%s\n", "ADSL line is down"); + atm_info(usbatm, "ADSL line is down\n"); /* It may never resync again unless we ask it to... */ ret = speedtch_start_synchro(instance); break; case 0x08: atm_dev->signal = ATM_PHY_SIG_UNKNOWN; - atm_info(usbatm, "%s\n", "ADSL line is blocked?"); + atm_info(usbatm, "ADSL line is blocked?\n"); break; case 0x10: atm_dev->signal = ATM_PHY_SIG_LOST; - atm_info(usbatm, "%s\n", "ADSL line is synchronising"); + atm_info(usbatm, "ADSL line is synchronising\n"); break; case 0x20: @@ -502,7 +502,7 @@ static void speedtch_status_poll(unsigned long data) if (instance->poll_delay < MAX_POLL_DELAY) mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(instance->poll_delay)); else - atm_warn(instance->usbatm, "%s\n", "Too many failures - disabling line status polling"); + atm_warn(instance->usbatm, "Too many failures - disabling line status polling\n"); } static void speedtch_resubmit_int(unsigned long data) @@ -545,9 +545,9 @@ static void speedtch_handle_int(struct urb *int_urb, struct pt_regs *regs) if ((count == 6) && !memcmp(up_int, instance->int_data, 6)) { del_timer(&instance->status_checker.timer); - atm_info(usbatm, "%s\n", "DSL line goes up"); + atm_info(usbatm, "DSL line goes up\n"); } else if ((count == 6) && !memcmp(down_int, instance->int_data, 6)) { - atm_info(usbatm, "%s\n", "DSL line goes down"); + atm_info(usbatm, "DSL line goes down\n"); } else { int i; -- cgit v1.2.3 From 77933d7276ee8fa0e2947641941a6f7a100a327b Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 27 Jul 2005 11:46:09 -0700 Subject: [PATCH] clean up inline static vs static inline `gcc -W' likes to complain if the static keyword is not at the beginning of the declaration. This patch fixes all remaining occurrences of "inline static" up with "static inline" in the entire kernel tree (140 occurrences in 47 files). While making this change I came across a few lines with trailing whitespace that I also fixed up, I have also added or removed a blank line or two here and there, but there are no functional changes in the patch. Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- crypto/aes.c | 2 +- drivers/cdrom/optcd.c | 28 ++++++++++++++-------------- drivers/char/ipmi/ipmi_si_intf.c | 2 +- drivers/ide/pci/cmd640.c | 2 +- drivers/isdn/hisax/avm_a1.c | 2 +- drivers/isdn/hisax/isdnl2.c | 2 +- drivers/isdn/hisax/teles3.c | 2 +- drivers/md/md.c | 2 +- drivers/media/radio/radio-maestro.c | 4 ++-- drivers/media/radio/radio-maxiradio.c | 2 +- drivers/mmc/wbsd.c | 2 +- drivers/net/3c505.c | 2 +- drivers/net/plip.c | 29 ++++++++++++++--------------- drivers/net/via-velocity.h | 4 ++-- drivers/net/wireless/airo.c | 2 +- drivers/oprofile/cpu_buffer.c | 23 +++-------------------- drivers/s390/cio/qdio.c | 20 ++++++++++---------- drivers/s390/net/qeth.h | 26 +++++++++++++------------- drivers/scsi/dc395x.c | 2 +- drivers/scsi/fdomain.c | 2 +- drivers/usb/image/microtek.c | 3 +-- drivers/video/pm2fb.c | 16 ++++++++-------- fs/reiserfs/journal.c | 4 ++-- include/sound/vx_core.h | 16 ++++++++-------- kernel/time.c | 2 +- net/core/pktgen.c | 2 +- sound/core/seq/oss/seq_oss_device.h | 6 +++--- sound/core/seq/seq_memory.c | 4 ++-- sound/core/seq/seq_midi_event.c | 2 +- sound/drivers/serial-u16550.c | 10 +++++----- sound/isa/sb/emu8000_patch.c | 2 +- sound/oss/dmasound/dmasound_awacs.c | 4 ++-- sound/pci/cmipci.c | 14 ++++++++------ sound/pci/cs4281.c | 2 +- sound/pci/emu10k1/memory.c | 2 +- sound/pci/es1968.c | 12 ++++++------ sound/pci/maestro3.c | 8 ++++---- sound/pci/nm256/nm256.c | 16 ++++++++-------- sound/pci/trident/trident_main.c | 2 +- sound/pci/trident/trident_memory.c | 2 +- sound/pci/vx222/vx222_ops.c | 4 ++-- sound/pcmcia/vx/vxp_ops.c | 2 +- sound/ppc/burgundy.c | 4 ++-- sound/ppc/pmac.c | 8 ++++---- sound/usb/usbaudio.c | 8 ++++---- sound/usb/usbmixer.c | 4 ++-- 46 files changed, 151 insertions(+), 168 deletions(-) (limited to 'drivers/usb') diff --git a/crypto/aes.c b/crypto/aes.c index d0dd7c3c5278..5df92888ef5a 100644 --- a/crypto/aes.c +++ b/crypto/aes.c @@ -67,7 +67,7 @@ /* * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) */ -inline static u8 +static inline u8 byte(const u32 x, const unsigned n) { return x >> (n << 3); diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c index 7e69c54568bf..351a01dd503a 100644 --- a/drivers/cdrom/optcd.c +++ b/drivers/cdrom/optcd.c @@ -245,7 +245,7 @@ module_param(optcd_port, short, 0); /* Busy wait until FLAG goes low. Return 0 on timeout. */ -inline static int flag_low(int flag, unsigned long timeout) +static inline int flag_low(int flag, unsigned long timeout) { int flag_high; unsigned long count = 0; @@ -381,7 +381,7 @@ static int send_seek_params(struct cdrom_msf *params) /* Wait for command execution status. Choice between busy waiting and sleeping. Return value <0 indicates timeout. */ -inline static int get_exec_status(int busy_waiting) +static inline int get_exec_status(int busy_waiting) { unsigned char exec_status; @@ -398,7 +398,7 @@ inline static int get_exec_status(int busy_waiting) /* Wait busy for extra byte of data that a command returns. Return value <0 indicates timeout. */ -inline static int get_data(int short_timeout) +static inline int get_data(int short_timeout) { unsigned char data; @@ -441,14 +441,14 @@ static int reset_drive(void) /* Facilities for asynchronous operation */ /* Read status/data availability flags FL_STEN and FL_DTEN */ -inline static int stdt_flags(void) +static inline int stdt_flags(void) { return inb(STATUS_PORT) & FL_STDT; } /* Fetch status that has previously been waited for. <0 means not available */ -inline static int fetch_status(void) +static inline int fetch_status(void) { unsigned char status; @@ -462,7 +462,7 @@ inline static int fetch_status(void) /* Fetch data that has previously been waited for. */ -inline static void fetch_data(char *buf, int n) +static inline void fetch_data(char *buf, int n) { insb(DATA_PORT, buf, n); DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n)); @@ -470,7 +470,7 @@ inline static void fetch_data(char *buf, int n) /* Flush status and data fifos */ -inline static void flush_data(void) +static inline void flush_data(void) { while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT) inb(DATA_PORT); @@ -482,7 +482,7 @@ inline static void flush_data(void) /* Send a simple command and wait for response. Command codes < COMFETCH are quick response commands */ -inline static int exec_cmd(int cmd) +static inline int exec_cmd(int cmd) { int ack = send_cmd(cmd); if (ack < 0) @@ -493,7 +493,7 @@ inline static int exec_cmd(int cmd) /* Send a command with parameters. Don't wait for the response, * which consists of data blocks read from the CD. */ -inline static int exec_read_cmd(int cmd, struct cdrom_msf *params) +static inline int exec_read_cmd(int cmd, struct cdrom_msf *params) { int ack = send_cmd(cmd); if (ack < 0) @@ -503,7 +503,7 @@ inline static int exec_read_cmd(int cmd, struct cdrom_msf *params) /* Send a seek command with parameters and wait for response */ -inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params) +static inline int exec_seek_cmd(int cmd, struct cdrom_msf *params) { int ack = send_cmd(cmd); if (ack < 0) @@ -516,7 +516,7 @@ inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params) /* Send a command with parameters and wait for response */ -inline static int exec_long_cmd(int cmd, struct cdrom_msf *params) +static inline int exec_long_cmd(int cmd, struct cdrom_msf *params) { int ack = exec_read_cmd(cmd, params); if (ack < 0) @@ -528,7 +528,7 @@ inline static int exec_long_cmd(int cmd, struct cdrom_msf *params) /* Binary to BCD (2 digits) */ -inline static void single_bin2bcd(u_char *p) +static inline void single_bin2bcd(u_char *p) { DEBUG((DEBUG_CONV, "bin2bcd %02d", *p)); *p = (*p % 10) | ((*p / 10) << 4); @@ -565,7 +565,7 @@ static void lba2msf(int lba, struct cdrom_msf *msf) /* Two BCD digits to binary */ -inline static u_char bcd2bin(u_char bcd) +static inline u_char bcd2bin(u_char bcd) { DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd)); return (bcd >> 4) * 10 + (bcd & 0x0f); @@ -988,7 +988,7 @@ static char buf[CD_FRAMESIZE * N_BUFS]; static volatile int buf_bn[N_BUFS], next_bn; static volatile int buf_in = 0, buf_out = NOBUF; -inline static void opt_invalidate_buffers(void) +static inline void opt_invalidate_buffers(void) { int i; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 298574e16061..a44b97304e95 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1726,7 +1726,7 @@ static int dmi_table(u32 base, int len, int num) return status; } -inline static int dmi_checksum(u8 *buf) +static inline int dmi_checksum(u8 *buf) { u8 sum=0; int a; diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c index 92a2b7caed58..11d035f1983d 100644 --- a/drivers/ide/pci/cmd640.c +++ b/drivers/ide/pci/cmd640.c @@ -487,7 +487,7 @@ static void display_clocks (unsigned int index) * Pack active and recovery counts into single byte representation * used by controller */ -inline static u8 pack_nibbles (u8 upper, u8 lower) +static inline u8 pack_nibbles (u8 upper, u8 lower) { return ((upper & 0x0f) << 4) | (lower & 0x0f); } diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c index 8f028d42fd2f..9a8b02557ff9 100644 --- a/drivers/isdn/hisax/avm_a1.c +++ b/drivers/isdn/hisax/avm_a1.c @@ -135,7 +135,7 @@ avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -inline static void +static inline void release_ioregs(struct IsdnCardState *cs, int mask) { release_region(cs->hw.avm.cfg_reg, 8); diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c index 1615c1a76ab8..6d0431725555 100644 --- a/drivers/isdn/hisax/isdnl2.c +++ b/drivers/isdn/hisax/isdnl2.c @@ -213,7 +213,7 @@ sethdraddr(struct Layer2 *l2, u_char * header, int rsp) } } -inline static void +static inline void enqueue_super(struct PStack *st, struct sk_buff *skb) { diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c index adeaad62d35c..a3eaf4d65707 100644 --- a/drivers/isdn/hisax/teles3.c +++ b/drivers/isdn/hisax/teles3.c @@ -143,7 +143,7 @@ teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -inline static void +static inline void release_ioregs(struct IsdnCardState *cs, int mask) { if (mask & 1) diff --git a/drivers/md/md.c b/drivers/md/md.c index 4a0c57db2b67..6580e0fa4a47 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -284,7 +284,7 @@ static mdk_rdev_t * find_rdev(mddev_t * mddev, dev_t dev) return NULL; } -inline static sector_t calc_dev_sboffset(struct block_device *bdev) +static inline sector_t calc_dev_sboffset(struct block_device *bdev) { sector_t size = bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; return MD_NEW_SIZE_BLOCKS(size); diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index e62147e4ed1b..e5e2021a7312 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -154,7 +154,7 @@ static void radio_bits_set(struct radio_device *dev, __u32 data) msleep(125); } -inline static int radio_function(struct inode *inode, struct file *file, +static inline int radio_function(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); @@ -283,7 +283,7 @@ static int __init maestro_radio_init(void) module_init(maestro_radio_init); module_exit(maestro_radio_exit); -inline static __u16 radio_power_on(struct radio_device *dev) +static inline __u16 radio_power_on(struct radio_device *dev) { register __u16 io=dev->io; register __u32 ofreq; diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 5b748a48ce72..02d39a50d5ed 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -166,7 +166,7 @@ static int get_tune(__u16 io) } -inline static int radio_function(struct inode *inode, struct file *file, +static inline int radio_function(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 0c41d4b41a65..8b487ed1069c 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1053,7 +1053,7 @@ static void wbsd_detect_card(unsigned long data) * Tasklets */ -inline static struct mmc_data* wbsd_get_data(struct wbsd_host* host) +static inline struct mmc_data* wbsd_get_data(struct wbsd_host* host) { WARN_ON(!host->mrq); if (!host->mrq) diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index ad17f17e8e7a..111601ca4ca3 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -272,7 +272,7 @@ static inline void set_hsf(struct net_device *dev, int hsf) static int start_receive(struct net_device *, pcb_struct *); -inline static void adapter_reset(struct net_device *dev) +static inline void adapter_reset(struct net_device *dev) { unsigned long timeout; elp_device *adapter = dev->priv; diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 21537ee3a6a7..1bd22cd40c75 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -160,7 +160,7 @@ static struct net_device_stats *plip_get_stats(struct net_device *dev); static int plip_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int plip_preempt(void *handle); static void plip_wakeup(void *handle); - + enum plip_connection_state { PLIP_CN_NONE=0, PLIP_CN_RECEIVE, @@ -231,8 +231,8 @@ struct net_local { atomic_t kill_timer; struct semaphore killed_timer_sem; }; - -inline static void enable_parport_interrupts (struct net_device *dev) + +static inline void enable_parport_interrupts (struct net_device *dev) { if (dev->irq != -1) { @@ -242,7 +242,7 @@ inline static void enable_parport_interrupts (struct net_device *dev) } } -inline static void disable_parport_interrupts (struct net_device *dev) +static inline void disable_parport_interrupts (struct net_device *dev) { if (dev->irq != -1) { @@ -252,7 +252,7 @@ inline static void disable_parport_interrupts (struct net_device *dev) } } -inline static void write_data (struct net_device *dev, unsigned char data) +static inline void write_data (struct net_device *dev, unsigned char data) { struct parport *port = ((struct net_local *)dev->priv)->pardev->port; @@ -260,14 +260,14 @@ inline static void write_data (struct net_device *dev, unsigned char data) port->ops->write_data (port, data); } -inline static unsigned char read_status (struct net_device *dev) +static inline unsigned char read_status (struct net_device *dev) { struct parport *port = ((struct net_local *)dev->priv)->pardev->port; return port->ops->read_status (port); } - + /* Entry point of PLIP driver. Probe the hardware, and register/initialize the driver. @@ -316,7 +316,7 @@ plip_init_netdev(struct net_device *dev) spin_lock_init(&nl->lock); } - + /* Bottom half handler for the delayed request. This routine is kicked by do_timer(). Request `plip_bh' to be invoked. */ @@ -471,7 +471,7 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, return TIMEOUT; } - + static int plip_none(struct net_device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv) @@ -481,7 +481,7 @@ plip_none(struct net_device *dev, struct net_local *nl, /* PLIP_RECEIVE --- receive a byte(two nibbles) Returns OK on success, TIMEOUT on timeout */ -inline static int +static inline int plip_receive(unsigned short nibble_timeout, struct net_device *dev, enum plip_nibble_state *ns_p, unsigned char *data_p) { @@ -582,7 +582,6 @@ static __be16 plip_type_trans(struct sk_buff *skb, struct net_device *dev) return htons(ETH_P_802_2); } - /* PLIP_RECEIVE_PACKET --- receive a packet */ static int plip_receive_packet(struct net_device *dev, struct net_local *nl, @@ -702,7 +701,7 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl, /* PLIP_SEND --- send a byte (two nibbles) Returns OK on success, TIMEOUT when timeout */ -inline static int +static inline int plip_send(unsigned short nibble_timeout, struct net_device *dev, enum plip_nibble_state *ns_p, unsigned char data) { @@ -902,7 +901,7 @@ plip_error(struct net_device *dev, struct net_local *nl, return OK; } - + /* Handle the parallel port interrupts. */ static void plip_interrupt(int irq, void *dev_id, struct pt_regs * regs) @@ -957,7 +956,7 @@ plip_interrupt(int irq, void *dev_id, struct pt_regs * regs) spin_unlock_irq(&nl->lock); } - + static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev) { @@ -1238,7 +1237,7 @@ plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } return 0; } - + static int parport[PLIP_MAX] = { [0 ... PLIP_MAX-1] = -1 }; static int timid; diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index 1b70b7c97580..d9a774b91ddc 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -1414,7 +1414,7 @@ static inline void mac_get_cam(struct mac_regs __iomem * regs, int idx, u8 *addr * the rest of the logic from the result of sleep/wakeup */ -inline static void mac_wol_reset(struct mac_regs __iomem * regs) +static inline void mac_wol_reset(struct mac_regs __iomem * regs) { /* Turn off SWPTAG right after leaving power mode */ @@ -1811,7 +1811,7 @@ struct velocity_info { * CHECK ME: locking */ -inline static int velocity_get_ip(struct velocity_info *vptr) +static inline int velocity_get_ip(struct velocity_info *vptr) { struct in_device *in_dev = (struct in_device *) vptr->dev->ip_ptr; struct in_ifaddr *ifa; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 47f3c5d0203d..df20adcd0730 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -5013,7 +5013,7 @@ static void proc_SSID_on_close( struct inode *inode, struct file *file ) { enable_MAC(ai, &rsp, 1); } -inline static u8 hexVal(char c) { +static inline u8 hexVal(char c) { if (c>='0' && c<='9') return c -= '0'; if (c>='a' && c<='f') return c -= 'a'-10; if (c>='A' && c<='F') return c -= 'A'-10; diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index e9b1772a3a28..026f671ea558 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -42,8 +42,7 @@ void free_cpu_buffers(void) vfree(cpu_buffer[i].buffer); } } - - + int alloc_cpu_buffers(void) { int i; @@ -74,7 +73,6 @@ fail: free_cpu_buffers(); return -ENOMEM; } - void start_cpu_work(void) { @@ -93,7 +91,6 @@ void start_cpu_work(void) } } - void end_cpu_work(void) { int i; @@ -109,7 +106,6 @@ void end_cpu_work(void) flush_scheduled_work(); } - /* Resets the cpu buffer to a sane state. */ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf) { @@ -121,7 +117,6 @@ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf) cpu_buf->last_task = NULL; } - /* compute number of available slots in cpu_buffer queue */ static unsigned long nr_available_slots(struct oprofile_cpu_buffer const * b) { @@ -134,7 +129,6 @@ static unsigned long nr_available_slots(struct oprofile_cpu_buffer const * b) return tail + (b->buffer_size - head) - 1; } - static void increment_head(struct oprofile_cpu_buffer * b) { unsigned long new_head = b->head_pos + 1; @@ -149,10 +143,7 @@ static void increment_head(struct oprofile_cpu_buffer * b) b->head_pos = 0; } - - - -inline static void +static inline void add_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc, unsigned long event) { @@ -162,14 +153,12 @@ add_sample(struct oprofile_cpu_buffer * cpu_buf, increment_head(cpu_buf); } - -inline static void +static inline void add_code(struct oprofile_cpu_buffer * buffer, unsigned long value) { add_sample(buffer, ESCAPE_CODE, value); } - /* This must be safe from any context. It's safe writing here * because of the head/tail separation of the writer and reader * of the CPU buffer. @@ -223,13 +212,11 @@ static int oprofile_begin_trace(struct oprofile_cpu_buffer * cpu_buf) return 1; } - static void oprofile_end_trace(struct oprofile_cpu_buffer * cpu_buf) { cpu_buf->tracing = 0; } - void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) { struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; @@ -251,14 +238,12 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) oprofile_end_trace(cpu_buf); } - void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) { struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; log_sample(cpu_buf, pc, is_kernel, event); } - void oprofile_add_trace(unsigned long pc) { struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; @@ -283,8 +268,6 @@ void oprofile_add_trace(unsigned long pc) add_sample(cpu_buf, pc, 0); } - - /* * This serves to avoid cpu buffer overflow, and makes sure * the task mortuary progresses diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 82194c4eadfb..d36258d6665f 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -432,7 +432,7 @@ tiqdio_clear_global_summary(void) /************************* OUTBOUND ROUTINES *******************************/ -inline static int +static inline int qdio_get_outbound_buffer_frontier(struct qdio_q *q) { int f,f_mod_no; @@ -510,7 +510,7 @@ out: } /* all buffers are processed */ -inline static int +static inline int qdio_is_outbound_q_done(struct qdio_q *q) { int no_used; @@ -532,7 +532,7 @@ qdio_is_outbound_q_done(struct qdio_q *q) return (no_used==0); } -inline static int +static inline int qdio_has_outbound_q_moved(struct qdio_q *q) { int i; @@ -552,7 +552,7 @@ qdio_has_outbound_q_moved(struct qdio_q *q) } } -inline static void +static inline void qdio_kick_outbound_q(struct qdio_q *q) { int result; @@ -641,7 +641,7 @@ qdio_kick_outbound_q(struct qdio_q *q) } } -inline static void +static inline void qdio_kick_outbound_handler(struct qdio_q *q) { int start, end, real_end, count; @@ -740,7 +740,7 @@ qdio_outbound_processing(struct qdio_q *q) /************************* INBOUND ROUTINES *******************************/ -inline static int +static inline int qdio_get_inbound_buffer_frontier(struct qdio_q *q) { int f,f_mod_no; @@ -865,7 +865,7 @@ out: return q->first_to_check; } -inline static int +static inline int qdio_has_inbound_q_moved(struct qdio_q *q) { int i; @@ -898,7 +898,7 @@ qdio_has_inbound_q_moved(struct qdio_q *q) } /* means, no more buffers to be filled */ -inline static int +static inline int tiqdio_is_inbound_q_done(struct qdio_q *q) { int no_used; @@ -951,7 +951,7 @@ tiqdio_is_inbound_q_done(struct qdio_q *q) return 0; } -inline static int +static inline int qdio_is_inbound_q_done(struct qdio_q *q) { int no_used; @@ -1010,7 +1010,7 @@ qdio_is_inbound_q_done(struct qdio_q *q) } } -inline static void +static inline void qdio_kick_inbound_handler(struct qdio_q *q) { int count, start, end, real_end, i; diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 008e0a5d2eb3..3a0285669adf 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -824,7 +824,7 @@ extern struct list_head qeth_notify_list; #define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "") -inline static __u8 +static inline __u8 qeth_get_ipa_adp_type(enum qeth_link_types link_type) { switch (link_type) { @@ -835,7 +835,7 @@ qeth_get_ipa_adp_type(enum qeth_link_types link_type) } } -inline static int +static inline int qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size) { struct sk_buff *new_skb = NULL; @@ -852,6 +852,7 @@ qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size) } return 0; } + static inline struct sk_buff * qeth_pskb_unshare(struct sk_buff *skb, int pri) { @@ -863,8 +864,7 @@ qeth_pskb_unshare(struct sk_buff *skb, int pri) return nskb; } - -inline static void * +static inline void * qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size) { void *hdr; @@ -887,7 +887,7 @@ qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size) } -inline static int +static inline int qeth_get_hlen(__u8 link_type) { #ifdef CONFIG_QETH_IPV6 @@ -911,7 +911,7 @@ qeth_get_hlen(__u8 link_type) #endif /* CONFIG_QETH_IPV6 */ } -inline static unsigned short +static inline unsigned short qeth_get_netdev_flags(struct qeth_card *card) { if (card->options.layer2) @@ -929,7 +929,7 @@ qeth_get_netdev_flags(struct qeth_card *card) } } -inline static int +static inline int qeth_get_initial_mtu_for_card(struct qeth_card * card) { switch (card->info.type) { @@ -950,7 +950,7 @@ qeth_get_initial_mtu_for_card(struct qeth_card * card) } } -inline static int +static inline int qeth_get_max_mtu_for_card(int cardtype) { switch (cardtype) { @@ -965,7 +965,7 @@ qeth_get_max_mtu_for_card(int cardtype) } } -inline static int +static inline int qeth_get_mtu_out_of_mpc(int cardtype) { switch (cardtype) { @@ -976,7 +976,7 @@ qeth_get_mtu_out_of_mpc(int cardtype) } } -inline static int +static inline int qeth_get_mtu_outof_framesize(int framesize) { switch (framesize) { @@ -993,7 +993,7 @@ qeth_get_mtu_outof_framesize(int framesize) } } -inline static int +static inline int qeth_mtu_is_valid(struct qeth_card * card, int mtu) { switch (card->info.type) { @@ -1008,7 +1008,7 @@ qeth_mtu_is_valid(struct qeth_card * card, int mtu) } } -inline static int +static inline int qeth_get_arphdr_type(int cardtype, int linktype) { switch (cardtype) { @@ -1027,7 +1027,7 @@ qeth_get_arphdr_type(int cardtype, int linktype) } #ifdef CONFIG_QETH_PERF_STATS -inline static int +static inline int qeth_get_micros(void) { return (int) (get_clock() >> 12); diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index ae13c002f60d..929170dcd3cb 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -744,7 +744,7 @@ static void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) /* Find cmd in SRB list */ -inline static struct ScsiReqBlk *find_cmd(struct scsi_cmnd *cmd, +static inline struct ScsiReqBlk *find_cmd(struct scsi_cmnd *cmd, struct list_head *head) { struct ScsiReqBlk *i; diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index aecf32dd0bde..3b2a5bf5c43e 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -570,7 +570,7 @@ static void do_pause(unsigned amount) /* Pause for amount*10 milliseconds */ mdelay(10*amount); } -inline static void fdomain_make_bus_idle( void ) +static inline void fdomain_make_bus_idle( void ) { outb(0, port_base + SCSI_Cntl); outb(0, port_base + SCSI_Mode_Cntl); diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 7d21a4f5c425..c84e1486054f 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -361,8 +361,7 @@ int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback ); static void mts_transfer_cleanup( struct urb *transfer ); static void mts_do_sg(struct urb * transfer, struct pt_regs *regs); - -inline static +static inline void mts_int_submit_urb (struct urb* transfer, int pipe, void* data, diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 5dceddedf507..42c17efa9fb0 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -138,27 +138,27 @@ static struct fb_var_screeninfo pm2fb_var __devinitdata = { * Utility functions */ -inline static u32 RD32(unsigned char __iomem *base, s32 off) +static inline u32 RD32(unsigned char __iomem *base, s32 off) { return fb_readl(base + off); } -inline static void WR32(unsigned char __iomem *base, s32 off, u32 v) +static inline void WR32(unsigned char __iomem *base, s32 off, u32 v) { fb_writel(v, base + off); } -inline static u32 pm2_RD(struct pm2fb_par* p, s32 off) +static inline u32 pm2_RD(struct pm2fb_par* p, s32 off) { return RD32(p->v_regs, off); } -inline static void pm2_WR(struct pm2fb_par* p, s32 off, u32 v) +static inline void pm2_WR(struct pm2fb_par* p, s32 off, u32 v) { WR32(p->v_regs, off, v); } -inline static u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx) +static inline u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx) { int index = PM2R_RD_INDEXED_DATA; switch (p->type) { @@ -174,7 +174,7 @@ inline static u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx) return pm2_RD(p, index); } -inline static void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) +static inline void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) { int index = PM2R_RD_INDEXED_DATA; switch (p->type) { @@ -190,7 +190,7 @@ inline static void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) pm2_WR(p, index, v); } -inline static void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) +static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) { pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); mb(); @@ -200,7 +200,7 @@ inline static void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT #define WAIT_FIFO(p,a) #else -inline static void WAIT_FIFO(struct pm2fb_par* p, u32 a) +static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) { while( pm2_RD(p, PM2R_IN_FIFO_SPACE) < a ); mb(); diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index c66c27ec4100..ca7989b04be3 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -556,14 +556,14 @@ static inline void insert_journal_hash(struct reiserfs_journal_cnode **table, } /* lock the current transaction */ -inline static void lock_journal(struct super_block *p_s_sb) +static inline void lock_journal(struct super_block *p_s_sb) { PROC_INFO_INC(p_s_sb, journal.lock_journal); down(&SB_JOURNAL(p_s_sb)->j_lock); } /* unlock the current transaction */ -inline static void unlock_journal(struct super_block *p_s_sb) +static inline void unlock_journal(struct super_block *p_s_sb) { up(&SB_JOURNAL(p_s_sb)->j_lock); } diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h index a7e29933f2d0..7a60a3888667 100644 --- a/include/sound/vx_core.h +++ b/include/sound/vx_core.h @@ -233,37 +233,37 @@ irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs); /* * lowlevel functions */ -inline static int vx_test_and_ack(vx_core_t *chip) +static inline int vx_test_and_ack(vx_core_t *chip) { snd_assert(chip->ops->test_and_ack, return -ENXIO); return chip->ops->test_and_ack(chip); } -inline static void vx_validate_irq(vx_core_t *chip, int enable) +static inline void vx_validate_irq(vx_core_t *chip, int enable) { snd_assert(chip->ops->validate_irq, return); chip->ops->validate_irq(chip, enable); } -inline static unsigned char snd_vx_inb(vx_core_t *chip, int reg) +static inline unsigned char snd_vx_inb(vx_core_t *chip, int reg) { snd_assert(chip->ops->in8, return 0); return chip->ops->in8(chip, reg); } -inline static unsigned int snd_vx_inl(vx_core_t *chip, int reg) +static inline unsigned int snd_vx_inl(vx_core_t *chip, int reg) { snd_assert(chip->ops->in32, return 0); return chip->ops->in32(chip, reg); } -inline static void snd_vx_outb(vx_core_t *chip, int reg, unsigned char val) +static inline void snd_vx_outb(vx_core_t *chip, int reg, unsigned char val) { snd_assert(chip->ops->out8, return); chip->ops->out8(chip, reg, val); } -inline static void snd_vx_outl(vx_core_t *chip, int reg, unsigned int val) +static inline void snd_vx_outl(vx_core_t *chip, int reg, unsigned int val) { snd_assert(chip->ops->out32, return); chip->ops->out32(chip, reg, val); @@ -303,14 +303,14 @@ int snd_vx_check_reg_bit(vx_core_t *chip, int reg, int mask, int bit, int time); /* * pseudo-DMA transfer */ -inline static void vx_pseudo_dma_write(vx_core_t *chip, snd_pcm_runtime_t *runtime, +static inline void vx_pseudo_dma_write(vx_core_t *chip, snd_pcm_runtime_t *runtime, vx_pipe_t *pipe, int count) { snd_assert(chip->ops->dma_write, return); chip->ops->dma_write(chip, runtime, pipe, count); } -inline static void vx_pseudo_dma_read(vx_core_t *chip, snd_pcm_runtime_t *runtime, +static inline void vx_pseudo_dma_read(vx_core_t *chip, snd_pcm_runtime_t *runtime, vx_pipe_t *pipe, int count) { snd_assert(chip->ops->dma_read, return); diff --git a/kernel/time.c b/kernel/time.c index d4335c1c884c..dd5ae1162a8f 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -128,7 +128,7 @@ asmlinkage long sys_gettimeofday(struct timeval __user *tv, struct timezone __us * as real UNIX machines always do it. This avoids all headaches about * daylight saving times and warping kernel clocks. */ -inline static void warp_clock(void) +static inline void warp_clock(void) { write_seqlock_irq(&xtime_lock); wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 975d651312dc..8eb083b6041a 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -363,7 +363,7 @@ struct pktgen_thread { * All Rights Reserved. * */ -inline static s64 divremdi3(s64 x, s64 y, int type) +static inline s64 divremdi3(s64 x, s64 y, int type) { u64 a = (x < 0) ? -x : x; u64 b = (y < 0) ? -y : y; diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h index da23c4db8dd5..973786758c55 100644 --- a/sound/core/seq/oss/seq_oss_device.h +++ b/sound/core/seq/oss/seq_oss_device.h @@ -158,21 +158,21 @@ void snd_seq_oss_readq_info_read(seq_oss_readq_t *q, snd_info_buffer_t *buf); #define is_nonblock_mode(mode) ((mode) & SNDRV_SEQ_OSS_FILE_NONBLOCK) /* dispatch event */ -inline static int +static inline int snd_seq_oss_dispatch(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int atomic, int hop) { return snd_seq_kernel_client_dispatch(dp->cseq, ev, atomic, hop); } /* ioctl */ -inline static int +static inline int snd_seq_oss_control(seq_oss_devinfo_t *dp, unsigned int type, void *arg) { return snd_seq_kernel_client_ctl(dp->cseq, type, arg); } /* fill the addresses in header */ -inline static void +static inline void snd_seq_oss_fill_addr(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int dest_client, int dest_port) { diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index 00d841e82fbc..03acb2d519ba 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -36,12 +36,12 @@ #define semaphore_of(fp) ((fp)->f_dentry->d_inode->i_sem) -inline static int snd_seq_pool_available(pool_t *pool) +static inline int snd_seq_pool_available(pool_t *pool) { return pool->total_elements - atomic_read(&pool->counter); } -inline static int snd_seq_output_ok(pool_t *pool) +static inline int snd_seq_output_ok(pool_t *pool) { return snd_seq_pool_available(pool) >= pool->room; } diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index df1e2bb39745..603b63716db6 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c @@ -146,7 +146,7 @@ void snd_midi_event_free(snd_midi_event_t *dev) /* * initialize record */ -inline static void reset_encode(snd_midi_event_t *dev) +static inline void reset_encode(snd_midi_event_t *dev) { dev->read = 0; dev->qlen = 0; diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 964b97e70c84..986df35fb829 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -168,7 +168,7 @@ typedef struct _snd_uart16550 { static snd_card_t *snd_serial_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; -inline static void snd_uart16550_add_timer(snd_uart16550_t *uart) +static inline void snd_uart16550_add_timer(snd_uart16550_t *uart) { if (! uart->timer_running) { /* timer 38600bps * 10bit * 16byte */ @@ -178,7 +178,7 @@ inline static void snd_uart16550_add_timer(snd_uart16550_t *uart) } } -inline static void snd_uart16550_del_timer(snd_uart16550_t *uart) +static inline void snd_uart16550_del_timer(snd_uart16550_t *uart) { if (uart->timer_running) { del_timer(&uart->buffer_timer); @@ -187,7 +187,7 @@ inline static void snd_uart16550_del_timer(snd_uart16550_t *uart) } /* This macro is only used in snd_uart16550_io_loop */ -inline static void snd_uart16550_buffer_output(snd_uart16550_t *uart) +static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart) { unsigned short buff_out = uart->buff_out; if( uart->buff_in_count > 0 ) { @@ -579,7 +579,7 @@ static int snd_uart16550_output_close(snd_rawmidi_substream_t * substream) return 0; }; -inline static int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num ) +static inline int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num ) { if( uart->buff_in_count + Num < TX_BUFF_SIZE ) return 1; @@ -587,7 +587,7 @@ inline static int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num return 0; } -inline static int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte) +static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte) { unsigned short buff_in = uart->buff_in; if( uart->buff_in_count < TX_BUFF_SIZE ) { diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c index 4afc4a1bc140..26e693078cb3 100644 --- a/sound/isa/sb/emu8000_patch.c +++ b/sound/isa/sb/emu8000_patch.c @@ -128,7 +128,7 @@ snd_emu8000_write_wait(emu8000_t *emu) * This is therefore much slower than need be, but is at least * working. */ -inline static void +static inline void write_word(emu8000_t *emu, int *offset, unsigned short data) { if (emu8000_reset_addr) { diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c index 2704e1598add..2ceb46f1d40f 100644 --- a/sound/oss/dmasound/dmasound_awacs.c +++ b/sound/oss/dmasound/dmasound_awacs.c @@ -1557,7 +1557,7 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when) /* All the burgundy functions: */ /* Waits for busy flag to clear */ -inline static void +static inline void awacs_burgundy_busy_wait(void) { int count = 50; /* > 2 samples at 44k1 */ @@ -1565,7 +1565,7 @@ awacs_burgundy_busy_wait(void) udelay(1) ; } -inline static void +static inline void awacs_burgundy_extend_wait(void) { int count = 50 ; /* > 2 samples at 44k1 */ diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index b4503385ea69..4725b4a010be 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -488,32 +488,34 @@ struct snd_stru_cmipci { /* read/write operations for dword register */ -inline static void snd_cmipci_write(cmipci_t *cm, unsigned int cmd, unsigned int data) +static inline void snd_cmipci_write(cmipci_t *cm, unsigned int cmd, unsigned int data) { outl(data, cm->iobase + cmd); } -inline static unsigned int snd_cmipci_read(cmipci_t *cm, unsigned int cmd) + +static inline unsigned int snd_cmipci_read(cmipci_t *cm, unsigned int cmd) { return inl(cm->iobase + cmd); } /* read/write operations for word register */ -inline static void snd_cmipci_write_w(cmipci_t *cm, unsigned int cmd, unsigned short data) +static inline void snd_cmipci_write_w(cmipci_t *cm, unsigned int cmd, unsigned short data) { outw(data, cm->iobase + cmd); } -inline static unsigned short snd_cmipci_read_w(cmipci_t *cm, unsigned int cmd) + +static inline unsigned short snd_cmipci_read_w(cmipci_t *cm, unsigned int cmd) { return inw(cm->iobase + cmd); } /* read/write operations for byte register */ -inline static void snd_cmipci_write_b(cmipci_t *cm, unsigned int cmd, unsigned char data) +static inline void snd_cmipci_write_b(cmipci_t *cm, unsigned int cmd, unsigned char data) { outb(data, cm->iobase + cmd); } -inline static unsigned char snd_cmipci_read_b(cmipci_t *cm, unsigned int cmd) +static inline unsigned char snd_cmipci_read_b(cmipci_t *cm, unsigned int cmd) { return inb(cm->iobase + cmd); } diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index eb3c52b03af3..c7a370d4f923 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -542,7 +542,7 @@ static void snd_cs4281_delay(unsigned int delay) } } -inline static void snd_cs4281_delay_long(void) +static inline void snd_cs4281_delay_long(void) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 7a595f0dd7a1..6afeaeab3e13 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -495,7 +495,7 @@ static int synth_free_pages(emu10k1_t *emu, emu10k1_memblk_t *blk) } /* calculate buffer pointer from offset address */ -inline static void *offset_ptr(emu10k1_t *emu, int page, int offset) +static inline void *offset_ptr(emu10k1_t *emu, int page, int offset) { char *ptr; snd_assert(page >= 0 && page < emu->max_cache_pages, return NULL); diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index ea889b311390..327a341e276b 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -636,7 +636,7 @@ static void __maestro_write(es1968_t *chip, u16 reg, u16 data) chip->maestro_map[reg] = data; } -inline static void maestro_write(es1968_t *chip, u16 reg, u16 data) +static inline void maestro_write(es1968_t *chip, u16 reg, u16 data) { unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); @@ -654,7 +654,7 @@ static u16 __maestro_read(es1968_t *chip, u16 reg) return chip->maestro_map[reg]; } -inline static u16 maestro_read(es1968_t *chip, u16 reg) +static inline u16 maestro_read(es1968_t *chip, u16 reg) { unsigned long flags; u16 result; @@ -755,7 +755,7 @@ static void __apu_set_register(es1968_t *chip, u16 channel, u8 reg, u16 data) apu_data_set(chip, data); } -inline static void apu_set_register(es1968_t *chip, u16 channel, u8 reg, u16 data) +static inline void apu_set_register(es1968_t *chip, u16 channel, u8 reg, u16 data) { unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); @@ -771,7 +771,7 @@ static u16 __apu_get_register(es1968_t *chip, u16 channel, u8 reg) return __maestro_read(chip, IDR0_DATA_PORT); } -inline static u16 apu_get_register(es1968_t *chip, u16 channel, u8 reg) +static inline u16 apu_get_register(es1968_t *chip, u16 channel, u8 reg) { unsigned long flags; u16 v; @@ -957,7 +957,7 @@ static u32 snd_es1968_compute_rate(es1968_t *chip, u32 freq) } /* get current pointer */ -inline static unsigned int +static inline unsigned int snd_es1968_get_dma_ptr(es1968_t *chip, esschan_t *es) { unsigned int offset; @@ -978,7 +978,7 @@ static void snd_es1968_apu_set_freq(es1968_t *chip, int apu, int freq) } /* spin lock held */ -inline static void snd_es1968_trigger_apu(es1968_t *esm, int apu, int mode) +static inline void snd_es1968_trigger_apu(es1968_t *esm, int apu, int mode) { /* set the APU mode */ __apu_set_register(esm, apu, 0, diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 096f15132853..52c585901c54 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1055,22 +1055,22 @@ static struct m3_hv_quirk m3_hv_quirk_list[] = { schedule_timeout(((msec) * HZ) / 1000);\ } while (0) -inline static void snd_m3_outw(m3_t *chip, u16 value, unsigned long reg) +static inline void snd_m3_outw(m3_t *chip, u16 value, unsigned long reg) { outw(value, chip->iobase + reg); } -inline static u16 snd_m3_inw(m3_t *chip, unsigned long reg) +static inline u16 snd_m3_inw(m3_t *chip, unsigned long reg) { return inw(chip->iobase + reg); } -inline static void snd_m3_outb(m3_t *chip, u8 value, unsigned long reg) +static inline void snd_m3_outb(m3_t *chip, u8 value, unsigned long reg) { outb(value, chip->iobase + reg); } -inline static u8 snd_m3_inb(m3_t *chip, unsigned long reg) +static inline u8 snd_m3_inb(m3_t *chip, unsigned long reg) { return inb(chip->iobase + reg); } diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 8a52091f8552..7eb20b8f89f6 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -285,43 +285,43 @@ MODULE_DEVICE_TABLE(pci, snd_nm256_ids); * lowlvel stuffs */ -inline static u8 +static inline u8 snd_nm256_readb(nm256_t *chip, int offset) { return readb(chip->cport + offset); } -inline static u16 +static inline u16 snd_nm256_readw(nm256_t *chip, int offset) { return readw(chip->cport + offset); } -inline static u32 +static inline u32 snd_nm256_readl(nm256_t *chip, int offset) { return readl(chip->cport + offset); } -inline static void +static inline void snd_nm256_writeb(nm256_t *chip, int offset, u8 val) { writeb(val, chip->cport + offset); } -inline static void +static inline void snd_nm256_writew(nm256_t *chip, int offset, u16 val) { writew(val, chip->cport + offset); } -inline static void +static inline void snd_nm256_writel(nm256_t *chip, int offset, u32 val) { writel(val, chip->cport + offset); } -inline static void +static inline void snd_nm256_write_buffer(nm256_t *chip, void *src, int offset, int size) { offset -= chip->buffer_start; @@ -926,7 +926,7 @@ snd_nm256_init_chip(nm256_t *chip) } -inline static void +static inline void snd_nm256_intr_check(nm256_t *chip) { if (chip->badintrcount++ > 1000) { diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index ccd5ca2ba16f..a09b0fb49e81 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3204,7 +3204,7 @@ static inline void snd_trident_free_gameport(trident_t *chip) { } /* * delay for 1 tick */ -inline static void do_delay(trident_t *chip) +static inline void do_delay(trident_t *chip) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index 6cc282681e09..333d3790692a 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c @@ -118,7 +118,7 @@ static inline void set_silent_tlb(trident_t *trident, int page) #endif /* PAGE_SIZE */ /* calculate buffer pointer from offset address */ -inline static void *offset_ptr(trident_t *trident, int offset) +static inline void *offset_ptr(trident_t *trident, int offset) { char *ptr; ptr = page_to_ptr(trident, get_aligned_page(offset)); diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 683e9799976f..967bd5e6b23c 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -82,7 +82,7 @@ static int vx2_reg_index[VX_REG_MAX] = { [VX_GPIOC] = 0, /* on the PLX */ }; -inline static unsigned long vx2_reg_addr(vx_core_t *_chip, int reg) +static inline unsigned long vx2_reg_addr(vx_core_t *_chip, int reg) { struct snd_vx222 *chip = (struct snd_vx222 *)_chip; return chip->port[vx2_reg_index[reg]] + vx2_reg_offset[reg]; @@ -235,7 +235,7 @@ static void vx2_setup_pseudo_dma(vx_core_t *chip, int do_write) /* * vx_release_pseudo_dma - disable the pseudo-DMA mode */ -inline static void vx2_release_pseudo_dma(vx_core_t *chip) +static inline void vx2_release_pseudo_dma(vx_core_t *chip) { /* HREQ pin disabled. */ vx_outl(chip, ICR, 0); diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c index ef6734271607..6f15c3d03ab5 100644 --- a/sound/pcmcia/vx/vxp_ops.c +++ b/sound/pcmcia/vx/vxp_ops.c @@ -49,7 +49,7 @@ static int vxp_reg_offset[VX_REG_MAX] = { }; -inline static unsigned long vxp_reg_addr(vx_core_t *_chip, int reg) +static inline unsigned long vxp_reg_addr(vx_core_t *_chip, int reg) { struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; return chip->port + vxp_reg_offset[reg]; diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c index 3f837d9f3eb1..edbc0484e22a 100644 --- a/sound/ppc/burgundy.c +++ b/sound/ppc/burgundy.c @@ -30,7 +30,7 @@ /* Waits for busy flag to clear */ -inline static void +static inline void snd_pmac_burgundy_busy_wait(pmac_t *chip) { int timeout = 50; @@ -40,7 +40,7 @@ snd_pmac_burgundy_busy_wait(pmac_t *chip) printk(KERN_DEBUG "burgundy_busy_wait: timeout\n"); } -inline static void +static inline void snd_pmac_burgundy_extend_wait(pmac_t *chip) { int timeout; diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 75b8b7423036..844d76152ea2 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -153,7 +153,7 @@ static pmac_stream_t *snd_pmac_get_stream(pmac_t *chip, int stream) /* * wait while run status is on */ -inline static void +static inline void snd_pmac_wait_ack(pmac_stream_t *rec) { int timeout = 50000; @@ -177,7 +177,7 @@ static void snd_pmac_pcm_set_format(pmac_t *chip) /* * stop the DMA transfer */ -inline static void snd_pmac_dma_stop(pmac_stream_t *rec) +static inline void snd_pmac_dma_stop(pmac_stream_t *rec) { out_le32(&rec->dma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); snd_pmac_wait_ack(rec); @@ -186,7 +186,7 @@ inline static void snd_pmac_dma_stop(pmac_stream_t *rec) /* * set the command pointer address */ -inline static void snd_pmac_dma_set_command(pmac_stream_t *rec, pmac_dbdma_t *cmd) +static inline void snd_pmac_dma_set_command(pmac_stream_t *rec, pmac_dbdma_t *cmd) { out_le32(&rec->dma->cmdptr, cmd->addr); } @@ -194,7 +194,7 @@ inline static void snd_pmac_dma_set_command(pmac_stream_t *rec, pmac_dbdma_t *cm /* * start the DMA */ -inline static void snd_pmac_dma_run(pmac_stream_t *rec, int status) +static inline void snd_pmac_dma_run(pmac_stream_t *rec, int status) { out_le32(&rec->dma->control, status | (status << 16)); } diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a75695045f29..b5e734d975e0 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -212,7 +212,7 @@ static snd_usb_audio_t *usb_chip[SNDRV_CARDS]; * convert a sampling rate into our full speed format (fs/1000 in Q16.16) * this will overflow at approx 524 kHz */ -inline static unsigned get_usb_full_speed_rate(unsigned int rate) +static inline unsigned get_usb_full_speed_rate(unsigned int rate) { return ((rate << 13) + 62) / 125; } @@ -221,19 +221,19 @@ inline static unsigned get_usb_full_speed_rate(unsigned int rate) * convert a sampling rate into USB high speed format (fs/8000 in Q16.16) * this will overflow at approx 4 MHz */ -inline static unsigned get_usb_high_speed_rate(unsigned int rate) +static inline unsigned get_usb_high_speed_rate(unsigned int rate) { return ((rate << 10) + 62) / 125; } /* convert our full speed USB rate into sampling rate in Hz */ -inline static unsigned get_full_speed_hz(unsigned int usb_rate) +static inline unsigned get_full_speed_hz(unsigned int usb_rate) { return (usb_rate * 125 + (1 << 12)) >> 13; } /* convert our high speed USB rate into sampling rate in Hz */ -inline static unsigned get_high_speed_hz(unsigned int usb_rate) +static inline unsigned get_high_speed_hz(unsigned int usb_rate) { return (usb_rate * 125 + (1 << 9)) >> 10; } diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index e73c1c9d3e73..fa7056f5caaf 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -363,7 +363,7 @@ static int get_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int *value } /* channel = 0: master, 1 = first channel */ -inline static int get_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int *value) +static inline int get_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int *value) { return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value); } @@ -399,7 +399,7 @@ static int set_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int value) return set_ctl_value(cval, SET_CUR, validx, value); } -inline static int set_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int value) +static inline int set_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int value) { return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value); } -- cgit v1.2.3 From 9b1513d91e195af46b8e59626f74d3d41a7565af Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 29 Jul 2005 12:16:31 -0700 Subject: [PATCH] USB: ftdi_sio: new microHAM and Evolution Robotics devices The attached patch adds the following new devices to the ftdi_sio driver: * microHAM USB-Y6 and USB-Y8 devices submitted by Justin Burket (KL1RL). * Evolution Robotics ER1 Control Module submitted by Shawn M. Lavelle. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/serial/ftdi_sio.c | 3 +++ drivers/usb/serial/ftdi_sio.h | 14 ++++++++++++++ 2 files changed, 17 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 0b03ddab53d9..cfb77ceced58 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -429,6 +429,9 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) }, + { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 8866376823a5..9f4342093e8b 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -264,11 +264,25 @@ #define MOBILITY_VID 0x1342 #define MOBILITY_USB_SERIAL_PID 0x0202 /* EasiDock USB 200 serial */ +/* + * microHAM product IDs (http://www.microham.com). + * Submitted by Justin Burket (KL1RL) . + */ +#define FTDI_MHAM_Y6_PID 0xEEEA /* USB-Y6 interface */ +#define FTDI_MHAM_Y8_PID 0xEEEB /* USB-Y8 interface */ + /* * Active Robots product ids. */ #define FTDI_ACTIVE_ROBOTS_PID 0xE548 /* USB comms board */ +/* + * Evolution Robotics products (http://www.evolution.com/). + * Submitted by Shawn M. Lavelle. + */ +#define EVOLUTION_VID 0xDEEE /* Vendor ID */ +#define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */ + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ -- cgit v1.2.3 From 74ede0ff59fb18787213ed979641624a2f234821 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 29 Jul 2005 12:16:41 -0700 Subject: [PATCH] USB: ftdi_sio: Update RTS and DTR simultaneously ftdi_sio: Update RTS and DTR simultaneously, using a single control URB instead of separate control URBs for RTS and DTR. Reinhard Bergmann observed time differences of up to 680 ms with his application on a 2.4.22 kernel when RTS and DTR were updated using separate control URBs, which is unacceptable. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/serial/ftdi_sio.c | 138 +++++++++++++----------------------------- 1 file changed, 43 insertions(+), 95 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index cfb77ceced58..d1d2aeebd20a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -596,62 +596,59 @@ static __u32 ftdi_232bm_baud_to_divisor(int baud) return(ftdi_232bm_baud_base_to_divisor(baud, 48000000)); } -static int set_rts(struct usb_serial_port *port, int high_or_low) +#define set_mctrl(port, set) update_mctrl((port), (set), 0) +#define clear_mctrl(port, clear) update_mctrl((port), 0, (clear)) + +static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned int clear) { struct ftdi_private *priv = usb_get_serial_port_data(port); char *buf; - unsigned ftdi_high_or_low; + unsigned urb_value; int rv; - - buf = kmalloc(1, GFP_NOIO); - if (!buf) - return -ENOMEM; - - if (high_or_low) { - ftdi_high_or_low = FTDI_SIO_SET_RTS_HIGH; - priv->last_dtr_rts |= TIOCM_RTS; - } else { - ftdi_high_or_low = FTDI_SIO_SET_RTS_LOW; - priv->last_dtr_rts &= ~TIOCM_RTS; - } - rv = usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - ftdi_high_or_low, priv->interface, - buf, 0, WDR_TIMEOUT); - - kfree(buf); - return rv; -} + if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) { + dbg("%s - DTR|RTS not being set|cleared", __FUNCTION__); + return 0; /* no change */ + } -static int set_dtr(struct usb_serial_port *port, int high_or_low) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - char *buf; - unsigned ftdi_high_or_low; - int rv; - buf = kmalloc(1, GFP_NOIO); - if (!buf) + if (!buf) { return -ENOMEM; - - if (high_or_low) { - ftdi_high_or_low = FTDI_SIO_SET_DTR_HIGH; - priv->last_dtr_rts |= TIOCM_DTR; - } else { - ftdi_high_or_low = FTDI_SIO_SET_DTR_LOW; - priv->last_dtr_rts &= ~TIOCM_DTR; } + + clear &= ~set; /* 'set' takes precedence over 'clear' */ + urb_value = 0; + if (clear & TIOCM_DTR) + urb_value |= FTDI_SIO_SET_DTR_LOW; + if (clear & TIOCM_RTS) + urb_value |= FTDI_SIO_SET_RTS_LOW; + if (set & TIOCM_DTR) + urb_value |= FTDI_SIO_SET_DTR_HIGH; + if (set & TIOCM_RTS) + urb_value |= FTDI_SIO_SET_RTS_HIGH; rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - ftdi_high_or_low, priv->interface, + urb_value, priv->interface, buf, 0, WDR_TIMEOUT); kfree(buf); + if (rv < 0) { + err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s", + __FUNCTION__, + (set & TIOCM_DTR) ? "HIGH" : + (clear & TIOCM_DTR) ? "LOW" : "unchanged", + (set & TIOCM_RTS) ? "HIGH" : + (clear & TIOCM_RTS) ? "LOW" : "unchanged"); + } else { + dbg("%s - DTR %s, RTS %s", __FUNCTION__, + (set & TIOCM_DTR) ? "HIGH" : + (clear & TIOCM_DTR) ? "LOW" : "unchanged", + (set & TIOCM_RTS) ? "HIGH" : + (clear & TIOCM_RTS) ? "LOW" : "unchanged"); + priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set; + } return rv; } @@ -1222,12 +1219,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) /* FIXME: Flow control might be enabled, so it should be checked - we have no control of defaults! */ /* Turn on RTS and DTR since we are not flow controlling by default */ - if (set_dtr(port, HIGH) < 0) { - err("%s Error from DTR HIGH urb", __FUNCTION__); - } - if (set_rts(port, HIGH) < 0){ - err("%s Error from RTS HIGH urb", __FUNCTION__); - } + set_mctrl(port, TIOCM_DTR | TIOCM_RTS); /* Not throttled */ spin_lock_irqsave(&priv->rx_lock, flags); @@ -1277,14 +1269,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) err("error from flowcontrol urb"); } - /* drop DTR */ - if (set_dtr(port, LOW) < 0){ - err("Error from DTR LOW urb"); - } - /* drop RTS */ - if (set_rts(port, LOW) < 0) { - err("Error from RTS LOW urb"); - } + /* drop RTS and DTR */ + clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } /* Note change no line if hupcl is off */ /* cancel any scheduled reading */ @@ -1815,25 +1801,14 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ err("%s error from disable flowcontrol urb", __FUNCTION__); } /* Drop RTS and DTR */ - if (set_dtr(port, LOW) < 0){ - err("%s Error from DTR LOW urb", __FUNCTION__); - } - if (set_rts(port, LOW) < 0){ - err("%s Error from RTS LOW urb", __FUNCTION__); - } - + clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } else { /* set the baudrate determined before */ if (change_speed(port)) { err("%s urb failed to set baurdrate", __FUNCTION__); } /* Ensure RTS and DTR are raised */ - else if (set_dtr(port, HIGH) < 0){ - err("%s Error from DTR HIGH urb", __FUNCTION__); - } - else if (set_rts(port, HIGH) < 0){ - err("%s Error from RTS HIGH urb", __FUNCTION__); - } + set_mctrl(port, TIOCM_DTR | TIOCM_RTS); } /* Set flow control */ @@ -1945,35 +1920,8 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear) { - int ret; - dbg("%s TIOCMSET", __FUNCTION__); - if (set & TIOCM_DTR){ - if ((ret = set_dtr(port, HIGH)) < 0) { - err("Urb to set DTR failed"); - return(ret); - } - } - if (set & TIOCM_RTS) { - if ((ret = set_rts(port, HIGH)) < 0){ - err("Urb to set RTS failed"); - return(ret); - } - } - - if (clear & TIOCM_DTR){ - if ((ret = set_dtr(port, LOW)) < 0){ - err("Urb to unset DTR failed"); - return(ret); - } - } - if (clear & TIOCM_RTS) { - if ((ret = set_rts(port, LOW)) < 0){ - err("Urb to unset RTS failed"); - return(ret); - } - } - return(0); + return update_mctrl(port, set, clear); } -- cgit v1.2.3 From 279e1545a1350b9147ae884f848ffc8b7db18967 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 29 Jul 2005 12:16:52 -0700 Subject: [PATCH] USB: ftdi_sio: fix a couple of timeouts ftdi_sio: Fix timeouts in a couple of usb_control_msg() calls due to change of units from jiffies to milliseconds in 2.6.12. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/serial/ftdi_sio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d1d2aeebd20a..d1964a0c4168 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -548,6 +548,7 @@ static struct usb_serial_device_type ftdi_sio_device = { #define WDR_TIMEOUT 5000 /* default urb timeout */ +#define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */ /* High and low are for DTR, RTS etc etc */ #define HIGH 1 @@ -681,7 +682,7 @@ static int change_speed(struct usb_serial_port *port) FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, urb_value, urb_index, - buf, 0, 100); + buf, 0, WDR_SHORT_TIMEOUT); kfree(buf); return rv; @@ -1786,7 +1787,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , priv->interface, - buf, 0, 100) < 0) { + buf, 0, WDR_SHORT_TIMEOUT) < 0) { err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); } -- cgit v1.2.3 From fe0410c7f43e133e156e54e3156392e800bedc21 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 29 Jul 2005 12:16:58 -0700 Subject: [PATCH] USB: usbfs: Don't leak uninitialized data This patch fixes an information leak in the usbfs snoop facility: uninitialized data from __get_free_page can be returned to userspace and written to the system log. It also improves the snoop output by printing the wLength value. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/core/devio.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 787c27a63c51..f86bf1454e21 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -569,8 +569,11 @@ static int proc_control(struct dev_state *ps, void __user *arg) free_page((unsigned long)tbuf); return -EINVAL; } - snoop(&dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", - ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex); + snoop(&dev->dev, "control read: bRequest=%02x " + "bRrequestType=%02x wValue=%04x " + "wIndex=%04x wLength=%04x\n", + ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, + ctrl.wIndex, ctrl.wLength); usb_unlock_device(dev); i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, @@ -579,11 +582,11 @@ static int proc_control(struct dev_state *ps, void __user *arg) if ((i > 0) && ctrl.wLength) { if (usbfs_snoop) { dev_info(&dev->dev, "control read: data "); - for (j = 0; j < ctrl.wLength; ++j) + for (j = 0; j < i; ++j) printk ("%02x ", (unsigned char)(tbuf)[j]); printk("\n"); } - if (copy_to_user(ctrl.data, tbuf, ctrl.wLength)) { + if (copy_to_user(ctrl.data, tbuf, i)) { free_page((unsigned long)tbuf); return -EFAULT; } @@ -595,8 +598,11 @@ static int proc_control(struct dev_state *ps, void __user *arg) return -EFAULT; } } - snoop(&dev->dev, "control write: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", - ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex); + snoop(&dev->dev, "control write: bRequest=%02x " + "bRrequestType=%02x wValue=%04x " + "wIndex=%04x wLength=%04x\n", + ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, + ctrl.wIndex, ctrl.wLength); if (usbfs_snoop) { dev_info(&dev->dev, "control write: data: "); for (j = 0; j < ctrl.wLength; ++j) -- cgit v1.2.3 From 4a0d73c463765ce34b22ac3924d0661caf2a7539 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 29 Jul 2005 12:17:11 -0700 Subject: [PATCH] USB: drivers/usb/net/: remove two unused multicast_filter_limit variables The only uses of both variables were recently removed. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/net/pegasus.c | 1 - drivers/usb/net/rtl8150.c | 2 -- 2 files changed, 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 5f4496d8dbac..fcd6d3ccef44 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -59,7 +59,6 @@ static const char driver_name[] = "pegasus"; static int loopback = 0; static int mii_mode = 0; -static int multicast_filter_limit = 32; static struct usb_eth_dev usb_dev_id[] = { #define PEGASUS_DEV(pn, vid, pid, flags) \ diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index 626b016addff..59ab40ebb394 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -167,8 +167,6 @@ struct rtl8150 { typedef struct rtl8150 rtl8150_t; -static unsigned long multicast_filter_limit = 32; - static void fill_skb_pool(rtl8150_t *); static void free_skb_pool(rtl8150_t *); static inline struct sk_buff *pull_skb(rtl8150_t *); -- cgit v1.2.3 From 86d30741e480f40676c2173e1153368a4846da48 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 29 Jul 2005 12:17:16 -0700 Subject: [PATCH] USB: Usbcore: Don't try to delete unregistered interfaces This patch handles a rarely-encountered failure mode in usbcore. It's legal for device_add to fail (although now it happens even more rarely than before since failure to bind a driver is no longer fatal). So when we destroy the interfaces in a configuration, we shouldn't try to delete ones which weren't successfully registered. Also, failure to register an interface shouldn't be fatal either -- I think; you may disagree about this part of the patch. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/core/message.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index a428ef479bd7..88d1b376f67c 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -985,8 +985,10 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { struct usb_interface *interface; - /* remove this interface */ + /* remove this interface if it has been registered */ interface = dev->actconfig->interface[i]; + if (!klist_node_attached(&interface->dev.knode_bus)) + continue; dev_dbg (&dev->dev, "unregistering interface %s\n", interface->dev.bus_id); usb_remove_sysfs_intf_files(interface); @@ -1439,7 +1441,7 @@ free_interfaces: } } - return ret; + return 0; } // synchronous request completion model -- cgit v1.2.3 From a6db592e1624bb7ec62cf56629c9556442169ac5 Mon Sep 17 00:00:00 2001 From: Michael Hund Date: Fri, 29 Jul 2005 12:17:20 -0700 Subject: [PATCH] USB: ldusb fixes below you will find the forgotten kmalloc check (sorry). Signed-off-by: Michael Hund Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/misc/ldusb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 66ec88354b93..ad17892aac9e 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -23,6 +23,7 @@ * * V0.1 (mh) Initial version * V0.11 (mh) Added raw support for HID 1.0 devices (no interrupt out endpoint) + * V0.12 (mh) Added kmalloc check for string buffer */ #include @@ -84,7 +85,7 @@ static struct usb_device_id ld_usb_table [] = { { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, ld_usb_table); -MODULE_VERSION("V0.11"); +MODULE_VERSION("V0.12"); MODULE_AUTHOR("Michael Hund "); MODULE_DESCRIPTION("LD USB Driver"); MODULE_LICENSE("GPL"); @@ -635,6 +636,10 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * (le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_COM3LAB)) && (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x103)) { buffer = kmalloc(256, GFP_KERNEL); + if (buffer == NULL) { + dev_err(&intf->dev, "Couldn't allocate string buffer\n"); + goto error; + } /* usb_string makes SETUP+STALL to leave always ControlReadLoop */ usb_string(udev, 255, buffer, 256); kfree(buffer); -- cgit v1.2.3 From 8753e65e34a7b02f8473e7c6ce1cf7e08db4c6e3 Mon Sep 17 00:00:00 2001 From: Masahito Omote Date: Fri, 29 Jul 2005 12:17:25 -0700 Subject: [PATCH] USB: Patch for KYOCERA AH-K3001V support This patch enables a support of KYOCERA AH-K3001V, one of the most popular cell phone in Japan. This device has vendor specific ID but works with acm driver by adding USB ID. This device already works on FreeBSD and OS X by native USB ACM driver with USB ID added. This device is probed as NO_UNION_NORMAL not to hang up when probing. Signed-off-by: Masahito Omote Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index adff5a77e31f..16ecad30e29c 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -980,6 +980,9 @@ static struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, + { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, /* control interfaces with various AT-command sets */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_ACM_PROTO_AT_V25TER) }, -- cgit v1.2.3 From f29080976d109b6c08e42be8a1888f338785c502 Mon Sep 17 00:00:00 2001 From: Mathieu Date: Fri, 29 Jul 2005 12:17:29 -0700 Subject: [PATCH] USB: drivers/net/usb/zd1201.c: Gigabyte GN-WLBZ201 dongle usbid Gigabyte GN-WLBZ201 wifi usb dongle works very well, using the zd1201 driver. the only missing part is that the corresponding usbid is not declared. The following patch should fix this. From: "Mathieu" Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/net/zd1201.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index 3b387b005739..29cd801eb958 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -29,6 +29,7 @@ static struct usb_device_id zd1201_table[] = { {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 */ + {USB_DEVICE(0x1044, 0x8005)}, /* GIGABYTE GN-WLBZ201 usb adapter */ {} }; -- cgit v1.2.3 From 3eb0c5f4b539873ca88f8597db6a49e83ddfd7e2 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 29 Jul 2005 12:18:03 -0700 Subject: [PATCH] USB: add S3C24XX USB Host driver support USB (OHCI) Host driver for S3C2410/S3C2440 based systems Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/Kconfig | 1 + drivers/usb/host/ohci-hcd.c | 5 + drivers/usb/host/ohci-s3c2410.c | 496 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 502 insertions(+) create mode 100644 drivers/usb/host/ohci-s3c2410.c (limited to 'drivers/usb') diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index cd329dd7fb86..85dacc92545a 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -20,6 +20,7 @@ config USB_ARCH_HAS_OHCI default y if SA1111 default y if ARCH_OMAP default y if ARCH_LH7A404 + default y if ARCH_S3C2410 default y if PXA27x # PPC: default y if STB03xxx diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 68decab280dd..56b43f2a0e52 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -887,6 +887,10 @@ MODULE_LICENSE ("GPL"); #include "ohci-sa1111.c" #endif +#ifdef CONFIG_ARCH_S3C2410 +#include "ohci-s3c2410.c" +#endif + #ifdef CONFIG_ARCH_OMAP #include "ohci-omap.c" #endif @@ -909,6 +913,7 @@ MODULE_LICENSE ("GPL"); #if !(defined(CONFIG_PCI) \ || defined(CONFIG_SA1111) \ + || defined(CONFIG_ARCH_S3C2410) \ || defined(CONFIG_ARCH_OMAP) \ || defined (CONFIG_ARCH_LH7A404) \ || defined (CONFIG_PXA27x) \ diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c new file mode 100644 index 000000000000..e9401662503c --- /dev/null +++ b/drivers/usb/host/ohci-s3c2410.c @@ -0,0 +1,496 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2002 Hewlett-Packard Company + * + * USB Bus Glue for Samsung S3C2410 + * + * Written by Christopher Hoover + * Based on fragments of previous driver by Rusell King et al. + * + * Modified for S3C2410 from ohci-sa1111.c, ohci-omap.c and ohci-lh7a40.c + * by Ben Dooks, + * Copyright (C) 2004 Simtec Electronics + * + * Thanks to basprog@mail.ru for updates to newer kernels + * + * This file is licenced under the GPL. +*/ + +#include +#include +#include +#include + +#define valid_port(idx) ((idx) == 1 || (idx) == 2) + +/* clock device associated with the hcd */ + +static struct clk *clk; + +/* forward definitions */ + +static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc); + +/* conversion functions */ + +struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd) +{ + return hcd->self.controller->platform_data; +} + +static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd) +{ + struct s3c2410_hcd_info *info = dev->dev.platform_data; + + dev_dbg(&dev->dev, "s3c2410_start_hc:\n"); + clk_enable(clk); + + if (info != NULL) { + info->hcd = hcd; + info->report_oc = s3c2410_hcd_oc; + + if (info->enable_oc != NULL) { + (info->enable_oc)(info, 1); + } + } +} + +static void s3c2410_stop_hc(struct platform_device *dev) +{ + struct s3c2410_hcd_info *info = dev->dev.platform_data; + + dev_dbg(&dev->dev, "s3c2410_stop_hc:\n"); + + if (info != NULL) { + info->report_oc = NULL; + info->hcd = NULL; + + if (info->enable_oc != NULL) { + (info->enable_oc)(info, 0); + } + } + + clk_disable(clk); +} + +/* ohci_s3c2410_hub_status_data + * + * update the status data from the hub with anything that + * has been detected by our system +*/ + +static int +ohci_s3c2410_hub_status_data (struct usb_hcd *hcd, char *buf) +{ + struct s3c2410_hcd_info *info = to_s3c2410_info(hcd); + struct s3c2410_hcd_port *port; + int orig; + int portno; + + orig = ohci_hub_status_data (hcd, buf); + + if (info == NULL) + return orig; + + port = &info->port[0]; + + /* mark any changed port as changed */ + + for (portno = 0; portno < 2; port++, portno++) { + if (port->oc_changed == 1 && + port->flags & S3C_HCDFLG_USED) { + dev_dbg(hcd->self.controller, + "oc change on port %d\n", portno); + + if (orig < 1) + orig = 1; + + buf[0] |= 1<<(portno+1); + } + } + + return orig; +} + +/* s3c2410_usb_set_power + * + * configure the power on a port, by calling the platform device + * routine registered with the platform device +*/ + +static void s3c2410_usb_set_power(struct s3c2410_hcd_info *info, + int port, int to) +{ + if (info == NULL) + return; + + if (info->power_control != NULL) { + info->port[port-1].power = to; + (info->power_control)(port, to); + } +} + +/* ohci_s3c2410_hub_control + * + * look at control requests to the hub, and see if we need + * to take any action or over-ride the results from the + * request. +*/ + +static int ohci_s3c2410_hub_control ( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength) +{ + struct s3c2410_hcd_info *info = to_s3c2410_info(hcd); + struct usb_hub_descriptor *desc; + int ret = -EINVAL; + u32 *data = (u32 *)buf; + + dev_dbg(hcd->self.controller, + "s3c2410_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n", + hcd, typeReq, wValue, wIndex, buf, wLength); + + /* if we are only an humble host without any special capabilites + * process the request straight away and exit */ + + if (info == NULL) { + ret = ohci_hub_control(hcd, typeReq, wValue, + wIndex, buf, wLength); + goto out; + } + + /* check the request to see if it needs handling */ + + switch (typeReq) { + case SetPortFeature: + if (wValue == USB_PORT_FEAT_POWER) { + dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n"); + s3c2410_usb_set_power(info, wIndex, 1); + goto out; + } + break; + + case ClearPortFeature: + switch (wValue) { + case USB_PORT_FEAT_C_OVER_CURRENT: + dev_dbg(hcd->self.controller, + "ClearPortFeature: C_OVER_CURRENT\n"); + + if (valid_port(wIndex)) { + info->port[wIndex-1].oc_changed = 0; + info->port[wIndex-1].oc_status = 0; + } + + goto out; + + case USB_PORT_FEAT_OVER_CURRENT: + dev_dbg(hcd->self.controller, + "ClearPortFeature: OVER_CURRENT\n"); + + if (valid_port(wIndex)) { + info->port[wIndex-1].oc_status = 0; + } + + goto out; + + case USB_PORT_FEAT_POWER: + dev_dbg(hcd->self.controller, + "ClearPortFeature: POWER\n"); + + if (valid_port(wIndex)) { + s3c2410_usb_set_power(info, wIndex, 0); + return 0; + } + } + break; + } + + ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); + if (ret) + goto out; + + switch (typeReq) { + case GetHubDescriptor: + + /* update the hub's descriptor */ + + desc = (struct usb_hub_descriptor *)buf; + + if (info->power_control == NULL) + return ret; + + dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n", + desc->wHubCharacteristics); + + /* remove the old configurations for power-switching, and + * over-current protection, and insert our new configuration + */ + + desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM); + desc->wHubCharacteristics |= cpu_to_le16(0x0001); + + if (info->enable_oc) { + desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM); + desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001); + } + + dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n", + desc->wHubCharacteristics); + + return ret; + + case GetPortStatus: + /* check port status */ + + dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex); + + if (valid_port(wIndex)) { + if (info->port[wIndex-1].oc_changed) { + *data |= cpu_to_le32(RH_PS_OCIC); + } + + if (info->port[wIndex-1].oc_status) { + *data |= cpu_to_le32(RH_PS_POCI); + } + } + } + + out: + return ret; +} + +/* s3c2410_hcd_oc + * + * handle an over-current report +*/ + +static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc) +{ + struct s3c2410_hcd_port *port; + struct usb_hcd *hcd; + unsigned long flags; + int portno; + + if (info == NULL) + return; + + port = &info->port[0]; + hcd = info->hcd; + + local_irq_save(flags); + + for (portno = 0; portno < 2; port++, portno++) { + if (port_oc & (1<flags & S3C_HCDFLG_USED) { + port->oc_status = 1; + port->oc_changed = 1; + + /* ok, once over-current is detected, + the port needs to be powered down */ + s3c2410_usb_set_power(info, portno+1, 0); + } + } + + local_irq_restore(flags); +} + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/* + * usb_hcd_s3c2410_remove - shutdown processing for HCD + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_3c2410_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * +*/ + +void usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev) +{ + usb_remove_hcd(hcd); + s3c2410_stop_hc(dev); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); +} + +/** + * usb_hcd_s3c2410_probe - initialize S3C2410-based 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. + * + */ +int usb_hcd_s3c2410_probe (const struct hc_driver *driver, + struct platform_device *dev) +{ + struct usb_hcd *hcd = NULL; + int retval; + + s3c2410_usb_set_power(dev->dev.platform_data, 0, 1); + s3c2410_usb_set_power(dev->dev.platform_data, 1, 1); + + hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx"); + if (hcd == NULL) + 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)) { + dev_err(&dev->dev, "request_mem_region failed"); + retval = -EBUSY; + goto err0; + } + + clk = clk_get(NULL, "usb-host"); + if (IS_ERR(clk)) { + dev_err(&dev->dev, "cannot get usb-host clock\n"); + retval = -ENOENT; + goto err1; + } + + clk_use(clk); + s3c2410_start_hc(dev, hcd); + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + dev_err(&dev->dev, "ioremap failed\n"); + retval = -ENOMEM; + goto err2; + } + + ohci_hcd_init(hcd_to_ohci(hcd)); + + retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT); + if (retval != 0) + goto err2; + + return 0; + + err2: + s3c2410_stop_hc(dev); + iounmap(hcd->regs); + clk_unuse(clk); + clk_put(clk); + + err1: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + + err0: + usb_put_hcd(hcd); + return retval; +} + +/*-------------------------------------------------------------------------*/ + +static int +ohci_s3c2410_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", hcd->self.bus_name); + ohci_stop (hcd); + return ret; + } + + return 0; +} + + +static const struct hc_driver ohci_s3c2410_hc_driver = { + .description = hcd_name, + .product_desc = "S3C24XX OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_s3c2410_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_s3c2410_hub_status_data, + .hub_control = ohci_s3c2410_hub_control, + +#if defined(CONFIG_USB_SUSPEND) && 0 + .hub_suspend = ohci_hub_suspend, + .hub_resume = ohci_hub_resume, +#endif +}; + +/* device driver */ + +static int ohci_hcd_s3c2410_drv_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + return usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev); +} + +static int ohci_hcd_s3c2410_drv_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + usb_hcd_s3c2410_remove(hcd, pdev); + return 0; +} + +static struct device_driver ohci_hcd_s3c2410_driver = { + .name = "s3c2410-ohci", + .bus = &platform_bus_type, + .probe = ohci_hcd_s3c2410_drv_probe, + .remove = ohci_hcd_s3c2410_drv_remove, + /*.suspend = ohci_hcd_s3c2410_drv_suspend, */ + /*.resume = ohci_hcd_s3c2410_drv_resume, */ +}; + +static int __init ohci_hcd_s3c2410_init (void) +{ + return driver_register(&ohci_hcd_s3c2410_driver); +} + +static void __exit ohci_hcd_s3c2410_cleanup (void) +{ + driver_unregister(&ohci_hcd_s3c2410_driver); +} + +module_init (ohci_hcd_s3c2410_init); +module_exit (ohci_hcd_s3c2410_cleanup); -- cgit v1.2.3 From 6b216df87cb5f3bb7d47a33f1cd955ebc7b84dfd Mon Sep 17 00:00:00 2001 From: "Conger, Chris A" Date: Fri, 29 Jul 2005 12:18:23 -0700 Subject: [PATCH] USB: fix Bug in usb-skeleton.c Compare endpoint address to USB_ENDPOINT_DIR_MASK to determine endpoint direction... From: "Conger, Chris A." Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/usb-skeleton.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 6051a646fe69..353f24d45bc1 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -257,7 +257,8 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i endpoint = &iface_desc->endpoint[i].desc; if (!dev->bulk_in_endpointAddr && - (endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + == USB_DIR_IN) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { /* we found a bulk in endpoint */ @@ -272,7 +273,8 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i } if (!dev->bulk_out_endpointAddr && - !(endpoint->bEndpointAddress & USB_DIR_OUT) && + ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + == USB_DIR_OUT) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { /* we found a bulk out endpoint */ -- cgit v1.2.3 From 498f78e6fcf558d0dec31f5648f43426ae16433f Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Fri, 29 Jul 2005 12:18:28 -0700 Subject: [PATCH] USB: fix in usb_calc_bus_time This patch does the same swap, i.e. use the ISO macro if (isoc). Additionally, it fixes the return value - the usb_calc_bus_time function returns the time in nanoseconds (I didn't notice that before) while the HS_USECS and HS_USECS_ISO are microseconds. This fixes the function to return nanoseconds always, and adjusts ehci-q.c (the only high-speed caller of the function) to wrap the call in NS_TO_US(). Signed-off-by: Dan Streetman Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/core/hcd.c | 4 ++-- drivers/usb/core/hcd.h | 8 +++++--- drivers/usb/host/ehci-q.c | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 8616356f55e8..79422a3b07bc 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -939,9 +939,9 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) case USB_SPEED_HIGH: /* ISOC or INTR */ // FIXME adjust for input vs output if (isoc) - tmp = HS_USECS (bytecount); + tmp = HS_NSECS_ISO (bytecount); else - tmp = HS_USECS_ISO (bytecount); + tmp = HS_NSECS (bytecount); return tmp; default: pr_debug ("%s: bogus device speed!\n", usbcore_name); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 67db4a999b93..28055f95645b 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -334,17 +334,19 @@ extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb); /* - * Ceiling microseconds (typical) for that many bytes at high speed + * Ceiling [nano/micro]seconds (typical) for that many bytes at high speed * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed * to preallocate bandwidth) */ #define USB2_HOST_DELAY 5 /* nsec, guess */ -#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \ +#define HS_NSECS(bytes) ( ((55 * 8 * 2083)/1000) \ + ((2083UL * (3167 + BitTime (bytes)))/1000) \ + USB2_HOST_DELAY) -#define HS_USECS_ISO(bytes) NS_TO_US ( ((38 * 8 * 2083)/1000) \ +#define HS_NSECS_ISO(bytes) ( ((38 * 8 * 2083)/1000) \ + ((2083UL * (3167 + BitTime (bytes)))/1000) \ + USB2_HOST_DELAY) +#define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes)) +#define HS_USECS_ISO(bytes) NS_TO_US (HS_NSECS_ISO(bytes)) extern long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index d74b2d68a50e..4f97a4ad1ed3 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -657,8 +657,8 @@ qh_make ( * For control/bulk requests, the HC or TT handles these. */ if (type == PIPE_INTERRUPT) { - qh->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0, - hb_mult (maxp) * max_packet (maxp)); + qh->usecs = NS_TO_US (usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0, + hb_mult (maxp) * max_packet (maxp))); qh->start = NO_FRAME; if (urb->dev->speed == USB_SPEED_HIGH) { -- cgit v1.2.3 From a9b2e9170bdf1dd27ca4aa9a63048065d252d116 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Fri, 29 Jul 2005 12:18:34 -0700 Subject: [PATCH] USB: hidinput_hid_event() oops fix It seems that I see a bug in hidinput_hid_event. The check for NULL can never work, becaue &hidinput->input is nonzero at all times. Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/input/hid-input.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index e071c8eeccee..63a4db721f7e 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -398,11 +398,12 @@ ignore: void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs) { - struct input_dev *input = &field->hidinput->input; + struct input_dev *input; int *quirks = &hid->quirks; - if (!input) + if (!field->hidinput) return; + input = &field->hidinput->input; input_regs(input, regs); -- cgit v1.2.3 From 003ba5153582427b1df2347553529299872961e5 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Thu, 4 Aug 2005 18:06:36 -0700 Subject: [PATCH] USB: ub documentation update The patch which went in was correct, but not quite what I had in mind. Here is a patch to update that a little bit. Original patch is at: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=4749f32da939d4e4160541b2cadc22492bb507ec Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- Documentation/usb/usbmon.txt | 2 +- drivers/usb/mon/Kconfig | 9 ++++----- drivers/usb/mon/Makefile | 1 + 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index f1896ee3bb2a..63cb7edd177e 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt @@ -102,7 +102,7 @@ Here is the list of words, from left to right: - URB Status. This field makes no sense for submissions, but is present to help scripts with parsing. In error case, it contains the error code. In case of a setup packet, it contains a Setup Tag. If scripts read a number - in this field, the proceed to read Data Length. Otherwise, they read + in this field, they proceed to read Data Length. Otherwise, they read the setup packet before reading the Data Length. - Setup packet, if present, consists of 5 words: one of each for bmRequestType, bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0. diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig index 777642e26b9a..deb9ddffa402 100644 --- a/drivers/usb/mon/Kconfig +++ b/drivers/usb/mon/Kconfig @@ -9,9 +9,8 @@ config USB_MON 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. + For more information, see . - This is somewhat experimental at this time, but it should be safe, - as long as you aren't using modular USB and try to remove this - module. + This is somewhat experimental at this time, but it should be safe. + + If unsure, say Y. diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile index f18d10ce91f9..b0015b8a1d1f 100644 --- a/drivers/usb/mon/Makefile +++ b/drivers/usb/mon/Makefile @@ -4,4 +4,5 @@ usbmon-objs := mon_main.o mon_stat.o mon_text.o +# This does not use CONFIG_USB_MON because we want this to use a tristate. obj-$(CONFIG_USB) += usbmon.o -- cgit v1.2.3 From 7dedacf4270a810fadcca887ac85d267b5f1882d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 4 Aug 2005 18:06:41 -0700 Subject: [PATCH] USB: ehci: microframe handling fix This patch has a one line oops fix, plus related cleanups. - The bugfix uses microframe scheduling data given to the hardware to test "is this a periodic QH", rather than testing for nonzero period. (Prevents an oops by providing the correct answer.) - The cleanup going along with the patch should make it clearer what's going on whenever those bitfields are accessed. The bug came about when, around January, two new kinds of EHCI interrupt scheduling operation were added, involving both the high speed (24 KBytes per millisec) and low/full speed (1-64 bytes per millisec) microframe scheduling. A driver for the Edirol UA-1000 Audio Capture Unit ran into the oops; it used one of the newly supported high speed modes. Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/host/ehci-dbg.c | 2 +- drivers/usb/host/ehci-q.c | 5 +++-- drivers/usb/host/ehci-sched.c | 13 +++++++------ drivers/usb/host/ehci.h | 5 +++++ 4 files changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 50cb01831075..b01efb6b36f6 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -527,7 +527,7 @@ show_periodic (struct class_device *class_dev, char *buf) p.qh->period, le32_to_cpup (&p.qh->hw_info2) /* uframe masks */ - & 0xffff, + & (QH_CMASK | QH_SMASK), p.qh); size -= temp; next += temp; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 4f97a4ad1ed3..20df01a79b2e 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -222,7 +222,7 @@ __acquires(ehci->lock) struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; /* S-mask in a QH means it's an interrupt urb */ - if ((qh->hw_info2 & __constant_cpu_to_le32 (0x00ff)) != 0) { + if ((qh->hw_info2 & __constant_cpu_to_le32 (QH_SMASK)) != 0) { /* ... update hc-wide periodic stats (for usbfs) */ ehci_to_hcd(ehci)->self.bandwidth_int_reqs--; @@ -428,7 +428,8 @@ halt: /* should be rare for periodic transfers, * except maybe high bandwidth ... */ - if (qh->period) { + if ((__constant_cpu_to_le32 (QH_SMASK) + & qh->hw_info2) != 0) { intr_deschedule (ehci, qh); (void) qh_schedule (ehci, qh); } else diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 9af4f64532a9..b56f25864ed6 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -301,7 +301,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) dev_dbg (&qh->dev->dev, "link qh%d-%04x/%p start %d [%d/%d us]\n", - period, le32_to_cpup (&qh->hw_info2) & 0xffff, + period, le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, qh->c_usecs); /* high bandwidth, or otherwise every microframe */ @@ -385,7 +385,8 @@ static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) dev_dbg (&qh->dev->dev, "unlink qh%d-%04x/%p start %d [%d/%d us]\n", - qh->period, le32_to_cpup (&qh->hw_info2) & 0xffff, + qh->period, + le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, qh->c_usecs); /* qh->qh_next still "live" to HC */ @@ -411,7 +412,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) * active high speed queues may need bigger delays... */ if (list_empty (&qh->qtd_list) - || (__constant_cpu_to_le32 (0x0ff << 8) + || (__constant_cpu_to_le32 (QH_CMASK) & qh->hw_info2) != 0) wait = 2; else @@ -533,7 +534,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh) /* reuse the previous schedule slots, if we can */ if (frame < qh->period) { - uframe = ffs (le32_to_cpup (&qh->hw_info2) & 0x00ff); + uframe = ffs (le32_to_cpup (&qh->hw_info2) & QH_SMASK); status = check_intr_schedule (ehci, frame, --uframe, qh, &c_mask); } else { @@ -569,10 +570,10 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh) qh->start = frame; /* reset S-frame and (maybe) C-frame masks */ - qh->hw_info2 &= __constant_cpu_to_le32 (~0xffff); + qh->hw_info2 &= __constant_cpu_to_le32(~(QH_CMASK | QH_SMASK)); qh->hw_info2 |= qh->period ? cpu_to_le32 (1 << uframe) - : __constant_cpu_to_le32 (0xff); + : __constant_cpu_to_le32 (QH_SMASK); qh->hw_info2 |= c_mask; } else ehci_dbg (ehci, "reused qh %p schedule\n", qh); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 4df498231752..a7542157534c 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -385,6 +385,11 @@ struct ehci_qh { __le32 hw_info1; /* see EHCI 3.6.2 */ #define QH_HEAD 0x00008000 __le32 hw_info2; /* see EHCI 3.6.2 */ +#define QH_SMASK 0x000000ff +#define QH_CMASK 0x0000ff00 +#define QH_HUBADDR 0x007f0000 +#define QH_HUBPORT 0x3f800000 +#define QH_MULT 0xc0000000 __le32 hw_current; /* qtd list - see EHCI 3.6.4 */ /* qtd overlay (hardware parts of a struct ehci_qtd) */ -- cgit v1.2.3 From f10eff26831159f52353e8f15c37cdb2935d5fbf Mon Sep 17 00:00:00 2001 From: Olav Kongas Date: Thu, 4 Aug 2005 18:06:47 -0700 Subject: [PATCH] USB: Fix setup packet initialization in isp116x-hcd When recently addressing remarks by Alexey Dobriyan about the isp116x-hcd, I introduced a bug in the driver. Please apply the attached patch to fix it. Signed-off-by: Olav Kongas Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/host/isp116x-hcd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 50b1970fe6b6..76cb496c5836 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -229,9 +229,11 @@ static void preproc_atl_queue(struct isp116x *isp116x) struct isp116x_ep *ep; struct urb *urb; struct ptd *ptd; - u16 toggle = 0, dir = PTD_DIR_SETUP, len; + u16 len; for (ep = isp116x->atl_active; ep; ep = ep->active) { + u16 toggle = 0, dir = PTD_DIR_SETUP; + BUG_ON(list_empty(&ep->hep->urb_list)); urb = container_of(ep->hep->urb_list.next, struct urb, urb_list); -- cgit v1.2.3 From dc1d97e466c2836adebe5618759bfb5b35b3bc0a Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 16 Aug 2005 15:16:32 -0700 Subject: [PATCH] USB: fix usb wacom tablet driver bug This patch fixes bug 4905 and a Cintiq 21UX bug. Signed-off-by: Ping Cheng Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/input/wacom.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index 02412e31a46b..3b266af3048a 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -342,9 +342,6 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - x = le16_to_cpu(*(__le16 *) &data[2]); - y = le16_to_cpu(*(__le16 *) &data[4]); - input_regs(dev, regs); if (data[1] & 0x10) { /* in prox */ @@ -373,15 +370,17 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) } } - if (data[1] & 0x80) { + if (data[1] & 0x90) { + x = le16_to_cpu(*(__le16 *) &data[2]); + y = le16_to_cpu(*(__le16 *) &data[4]); input_report_abs(dev, ABS_X, x); input_report_abs(dev, ABS_Y, y); - } - if (wacom->tool[0] != BTN_TOOL_MOUSE) { - input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6])); - input_report_key(dev, BTN_TOUCH, data[1] & 0x01); - input_report_key(dev, BTN_STYLUS, data[1] & 0x02); - input_report_key(dev, BTN_STYLUS2, data[1] & 0x04); + if (wacom->tool[0] != BTN_TOOL_MOUSE) { + input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6])); + input_report_key(dev, BTN_TOUCH, data[1] & 0x01); + input_report_key(dev, BTN_STYLUS, data[1] & 0x02); + input_report_key(dev, BTN_STYLUS2, data[1] & 0x04); + } } input_report_key(dev, wacom->tool[0], data[1] & 0x10); @@ -568,7 +567,7 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) /* Cintiq doesn't send data when RDY bit isn't set */ if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40)) - return; + goto exit; if (wacom->features->type >= INTUOS3) { input_report_abs(dev, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1)); -- cgit v1.2.3 From da5ca008933b3b28303ba44d0be3372fbac7748b Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 16 Aug 2005 15:16:46 -0700 Subject: [PATCH] USB: usbmon: Copyrights and a typo Add copyright statements and fix a typo. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/mon/mon_main.c | 4 +++- drivers/usb/mon/usb_mon.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index aa9d00808e4e..508a21028db4 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -2,6 +2,8 @@ * The USB Monitor, inspired by Dave Harding's USBMon. * * mon_main.c: Main file, module initiation and exit, registrations, etc. + * + * Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com) */ #include @@ -311,7 +313,7 @@ static int __init mon_init(void) mondir = debugfs_create_dir("usbmon", NULL); if (IS_ERR(mondir)) { - printk(KERN_NOTICE TAG ": debugs is not available\n"); + printk(KERN_NOTICE TAG ": debugfs is not available\n"); return -ENODEV; } if (mondir == NULL) { diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index ed35c18a5c44..9b06784d2c48 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -1,5 +1,7 @@ /* * The USB Monitor, inspired by Dave Harding's USBMon. + * + * Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com) */ #ifndef __USB_MON_H -- cgit v1.2.3 From 81065e2f415af6c028eac13f481fb9e60a0b487b Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 22 Aug 2005 13:11:09 -0700 Subject: [PATCH] zd1201 kmalloc size fix Noticed by Coverity checker. (akpm: I stole this from Greg's tree and used the (IMO) tidier sizeof(*p) construct). Signed-off-by: Alexey Dobriyan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/net/zd1201.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index 29cd801eb958..e32a80b39182 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -346,8 +346,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs) if (datalen<14) goto resubmit; if ((seq & IEEE802_11_SCTL_FRAG) == 0) { - frag = kmalloc(sizeof(struct zd1201_frag*), - GFP_ATOMIC); + frag = kmalloc(sizeof(*frag), GFP_ATOMIC); if (!frag) goto resubmit; skb = dev_alloc_skb(IEEE802_11_DATA_LEN +14+2); -- cgit v1.2.3 From 2bbfb16bf345acd81ab1e6e3d4b35964650517ac Mon Sep 17 00:00:00 2001 From: lepton Date: Mon, 22 Aug 2005 17:06:14 -0700 Subject: [PATCH] usbnet oops fix There's a "return the wrong SKB" error in the GL620A cable minidriver (for "usbnet") which can oops. This would not appear when talking Linux-to-Linux, only Linux-to-Windows (for recent Linuxes). Signed-off-by: David Brownell Signed-off-by: Linus Torvalds --- drivers/usb/net/usbnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 576f3b852fce..4528a00c45b0 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1922,7 +1922,7 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb) // copy the packet data to the new skb memcpy(skb_put(gl_skb, size), packet->packet_data, size); - skb_return (dev, skb); + skb_return (dev, gl_skb); } // advance to the next packet -- cgit v1.2.3