diff options
| author | Patrick Mochel <mochel@osdl.org> | 2003-09-25 02:17:47 -0700 |
|---|---|---|
| committer | Patrick Mochel <mochel@osdl.org> | 2003-09-25 02:17:47 -0700 |
| commit | 9559f65da4677764ebcba5e37408698b3a413c09 (patch) | |
| tree | 64510d518869a80ccb65f2c72778c84d526dc784 | |
| parent | 70b812cda02d7c74d3122666a44e103ec610793b (diff) | |
| parent | 729fe396d4ccf2348bc3ff6c9eef9f8a6d7148cf (diff) | |
Merge bk://kernel.bkbits.net//home/mochel/linux-2.5-power
into osdl.org:/home/mochel/src/kernel/linux-2.5-power
39 files changed, 772 insertions, 1615 deletions
diff --git a/Documentation/i2c/sysfs-interface b/Documentation/i2c/sysfs-interface index a62f15ecaf3e..d601296ce5a9 100644 --- a/Documentation/i2c/sysfs-interface +++ b/Documentation/i2c/sysfs-interface @@ -77,7 +77,10 @@ curr_min[1-n] Current min or hysteresis value. curr_input[1-n] Current input value Fixed point XXXXX, divide by 1000 to get Amps. Read only. - + +eeprom Raw EEPROM data in binary form. + Read only. + fan_min[1-3] Fan minimum value Integer value indicating RPM Read/Write. diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 339d8c50e2c5..1284a252dace 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -376,6 +376,11 @@ void blk_queue_hardsect_size(request_queue_t *q, unsigned short size) q->hardsect_size = size; } +/* + * Returns the minimum that is _not_ zero, unless both are zero. + */ +#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r)) + /** * blk_queue_stack_limits - inherit underlying queue limits for stacked drivers * @t: the stacking driver (top) @@ -383,7 +388,9 @@ void blk_queue_hardsect_size(request_queue_t *q, unsigned short size) **/ void blk_queue_stack_limits(request_queue_t *t, request_queue_t *b) { - t->max_sectors = min(t->max_sectors,b->max_sectors); + /* zero is "infinity" */ + t->max_sectors = min_not_zero(t->max_sectors,b->max_sectors); + t->max_phys_segments = min(t->max_phys_segments,b->max_phys_segments); t->max_hw_segments = min(t->max_hw_segments,b->max_hw_segments); t->max_segment_size = min(t->max_segment_size,b->max_segment_size); diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 939448e93662..da0727d9377f 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -37,43 +37,7 @@ config I2C_CHARDEV This support is also available as a module. If so, the module will be called i2c-dev. -config I2C_ALGOBIT - tristate "I2C bit-banging interfaces" - depends on I2C - help - This allows you to use a range of I2C adapters called bit-banging - adapters. Say Y if you own an I2C adapter belonging to this class - and then say Y to the specific driver for you adapter below. - - This support is also available as a module. If so, the module - will be called i2c-algo-bit. - -config I2C_ALGOPCF - tristate "I2C PCF 8584 interfaces" - depends on I2C - help - This allows you to use a range of I2C adapters called PCF adapters. - Say Y if you own an I2C adapter belonging to this class and then say - Y to the specific driver for you adapter below. - - This support is also available as a module. If so, the module - will be called i2c-algo-pcf. - -config I2C_ALGOITE - tristate "ITE I2C Algorithm" - depends on MIPS_ITE8172 && I2C - help - This supports the use of the ITE8172 I2C interface found on some MIPS - systems. Say Y if you have one of these. You should also say Y for - the ITE I2C peripheral driver support below. - - This support is also available as a module. If so, the module - will be called i2c-algo-ite. - -config I2C_ALGO8XX - tristate "MPC8xx CPM I2C interface" - depends on 8xx && I2C - + source drivers/i2c/algos/Kconfig source drivers/i2c/busses/Kconfig source drivers/i2c/chips/Kconfig diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 1cec46521453..b2ded05c1e7f 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -5,7 +5,4 @@ obj-$(CONFIG_I2C) += i2c-core.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-$(CONFIG_I2C_SENSOR) += i2c-sensor.o -obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o -obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o -obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o -obj-y += busses/ chips/ +obj-y += busses/ chips/ algos/ diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig new file mode 100644 index 000000000000..04d3e0b7c450 --- /dev/null +++ b/drivers/i2c/algos/Kconfig @@ -0,0 +1,45 @@ +# +# Character device configuration +# + +menu "I2C Algorithms" + +config I2C_ALGOBIT + tristate "I2C bit-banging interfaces" + depends on I2C + help + This allows you to use a range of I2C adapters called bit-banging + adapters. Say Y if you own an I2C adapter belonging to this class + and then say Y to the specific driver for you adapter below. + + This support is also available as a module. If so, the module + will be called i2c-algo-bit. + +config I2C_ALGOPCF + tristate "I2C PCF 8584 interfaces" + depends on I2C + help + This allows you to use a range of I2C adapters called PCF adapters. + Say Y if you own an I2C adapter belonging to this class and then say + Y to the specific driver for you adapter below. + + This support is also available as a module. If so, the module + will be called i2c-algo-pcf. + +config I2C_ALGOITE + tristate "ITE I2C Algorithm" + depends on MIPS_ITE8172 && I2C + help + This supports the use of the ITE8172 I2C interface found on some MIPS + systems. Say Y if you have one of these. You should also say Y for + the ITE I2C peripheral driver support below. + + This support is also available as a module. If so, the module + will be called i2c-algo-ite. + +config I2C_ALGO8XX + tristate "MPC8xx CPM I2C interface" + depends on 8xx && I2C + +endmenu + diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile new file mode 100644 index 000000000000..fba9ef96d68c --- /dev/null +++ b/drivers/i2c/algos/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the i2c algorithms +# + +obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o +obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o +obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o diff --git a/drivers/i2c/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index f8330b3ef5d3..f8330b3ef5d3 100644 --- a/drivers/i2c/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c diff --git a/drivers/i2c/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c index f53adcd25dd4..d8f601a31672 100644 --- a/drivers/i2c/i2c-algo-ite.c +++ b/drivers/i2c/algos/i2c-algo-ite.c @@ -46,7 +46,7 @@ #include <linux/i2c.h> #include <linux/i2c-algo-ite.h> -#include "i2c-ite.h" +#include "i2c-algo-ite.h" #define PM_DSR IT8172_PCI_IO_BASE + IT_PM_DSR #define PM_IBSR IT8172_PCI_IO_BASE + IT_PM_DSR + 0x04 diff --git a/drivers/i2c/i2c-ite.h b/drivers/i2c/algos/i2c-algo-ite.h index a8ca3c9b546a..a8ca3c9b546a 100644 --- a/drivers/i2c/i2c-ite.h +++ b/drivers/i2c/algos/i2c-algo-ite.h diff --git a/drivers/i2c/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index f8af2ffc85ca..6ed11937c00e 100644 --- a/drivers/i2c/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -37,7 +37,7 @@ #include <linux/errno.h> #include <linux/i2c.h> #include <linux/i2c-algo-pcf.h> -#include "i2c-pcf8584.h" +#include "i2c-algo-pcf.h" /* ----- global defines ----------------------------------------------- */ diff --git a/drivers/i2c/i2c-pcf8584.h b/drivers/i2c/algos/i2c-algo-pcf.h index 4908ebae5526..4908ebae5526 100644 --- a/drivers/i2c/i2c-pcf8584.h +++ b/drivers/i2c/algos/i2c-algo-pcf.h diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 98db1a13a0c2..2a8b03bd8bbd 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -41,7 +41,7 @@ #include <asm/io.h> #include <asm/irq.h> -#include "../i2c-pcf8584.h" +#include "../algos/i2c-algo-pcf.h" #define DEFAULT_BASE 0x330 diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 7c0db1408429..7e8db5a4bfb0 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -21,6 +21,18 @@ config SENSORS_ADM1021 This driver can also be built as a module. If so, the module will be called adm1021. +config SENSORS_EEPROM + tristate "EEPROM (DIMM) reader" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get read-only access to the EEPROM data + available on modern memory DIMMs, and which could theoretically + also be available on other devices. + + This driver can also be built as a module. If so, the module + will be called eeprom. + config SENSORS_IT87 tristate "National Semiconductors IT87 and compatibles" depends on I2C && EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 7c244c8b5cd0..e4896edfae26 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_SENSORS_W83781D) += w83781d.o obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o +obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_LM75) += lm75.o obj-$(CONFIG_SENSORS_LM78) += lm78.o diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c new file mode 100644 index 000000000000..7e8940a3c7e2 --- /dev/null +++ b/drivers/i2c/chips/eeprom.c @@ -0,0 +1,276 @@ +/* + eeprom.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and + Philip Edelbrock <phil@netroedge.com> + Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com> + Copyright (C) 2003 IBM Corp. + + 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. +*/ + +/* #define DEBUG */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/i2c-sensor.h> + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { 0x50, 0x57, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; +static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(eeprom); + +static int checksum = 0; +MODULE_PARM(checksum, "i"); +MODULE_PARM_DESC(checksum, "Only accept eeproms whose checksum is correct"); + + +/* EEPROM registers */ +#define EEPROM_REG_CHECKSUM 0x3f + +/* Size of EEPROM in bytes */ +#define EEPROM_SIZE 256 + +/* possible types of eeprom devices */ +enum eeprom_nature { + UNKNOWN, + VAIO, +}; + +/* Each client has this additional data */ +struct eeprom_data { + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + u8 data[EEPROM_SIZE]; /* Register values */ +}; + + +static int eeprom_attach_adapter(struct i2c_adapter *adapter); +static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind); +static int eeprom_detach_client(struct i2c_client *client); + +/* This is the driver that will be inserted */ +static struct i2c_driver eeprom_driver = { + .owner = THIS_MODULE, + .name = "eeprom", + .id = I2C_DRIVERID_EEPROM, + .flags = I2C_DF_NOTIFY, + .attach_adapter = eeprom_attach_adapter, + .detach_client = eeprom_detach_client, +}; + +static int eeprom_id = 0; + +static void eeprom_update_client(struct i2c_client *client) +{ + struct eeprom_data *data = i2c_get_clientdata(client); + int i, j; + + down(&data->update_lock); + + if ((jiffies - data->last_updated > 300 * HZ) | + (jiffies < data->last_updated) || !data->valid) { + dev_dbg(&client->dev, "Starting eeprom update\n"); + + if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + for (i=0; i < EEPROM_SIZE; i += I2C_SMBUS_I2C_BLOCK_MAX) + if (i2c_smbus_read_i2c_block_data(client, i, data->data + i) != I2C_SMBUS_I2C_BLOCK_MAX) + goto exit; + } else { + if (i2c_smbus_write_byte(client, 0)) { + dev_dbg(&client->dev, "eeprom read start has failed!\n"); + goto exit; + } + for (i = 0; i < EEPROM_SIZE; i++) { + j = i2c_smbus_read_byte(client); + if (j < 0) + goto exit; + data->data[i] = (u8) j; + } + } + data->last_updated = jiffies; + data->valid = 1; + } +exit: + up(&data->update_lock); +} + +static ssize_t eeprom_read(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); + struct eeprom_data *data = i2c_get_clientdata(client); + + eeprom_update_client(client); + + if (off > EEPROM_SIZE) + return 0; + if (off + count > EEPROM_SIZE) + count = EEPROM_SIZE - off; + + memcpy(buf, &data->data[off], count); + return count; +} + +static struct bin_attribute eeprom_attr = { + .attr = { + .name = "eeprom", + .mode = S_IRUGO, + }, + .size = EEPROM_SIZE, + .read = eeprom_read, +}; + +static int eeprom_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, eeprom_detect); +} + +/* This function is called by i2c_detect */ +int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i, cs; + struct i2c_client *new_client; + struct eeprom_data *data; + enum eeprom_nature nature = UNKNOWN; + int err = 0; + + /* Make sure we aren't probing the ISA bus!! This is just a safety check + at this moment; i2c_detect really won't call us. */ +#ifdef DEBUG + if (i2c_is_isa_adapter(adapter)) { + dev_dbg(&adapter->dev, " eeprom_detect called for an ISA bus adapter?!?\n"); + return 0; + } +#endif + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access eeprom_{read,write}_value. */ + if (!(new_client = kmalloc(sizeof(struct i2c_client) + + sizeof(struct eeprom_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(new_client, 0x00, sizeof(struct i2c_client) + + sizeof(struct eeprom_data)); + + data = (struct eeprom_data *) (new_client + 1); + memset(data, 0xff, EEPROM_SIZE); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &eeprom_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. It is not there, unless you force + the checksum to work out. */ + if (checksum) { + /* prevent 24RF08 corruption */ + i2c_smbus_write_quick(new_client, 0); + cs = 0; + for (i = 0; i <= 0x3e; i++) + cs += i2c_smbus_read_byte_data(new_client, i); + cs &= 0xff; + if (i2c_smbus_read_byte_data (new_client, EEPROM_REG_CHECKSUM) != cs) + goto exit_kfree; + } + + /* Detect the Vaio nature of EEPROMs. + We use the "PCG-" prefix as the signature. */ + if (address == 0x57) { + if (i2c_smbus_read_byte_data(new_client, 0x80) == 'P' && + i2c_smbus_read_byte_data(new_client, 0x81) == 'C' && + i2c_smbus_read_byte_data(new_client, 0x82) == 'G' && + i2c_smbus_read_byte_data(new_client, 0x83) == '-') + nature = VAIO; + } + + /* If this is a VIAO, then we only allow root to read from this file, + as BIOS passwords can be present here in plaintext */ + switch (nature) { + case VAIO: + eeprom_attr.attr.mode = S_IRUSR; + break; + default: + eeprom_attr.attr.mode = S_IRUGO; + } + + /* Fill in the remaining client fields */ + strncpy(new_client->name, "eeprom", I2C_NAME_SIZE); + new_client->id = eeprom_id++; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_kfree; + + /* create the sysfs eeprom file */ + sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr); + + return 0; + +exit_kfree: + kfree(new_client); +exit: + return err; +} + +static int eeprom_detach_client(struct i2c_client *client) +{ + int err; + + err = i2c_detach_client(client); + if (err) { + dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + + return 0; +} + +static int __init eeprom_init(void) +{ + return i2c_add_driver(&eeprom_driver); +} + +static void __exit eeprom_exit(void) +{ + i2c_del_driver(&eeprom_driver); +} + + +MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and " + "Philip Edelbrock <phil@netroedge.com> and " + "Greg Kroah-Hartman <greg@kroah.com>"); +MODULE_DESCRIPTION("I2C EEPROM driver"); +MODULE_LICENSE("GPL"); + +module_init(eeprom_init); +module_exit(eeprom_exit); diff --git a/drivers/i2c/i2c-sensor.c b/drivers/i2c/i2c-sensor.c index 37ef97d470f1..ccfb8baac06c 100644 --- a/drivers/i2c/i2c-sensor.c +++ b/drivers/i2c/i2c-sensor.c @@ -50,10 +50,7 @@ int i2c_detect(struct i2c_adapter *adapter, return -1; for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) { - void *region_used = request_region(addr, 1, "foo"); - release_region(addr, 1); - if ((is_isa && (region_used == NULL)) || - (!is_isa && i2c_check_addr(adapter, addr))) + if (!is_isa && i2c_check_addr(adapter, addr)) continue; /* If it is in one of the force entries, we don't do any diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index c6446bd0d4e6..0531e2e7c519 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -35,7 +35,6 @@ obj-$(CONFIG_USB_SE401) += media/ obj-$(CONFIG_USB_STV680) += media/ obj-$(CONFIG_USB_VICAM) += media/ -obj-$(CONFIG_USB_AX8817X) += net/ obj-$(CONFIG_USB_CATC) += net/ obj-$(CONFIG_USB_KAWETH) += net/ obj-$(CONFIG_USB_PEGASUS) += net/ diff --git a/drivers/usb/Makefile.lib b/drivers/usb/Makefile.lib index 26e36d9c653d..78bfdd1ad89c 100644 --- a/drivers/usb/Makefile.lib +++ b/drivers/usb/Makefile.lib @@ -1,4 +1,3 @@ -obj-$(CONFIG_USB_AX8817X) += crc32.o obj-$(CONFIG_USB_CATC) += crc32.o obj-$(CONFIG_USB_SPEEDTOUCH) += crc32.o obj-$(CONFIG_USB_USBNET) += crc32.o diff --git a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c index 8ffbd3cfa34a..e817e90c6948 100644 --- a/drivers/usb/class/usb-midi.c +++ b/drivers/usb/class/usb-midi.c @@ -1750,7 +1750,7 @@ static int alloc_usb_midi_device( struct usb_device *d, struct usb_midi_state *s return 0; error_end: - if ( mdevs != NULL && devices > 0 ) { + if ( mdevs != NULL ) { for ( i=0 ; i<devices ; i++ ) { if ( mdevs[i] != NULL ) { unregister_sound_midi( mdevs[i]->dev_midi ); diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 00a63ae9b7da..2332526cd803 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -237,9 +237,6 @@ int usb_parse_configuration(struct usb_host_config *config, char *buffer, int si memset(interface, 0, sizeof(struct usb_interface)); interface->dev.release = usb_release_intf; device_initialize(&interface->dev); - - /* put happens in usb_destroy_configuration */ - get_device(&interface->dev); } /* Go through the descriptors, checking their length and counting the diff --git a/drivers/usb/core/driverfs.c b/drivers/usb/core/driverfs.c index 6e56fcb7cc7f..6a177d5932a4 100644 --- a/drivers/usb/core/driverfs.c +++ b/drivers/usb/core/driverfs.c @@ -23,22 +23,44 @@ #include "usb.h" /* Active configuration fields */ -#define usb_actconfig_attr(field, format_string) \ +#define usb_actconfig_show(field, format_string) \ static ssize_t \ show_##field (struct device *dev, char *buf) \ { \ struct usb_device *udev; \ \ udev = to_usb_device (dev); \ + if (udev->actconfig) \ return sprintf (buf, format_string, udev->actconfig->desc.field); \ + else return 0; \ } \ + +#define usb_actconfig_attr(field, format_string) \ +usb_actconfig_show(field,format_string) \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); usb_actconfig_attr (bNumInterfaces, "%2d\n") -usb_actconfig_attr (bConfigurationValue, "%2d\n") usb_actconfig_attr (bmAttributes, "%2x\n") usb_actconfig_attr (bMaxPower, "%3dmA\n") +/* configuration value is always present, and r/w */ +usb_actconfig_show(bConfigurationValue,"%u\n"); + +static ssize_t +set_bConfigurationValue (struct device *dev, const char *buf, size_t count) +{ + struct usb_device *udev = udev = to_usb_device (dev); + int config, value; + + if (sscanf (buf, "%u", &config) != 1 || config > 255) + return -EINVAL; + value = usb_set_configuration (udev, config); + return (value < 0) ? value : count; +} + +static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, + show_bConfigurationValue, set_bConfigurationValue); + /* String fields */ static ssize_t show_product (struct device *dev, char *buf) { diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index dc3a0734aa3b..6070530a09f4 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -273,17 +273,17 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) int retval = 0; hcd = pci_get_drvdata(dev); + dev_dbg (hcd->controller, "suspend D%d --> D%d\n", + dev->current_state, state); + switch (hcd->state) { case USB_STATE_HALT: dev_dbg (hcd->controller, "halted; hcd not suspended\n"); break; case USB_STATE_SUSPENDED: - dev_dbg (hcd->controller, "suspend D%d --> D%d\n", - dev->current_state, state); + dev_dbg (hcd->controller, "hcd already suspended\n"); break; default: - dev_dbg (hcd->controller, "suspend to state %d\n", state); - /* remote wakeup needs hub->suspend() cooperation */ // pci_enable_wake (dev, 3, 1); @@ -292,6 +292,9 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) /* driver may want to disable DMA etc */ hcd->state = USB_STATE_QUIESCING; retval = hcd->driver->suspend (hcd, state); + if (retval) + dev_dbg (hcd->controller, "suspend fail, retval %d\n", + retval); } pci_set_power_state (dev, state); @@ -311,6 +314,9 @@ int usb_hcd_pci_resume (struct pci_dev *dev) int retval; hcd = pci_get_drvdata(dev); + dev_dbg (hcd->controller, "resume from state D%d\n", + dev->current_state); + if (hcd->state != USB_STATE_SUSPENDED) { dev_dbg (hcd->controller, "can't resume, not suspended!\n"); return -EL3HLT; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 3990e5c6238c..374527d88b55 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -781,18 +781,40 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf) * @skip_ep0: 0 to disable endpoint 0, 1 to skip it. * * Disables all the device's endpoints, potentially including endpoint 0. - * Deallocates hcd/hardware state for the endpoints ... and nukes all - * pending urbs. + * Deallocates hcd/hardware state for the endpoints (nuking all or most + * pending urbs) and usbcore state for the interfaces, so that usbcore + * must usb_set_configuration() before any interfaces could be used. */ void usb_disable_device(struct usb_device *dev, int skip_ep0) { int i; - dbg("nuking URBs for device %s", dev->dev.bus_id); + dev_dbg(&dev->dev, "%s nuking %s URBs\n", __FUNCTION__, + skip_ep0 ? "non-ep0" : "all"); for (i = skip_ep0; i < 16; ++i) { usb_disable_endpoint(dev, i); usb_disable_endpoint(dev, i + USB_DIR_IN); } + dev->toggle[0] = dev->toggle[1] = 0; + dev->halted[0] = dev->halted[1] = 0; + + /* getting rid of interfaces will disconnect + * any drivers bound to them (a key side effect) + */ + if (dev->actconfig) { + for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *interface; + + /* remove this interface */ + interface = dev->actconfig->interface[i]; + dev_dbg (&dev->dev, "unregistering interface %s\n", + interface->dev.bus_id); + device_del(&interface->dev); + } + dev->actconfig = 0; + if (dev->state == USB_STATE_CONFIGURED) + dev->state = USB_STATE_ADDRESS; + } } @@ -979,6 +1001,9 @@ int usb_reset_configuration(struct usb_device *dev) int i, retval; struct usb_host_config *config; + /* dev->serialize guards all config changes */ + down(&dev->serialize); + for (i = 1; i < 16; ++i) { usb_disable_endpoint(dev, i); usb_disable_endpoint(dev, i + USB_DIR_IN); @@ -989,8 +1014,10 @@ int usb_reset_configuration(struct usb_device *dev) USB_REQ_SET_CONFIGURATION, 0, config->desc.bConfigurationValue, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); - if (retval < 0) - return retval; + if (retval < 0) { + dev->state = USB_STATE_ADDRESS; + goto done; + } dev->toggle[0] = dev->toggle[1] = 0; dev->halted[0] = dev->halted[1] = 0; @@ -1002,7 +1029,9 @@ int usb_reset_configuration(struct usb_device *dev) intf->act_altsetting = 0; usb_enable_interface(dev, intf); } - return 0; +done: + up(&dev->serialize); + return (retval < 0) ? retval : 0; } /** @@ -1012,72 +1041,105 @@ int usb_reset_configuration(struct usb_device *dev) * Context: !in_interrupt () * * This is used to enable non-default device modes. Not all devices - * support this kind of configurability. By default, configuration - * zero is selected after enumeration; many devices only have a single + * use this kind of configurability; many devices only have one * configuration. * - * USB devices may support one or more configurations, which affect + * USB device configurations may affect Linux interoperability, * power consumption and the functionality available. For example, * the default configuration is limited to using 100mA of bus power, * so that when certain device functionality requires more power, - * and the device is bus powered, that functionality will be in some + * and the device is bus powered, that functionality should be in some * non-default device configuration. Other device modes may also be * reflected as configuration options, such as whether two ISDN - * channels are presented as independent 64Kb/s interfaces or as one - * bonded 128Kb/s interface. + * channels are available independently; and choosing between open + * standard device protocols (like CDC) or proprietary ones. * * Note that USB has an additional level of device configurability, * associated with interfaces. That configurability is accessed using * usb_set_interface(). * - * This call is synchronous, and may not be used in an interrupt context. + * This call is synchronous. The calling context must be able to sleep, + * and must not hold the driver model lock for USB; usb device driver + * probe() methods may not use this routine. * * Returns zero on success, or else the status code returned by the - * underlying usb_control_msg() call. + * underlying call that failed. On succesful completion, each interface + * in the original device configuration has been destroyed, and each one + * in the new configuration has been probed by all relevant usb device + * drivers currently known to the kernel. */ int usb_set_configuration(struct usb_device *dev, int configuration) { int i, ret; struct usb_host_config *cp = NULL; + /* dev->serialize guards all config changes */ + down(&dev->serialize); + for (i=0; i<dev->descriptor.bNumConfigurations; i++) { if (dev->config[i].desc.bConfigurationValue == configuration) { cp = &dev->config[i]; break; } } - if ((!cp && configuration != 0) || (cp && configuration == 0)) { - warn("selecting invalid configuration %d", configuration); - return -EINVAL; + if ((!cp && configuration != 0)) { + ret = -EINVAL; + goto out; } + if (cp && configuration == 0) + dev_warn(&dev->dev, "config 0 descriptor??\n"); - /* if it's already configured, clear out old state first. */ + /* if it's already configured, clear out old state first. + * getting rid of old interfaces means unbinding their drivers. + */ if (dev->state != USB_STATE_ADDRESS) usb_disable_device (dev, 1); // Skip ep0 - dev->toggle[0] = dev->toggle[1] = 0; - dev->halted[0] = dev->halted[1] = 0; - dev->state = USB_STATE_ADDRESS; if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION, 0, configuration, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0) - return ret; - if (configuration) - dev->state = USB_STATE_CONFIGURED; - dev->actconfig = cp; + goto out; - /* reset more hc/hcd interface/endpoint state */ - for (i = 0; i < cp->desc.bNumInterfaces; ++i) { - struct usb_interface *intf = cp->interface[i]; + dev->actconfig = cp; + if (!configuration) + dev->state = USB_STATE_ADDRESS; + else { + dev->state = USB_STATE_CONFIGURED; - intf->act_altsetting = 0; - usb_enable_interface(dev, intf); + /* re-initialize hc/hcd/usbcore interface/endpoint state. + * this triggers binding of drivers to interfaces; and + * maybe probe() calls will choose different altsettings. + */ + for (i = 0; i < cp->desc.bNumInterfaces; ++i) { + struct usb_interface *intf = cp->interface[i]; + struct usb_interface_descriptor *desc; + + intf->act_altsetting = 0; + desc = &intf->altsetting [0].desc; + usb_enable_interface(dev, intf); + + intf->dev.parent = &dev->dev; + intf->dev.driver = NULL; + intf->dev.bus = &usb_bus_type; + intf->dev.dma_mask = dev->dev.dma_mask; + sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", + dev->bus->busnum, dev->devpath, + configuration, + desc->bInterfaceNumber); + dev_dbg (&dev->dev, + "registering %s (config #%d, interface %d)\n", + intf->dev.bus_id, configuration, + desc->bInterfaceNumber); + device_add (&intf->dev); + usb_create_driverfs_intf_files (intf); + } } - return 0; +out: + up(&dev->serialize); + return ret; } - /** * usb_string - returns ISO 8859-1 version of a string descriptor * @dev: the device whose string descriptor is being retrieved diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 8717775dc0b1..5d2b6ebdf517 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -898,6 +898,7 @@ void usb_disconnect(struct usb_device **pdev) * this device will fail. */ dev->state = USB_STATE_NOTATTACHED; + down(&dev->serialize); dev_info (&dev->dev, "USB disconnect, address %d\n", dev->devnum); @@ -908,32 +909,19 @@ void usb_disconnect(struct usb_device **pdev) usb_disconnect(child); } - /* deallocate hcd/hardware state ... and nuke all pending urbs */ + /* deallocate hcd/hardware state ... nuking all pending urbs and + * cleaning up all state associated with the current configuration + */ usb_disable_device(dev, 0); - /* disconnect() drivers from interfaces (a key side effect) */ - dev_dbg (&dev->dev, "unregistering interfaces\n"); - if (dev->actconfig) { - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *interface; - - /* remove this interface */ - interface = dev->actconfig->interface[i]; - device_unregister(&interface->dev); - } - } - dev_dbg (&dev->dev, "unregistering device\n"); /* Free the device number and remove the /proc/bus/usb entry */ if (dev->devnum > 0) { clear_bit(dev->devnum, dev->bus->devmap.devicemap); usbfs_remove_device(dev); } + up(&dev->serialize); device_unregister(&dev->dev); - - /* Decrement the reference count, it'll auto free everything when */ - /* it hits 0 which could very well be now */ - usb_put_dev(dev); } /** @@ -1017,7 +1005,6 @@ int usb_new_device(struct usb_device *dev, struct device *parent) dev->dev.driver = &usb_generic_driver; dev->dev.bus = &usb_bus_type; dev->dev.driver_data = &usb_generic_driver_data; - usb_get_dev(dev); if (dev->dev.bus_id[0] == 0) sprintf (&dev->dev.bus_id[0], "%d-%s", dev->bus->busnum, dev->devpath); @@ -1090,27 +1077,12 @@ int usb_new_device(struct usb_device *dev, struct device *parent) err = usb_get_configuration(dev); if (err < 0) { - dev_err(&dev->dev, "unable to get device %d configuration (error=%d)\n", - dev->devnum, err); - goto fail; - } - - /* choose and set the configuration here */ - if (dev->descriptor.bNumConfigurations != 1) { - dev_info(&dev->dev, - "configuration #%d chosen from %d choices\n", - dev->config[0].desc.bConfigurationValue, - dev->descriptor.bNumConfigurations); - } - err = usb_set_configuration(dev, dev->config[0].desc.bConfigurationValue); - if (err) { - dev_err(&dev->dev, "failed to set device %d default configuration (error=%d)\n", - dev->devnum, err); + dev_err(&dev->dev, "can't read configurations, error %d\n", + err); goto fail; } - /* USB device state == configured ... tell the world! */ - + /* Tell the world! */ dev_dbg(&dev->dev, "new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n", dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber); @@ -1123,30 +1095,32 @@ int usb_new_device(struct usb_device *dev, struct device *parent) usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); #endif - /* put into sysfs, with device and config specific files */ + /* put device-specific files into sysfs */ err = device_add (&dev->dev); - if (err) + if (err) { + dev_err(&dev->dev, "can't device_add, error %d\n", err); goto fail; + } usb_create_driverfs_dev_files (dev); - /* Register all of the interfaces for this device with the driver core. - * Remember, interfaces get bound to drivers, not devices. */ - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *interface = dev->actconfig->interface[i]; - struct usb_interface_descriptor *desc; - - desc = &interface->altsetting [interface->act_altsetting].desc; - interface->dev.parent = &dev->dev; - interface->dev.driver = NULL; - interface->dev.bus = &usb_bus_type; - interface->dev.dma_mask = parent->dma_mask; - sprintf (&interface->dev.bus_id[0], "%d-%s:%d", - dev->bus->busnum, dev->devpath, - desc->bInterfaceNumber); - dev_dbg (&dev->dev, "%s - registering interface %s\n", __FUNCTION__, interface->dev.bus_id); - device_add (&interface->dev); - usb_create_driverfs_intf_files (interface); + /* choose and set the configuration. that registers the interfaces + * with the driver core, and lets usb device drivers bind to them. + */ + if (dev->descriptor.bNumConfigurations != 1) { + dev_info(&dev->dev, + "configuration #%d chosen from %d choices\n", + dev->config[0].desc.bConfigurationValue, + dev->descriptor.bNumConfigurations); } + err = usb_set_configuration(dev, + dev->config[0].desc.bConfigurationValue); + if (err) { + dev_err(&dev->dev, "can't set config #%d, error %d\n", + dev->config[0].desc.bConfigurationValue, err); + goto fail; + } + + /* USB device state == configured ... usable */ /* add a /proc/bus/usb entry */ usbfs_add_device(dev); @@ -1156,7 +1130,6 @@ fail: dev->state = USB_STATE_DEFAULT; clear_bit(dev->devnum, dev->bus->devmap.devicemap); dev->devnum = -1; - usb_put_dev(dev); return err; } diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 9d0073171a8f..cdec8e8420f4 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -93,6 +93,7 @@ struct eth_dev { struct usb_ep *in_ep, *out_ep, *status_ep; const struct usb_endpoint_descriptor *in, *out, *status; + struct list_head tx_reqs, rx_reqs; struct net_device *net; struct net_device_stats stats; @@ -105,28 +106,6 @@ struct eth_dev { /*-------------------------------------------------------------------------*/ -/* This driver keeps a variable number of requests queued, more at - * high speeds. (Numbers are just educated guesses, untuned.) - * Shrink the queue if memory is tight, or make it bigger to - * handle bigger traffic bursts between IRQs. - */ - -static unsigned qmult = 4; - -#define HS_FACTOR 5 - -#define qlen(gadget) \ - (qmult*((gadget->speed == USB_SPEED_HIGH) ? HS_FACTOR : 1)) - -/* defer IRQs on highspeed TX */ -#define TX_DELAY 8 - - -module_param (qmult, uint, S_IRUGO|S_IWUSR); - - -/*-------------------------------------------------------------------------*/ - /* Thanks to NetChip Technologies for donating this product ID. * * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! @@ -175,6 +154,7 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR); */ #ifdef CONFIG_USB_ETH_NET2280 #define CHIP "net2280" +#define DEFAULT_QLEN 4 /* has dma chaining */ #define DRIVER_VERSION_NUM 0x0101 #define EP0_MAXPACKET 64 static const char EP_OUT_NAME [] = "ep-a"; @@ -220,7 +200,7 @@ static const char EP_IN_NAME [] = "ep1in-bulk"; /* supports remote wakeup, but this driver doesn't */ /* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0); +#define hw_optimize(g) do {} while (0) #endif /* @@ -243,7 +223,7 @@ static const char EP_IN_NAME [] = "ep2in-bulk"; /* doesn't support remote wakeup? */ /* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0); +#define hw_optimize(g) do {} while (0) #endif /*-------------------------------------------------------------------------*/ @@ -301,9 +281,32 @@ static const char EP_IN_NAME [] = "ep2in-bulk"; /*-------------------------------------------------------------------------*/ +#ifndef DEFAULT_QLEN +#define DEFAULT_QLEN 2 /* double buffering by default */ +#endif + +#ifdef HIGHSPEED + +static unsigned qmult = 5; +module_param (qmult, uint, S_IRUGO|S_IWUSR); + + +/* for dual-speed hardware, use deeper queues at highspeed */ +#define qlen(gadget) \ + (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1)) + +/* also defer IRQs on highspeed TX */ +#define TX_DELAY DEFAULT_QLEN + +#else /* !HIGHSPEED ... full speed: */ +#define qlen(gadget) DEFAULT_QLEN +#endif + + +/*-------------------------------------------------------------------------*/ + #define xprintk(d,level,fmt,args...) \ - printk(level "%s %s: " fmt , shortname , (d)->gadget->dev.bus_id , \ - ## args) + printk(level "%s: " fmt , (d)->net->name , ## args) #ifdef DEBUG #undef DEBUG @@ -763,6 +766,7 @@ config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) /*-------------------------------------------------------------------------*/ 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 int set_ether_config (struct eth_dev *dev, int gfp_flags) @@ -852,11 +856,21 @@ set_ether_config (struct eth_dev *dev, int gfp_flags) if (!result && (!dev->in_ep || !dev->out_ep)) result = -ENODEV; + if (result == 0) + result = alloc_requests (dev, qlen (gadget), gfp_flags); + #ifndef DEV_CONFIG_CDC if (result == 0) { netif_carrier_on (dev->net); if (netif_running (dev->net)) eth_start (dev, GFP_ATOMIC); + } else { + (void) usb_ep_disable (dev->in_ep); + dev->in_ep = 0; + dev->in = 0; + (void) usb_ep_disable (dev->out_ep); + dev->out_ep = 0; + dev->out = 0; } #endif /* !CONFIG_CDC_ETHER */ @@ -869,6 +883,8 @@ set_ether_config (struct eth_dev *dev, int gfp_flags) static void eth_reset_config (struct eth_dev *dev) { + struct usb_request *req; + if (dev->config == 0) return; @@ -877,17 +893,30 @@ static void eth_reset_config (struct eth_dev *dev) netif_stop_queue (dev->net); netif_carrier_off (dev->net); - /* just disable endpoints, forcing completion of pending i/o. - * all our completion handlers free their requests in this case. + /* disable endpoints, forcing (synchronous) completion of + * pending i/o. then free the requests. */ if (dev->in_ep) { usb_ep_disable (dev->in_ep); + while (likely (!list_empty (&dev->tx_reqs))) { + req = container_of (dev->tx_reqs.next, + struct usb_request, list); + list_del (&req->list); + usb_ep_free_request (dev->in_ep, req); + } dev->in_ep = 0; } if (dev->out_ep) { usb_ep_disable (dev->out_ep); + while (likely (!list_empty (&dev->rx_reqs))) { + req = container_of (dev->rx_reqs.next, + struct usb_request, list); + list_del (&req->list); + usb_ep_free_request (dev->out_ep, req); + } dev->out_ep = 0; } + #ifdef EP_STATUS_NUM if (dev->status_ep) { usb_ep_disable (dev->status_ep); @@ -1345,7 +1374,8 @@ static int eth_ioctl (struct net_device *net, struct ifreq *rq, int cmd) static void defer_kevent (struct eth_dev *dev, int flag) { - set_bit (flag, &dev->todo); + if (test_and_set_bit (flag, &dev->todo)) + return; if (!schedule_work (&dev->work)) ERROR (dev, "kevent %d may have been dropped\n", flag); else @@ -1366,7 +1396,7 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) if ((skb = alloc_skb (size, gfp_flags)) == 0) { DEBUG (dev, "no rx skb\n"); defer_kevent (dev, WORK_RX_MEMORY); - usb_ep_free_request (dev->out_ep, req); + list_add (&req->list, &dev->rx_reqs); return -ENOMEM; } @@ -1381,7 +1411,7 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) if (retval) { DEBUG (dev, "rx submit --> %d\n", retval); dev_kfree_skb_any (skb); - usb_ep_free_request (dev->out_ep, req); + list_add (&req->list, &dev->rx_reqs); } return retval; } @@ -1421,6 +1451,14 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req) case -ECONNRESET: // unlink case -ESHUTDOWN: // disconnect etc VDEBUG (dev, "rx shutdown, code %d\n", status); + goto quiesce; + + /* for hardware automagic (such as pxa) */ + case -ECONNABORTED: // endpoint reset + DEBUG (dev, "rx %s reset\n", ep->name); + defer_kevent (dev, WORK_RX_MEMORY); +quiesce: + dev_kfree_skb_any (skb); goto clean; /* data overrun */ @@ -1438,28 +1476,96 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req) dev_kfree_skb_any (skb); if (!netif_running (dev->net)) { clean: - usb_ep_free_request (dev->out_ep, req); + list_add (&req->list, &dev->rx_reqs); req = 0; } if (req) rx_submit (dev, req, GFP_ATOMIC); } +static int prealloc (struct list_head *list, struct usb_ep *ep, + unsigned n, int gfp_flags) +{ + unsigned i; + struct usb_request *req; + + if (!n) + return -ENOMEM; + + /* queue/recycle up to N requests */ + i = n; + list_for_each_entry (req, list, list) { + if (i-- == 0) + goto extra; + } + while (i--) { + req = usb_ep_alloc_request (ep, gfp_flags); + if (!req) + return list_empty (list) ? -ENOMEM : 0; + list_add (&req->list, list); + } + return 0; + +extra: + /* free extras */ + for (;;) { + struct list_head *next; + + next = req->list.next; + list_del (&req->list); + usb_ep_free_request (ep, req); + + if (next == list) + break; + + req = container_of (next, struct usb_request, list); + } + return 0; +} + +static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags) +{ + int status; + + status = prealloc (&dev->tx_reqs, dev->in_ep, n, gfp_flags); + if (status < 0) + goto fail; + status = prealloc (&dev->rx_reqs, dev->out_ep, n, gfp_flags); + if (status < 0) + goto fail; + return 0; +fail: + DEBUG (dev, "can't alloc requests\n"); + return status; +} + +static void rx_fill (struct eth_dev *dev, int gfp_flags) +{ + struct usb_request *req; + + clear_bit (WORK_RX_MEMORY, &dev->todo); + + /* fill unused rxq slots with some skb */ + while (!list_empty (&dev->rx_reqs)) { + req = container_of (dev->rx_reqs.next, + struct usb_request, list); + list_del_init (&req->list); + if (rx_submit (dev, req, gfp_flags) < 0) { + defer_kevent (dev, WORK_RX_MEMORY); + return; + } + } +} + static void eth_work (void *_dev) { struct eth_dev *dev = _dev; if (test_bit (WORK_RX_MEMORY, &dev->todo)) { - struct usb_request *req = 0; - if (netif_running (dev->net)) - req = usb_ep_alloc_request (dev->in_ep, GFP_KERNEL); + rx_fill (dev, GFP_KERNEL); else clear_bit (WORK_RX_MEMORY, &dev->todo); - if (req != 0) { - clear_bit (WORK_RX_MEMORY, &dev->todo); - rx_submit (dev, req, GFP_KERNEL); - } } if (dev->todo) @@ -1484,10 +1590,10 @@ static void tx_complete (struct usb_ep *ep, struct usb_request *req) } dev->stats.tx_packets++; - usb_ep_free_request (ep, req); + list_add (&req->list, &dev->tx_reqs); dev_kfree_skb_any (skb); - atomic_inc (&dev->tx_qlen); + atomic_dec (&dev->tx_qlen); if (netif_carrier_ok (dev->net)) netif_wake_queue (dev->net); } @@ -1499,10 +1605,10 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) int retval; struct usb_request *req = 0; - if (!(req = usb_ep_alloc_request (dev->in_ep, GFP_ATOMIC))) { - DEBUG (dev, "no request\n"); - goto drop; - } + req = container_of (dev->tx_reqs.next, struct usb_request, list); + list_del (&req->list); + if (list_empty (&dev->tx_reqs)) + netif_stop_queue (net); /* no buffer copies needed, unless the network stack did it * or the hardware can't use skb buffers. @@ -1537,42 +1643,28 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) break; case 0: net->trans_start = jiffies; - if (atomic_dec_and_test (&dev->tx_qlen)) - netif_stop_queue (net); + atomic_inc (&dev->tx_qlen); } if (retval) { - DEBUG (dev, "drop, code %d\n", retval); -drop: dev->stats.tx_dropped++; dev_kfree_skb_any (skb); - usb_ep_free_request (dev->in_ep, req); + if (list_empty (&dev->tx_reqs)) + netif_start_queue (net); + list_add (&req->list, &dev->tx_reqs); } return 0; } static void eth_start (struct eth_dev *dev, int gfp_flags) { - struct usb_request *req; - int retval = 0; - unsigned i; - int size = qlen (dev->gadget); - DEBUG (dev, "%s\n", __FUNCTION__); /* fill the rx queue */ - for (i = 0; retval == 0 && i < size; i++) { - req = usb_ep_alloc_request (dev->in_ep, gfp_flags); - if (req) - retval = rx_submit (dev, req, gfp_flags); - else if (i > 0) - defer_kevent (dev, WORK_RX_MEMORY); - else - retval = -ENOMEM; - } + rx_fill (dev, gfp_flags); /* and open the tx floodgates */ - atomic_set (&dev->tx_qlen, size); + atomic_set (&dev->tx_qlen, 0); netif_wake_queue (dev->net); } @@ -1590,7 +1682,7 @@ static int eth_stop (struct net_device *net) { struct eth_dev *dev = (struct eth_dev *) net->priv; - DEBUG (dev, "%s\n", __FUNCTION__); + VDEBUG (dev, "%s\n", __FUNCTION__); netif_stop_queue (net); DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n", @@ -1604,6 +1696,7 @@ static int eth_stop (struct net_device *net) usb_ep_disable (dev->out_ep); if (netif_carrier_ok (dev->net)) { DEBUG (dev, "host still using in/out endpoints\n"); + // FIXME idiom may leave toggle wrong here usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); } @@ -1662,6 +1755,8 @@ eth_bind (struct usb_gadget *gadget) dev = net->priv; spin_lock_init (&dev->lock); INIT_WORK (&dev->work, eth_work, dev); + INIT_LIST_HEAD (&dev->tx_reqs); + INIT_LIST_HEAD (&dev->rx_reqs); /* network device setup */ dev->net = net; @@ -1714,10 +1809,6 @@ eth_bind (struct usb_gadget *gadget) dev->gadget = gadget; set_gadget_data (gadget, dev); gadget->ep0->driver_data = dev; - INFO (dev, "%s, " CHIP ", version: " DRIVER_VERSION "\n", driver_desc); -#ifdef DEV_CONFIG_CDC - INFO (dev, "CDC host enet %s\n", ethaddr); -#endif /* two kinds of host-initiated state changes: * - iff DATA transfer is active, carrier is "on" @@ -1728,8 +1819,16 @@ eth_bind (struct usb_gadget *gadget) // SET_NETDEV_DEV (dev->net, &gadget->dev); status = register_netdev (dev->net); - if (status == 0) + if (status == 0) { + + INFO (dev, "%s, " CHIP ", version: " DRIVER_VERSION "\n", + driver_desc); +#ifdef DEV_CONFIG_CDC + INFO (dev, "CDC host enet %s\n", ethaddr); +#endif return status; + } + dev_dbg(&gadget->dev, "register_netdev failed, %d\n", status); fail: eth_unbind (gadget); return status; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 64fef4a8580e..4f3574871c66 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -354,6 +354,7 @@ static ssize_t ep_io (struct ep_data *epdata, void *buf, unsigned len) { DECLARE_COMPLETION (done); + int value; spin_lock_irq (&epdata->dev->lock); if (likely (epdata->ep != NULL)) { @@ -363,14 +364,12 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len) req->complete = epio_complete; req->buf = buf; req->length = len; - epdata->status = usb_ep_queue (epdata->ep, req, GFP_ATOMIC); + value = usb_ep_queue (epdata->ep, req, GFP_ATOMIC); } else - epdata->status = -ENODEV; + value = -ENODEV; spin_unlock_irq (&epdata->dev->lock); - if (epdata->status == 0) { - int value; - + if (likely (value == 0)) { value = wait_event_interruptible (done.wait, done.done); if (value != 0) { spin_lock_irq (&epdata->dev->lock); @@ -378,17 +377,21 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len) DBG (epdata->dev, "%s i/o interrupted\n", epdata->name); usb_ep_dequeue (epdata->ep, epdata->req); + spin_unlock_irq (&epdata->dev->lock); + wait_event (done.wait, done.done); - if (epdata->status == 0) - epdata->status = value; + if (epdata->status == -ECONNRESET) + epdata->status = -EINTR; } else { + spin_unlock_irq (&epdata->dev->lock); + DBG (epdata->dev, "endpoint gone\n"); epdata->status = -ENODEV; } - spin_unlock_irq (&epdata->dev->lock); } + return epdata->status; } - return epdata->status; + return value; } @@ -424,10 +427,12 @@ ep_read (struct file *fd, char *buf, size_t len, loff_t *ptr) if (unlikely (!kbuf)) goto free1; - VDEBUG (data->dev, "%s read %d OUT\n", data->name, len); value = ep_io (data, kbuf, len); + VDEBUG (data->dev, "%s read %d OUT, status %d\n", + data->name, len, value); if (value >= 0 && copy_to_user (buf, kbuf, value)) value = -EFAULT; + free1: up (&data->lock); kfree (kbuf); @@ -470,8 +475,9 @@ ep_write (struct file *fd, const char *buf, size_t len, loff_t *ptr) goto free1; } - VDEBUG (data->dev, "%s write %d IN\n", data->name, len); value = ep_io (data, kbuf, len); + VDEBUG (data->dev, "%s write %d IN, status %d\n", + data->name, len, value); free1: up (&data->lock); kfree (kbuf); @@ -1200,9 +1206,11 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (value >= 0) value = min (ctrl->wLength, (u16) value); break; - - default: + case USB_DT_STRING: goto unrecognized; + + default: // all others are errors + break; } break; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index b1cb550cbb47..6e6b4424e030 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -1965,13 +1965,11 @@ static void reset_hc(struct uhci_hcd *uhci) outw(USBCMD_GRESET, io_addr + USBCMD); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((HZ*50+999) / 1000); - set_current_state(TASK_RUNNING); outw(0, io_addr + USBCMD); /* Another 10ms delay */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((HZ*10+999) / 1000); - set_current_state(TASK_RUNNING); uhci->resume_detect = 0; } diff --git a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c index e9dcb02a846d..55d1aa68ed9b 100644 --- a/drivers/usb/image/scanner.c +++ b/drivers/usb/image/scanner.c @@ -1,7 +1,7 @@ /* -*- linux-c -*- */ /* - * Driver for USB Scanners (linux-2.5) + * Driver for USB Scanners (linux-2.6) * * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson * Copyright (C) 2002, 2003 Henning Meier-Geinitz @@ -369,6 +369,18 @@ * - Added vendor/product ids for Avision, Canon, HP, Microtek and Relisys scanners. * - Clean up irq urb when not enough memory is available. * + * 0.4.15 2003-09-22 + * - Use static declarations for usb_scanner_init/usb_scanner_exit + * (Daniele Bellucci). + * - Report back return codes of usb_register and usb_usbmit_urb instead of -1 or + * -ENONMEM (Daniele Bellucci). + * - Balancing usb_register_dev/usb_deregister_dev in probe_scanner when a fail + * condition occours (Daniele Bellucci). + * - Added vendor/product ids for Canon, HP, Microtek, Mustek, Siemens, UMAX, and + * Visioneer scanners. + * - Added test for USB_CLASS_CDC_DATA which is used by some fingerprint scanners. + * + * * TODO * - Performance * - Select/poll methods @@ -950,6 +962,7 @@ probe_scanner(struct usb_interface *intf, if (interface[0].desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC && interface[0].desc.bInterfaceClass != USB_CLASS_PER_INTERFACE && + interface[0].desc.bInterfaceClass != USB_CLASS_CDC_DATA && interface[0].desc.bInterfaceClass != SCN_CLASS_SCANJET) { dbg("probe_scanner: This interface doesn't look like a scanner (class=0x%x).", interface[0].desc.bInterfaceClass); return -ENODEV; @@ -1043,6 +1056,7 @@ probe_scanner(struct usb_interface *intf, scn->scn_irq = usb_alloc_urb(0, GFP_KERNEL); if (!scn->scn_irq) { + usb_deregister_dev(intf, &scanner_class); kfree(scn); up(&scn_mutex); return -ENOMEM; @@ -1061,11 +1075,13 @@ probe_scanner(struct usb_interface *intf, // endpoint[(int)have_intr].bInterval); 250); - if (usb_submit_urb(scn->scn_irq, GFP_KERNEL)) { + retval = usb_submit_urb(scn->scn_irq, GFP_KERNEL); + if (retval) { err("probe_scanner(%d): Unable to allocate INT URB.", intf->minor); + usb_deregister_dev(intf, &scanner_class); kfree(scn); up(&scn_mutex); - return -ENOMEM; + return retval; } } @@ -1076,6 +1092,7 @@ probe_scanner(struct usb_interface *intf, if (have_intr) usb_unlink_urb(scn->scn_irq); usb_free_urb(scn->scn_irq); + usb_deregister_dev(intf, &scanner_class); kfree(scn); up(&scn_mutex); return -ENOMEM; @@ -1087,6 +1104,7 @@ probe_scanner(struct usb_interface *intf, if (have_intr) usb_unlink_urb(scn->scn_irq); usb_free_urb(scn->scn_irq); + usb_deregister_dev(intf, &scanner_class); kfree(scn->obuf); kfree(scn); up(&scn_mutex); @@ -1169,22 +1187,25 @@ usb_driver scanner_driver = { .id_table = ids, }; -void __exit +static void __exit usb_scanner_exit(void) { usb_deregister(&scanner_driver); } -int __init +static int __init usb_scanner_init (void) { - if (usb_register(&scanner_driver) < 0) - return -1; + int retval; + retval = usb_register(&scanner_driver); + if (retval) + goto out; info(DRIVER_VERSION ":" DRIVER_DESC); if (vendor != -1 && product != -1) info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product); - return 0; + out: + return retval; } module_init(usb_scanner_init); diff --git a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h index f5a4be152899..915a4f5e790b 100644 --- a/drivers/usb/image/scanner.h +++ b/drivers/usb/image/scanner.h @@ -1,5 +1,5 @@ /* - * Driver for USB Scanners (linux-2.5) + * Driver for USB Scanners (linux-2.6) * * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson * Previously maintained by Brian Beattie @@ -43,7 +43,7 @@ // #define DEBUG -#define DRIVER_VERSION "0.4.14" +#define DRIVER_VERSION "0.4.15" #define DRIVER_DESC "USB Scanner Driver" #include <linux/usb.h> @@ -122,7 +122,10 @@ static struct usb_device_id scanner_device_ids [] = { { USB_DEVICE(0x04a9, 0x220d) }, /* CanoScan N670U/N676U/LIDE 20 */ { USB_DEVICE(0x04a9, 0x220e) }, /* CanoScan N1240U/LIDE 30 */ { USB_DEVICE(0x04a9, 0x220f) }, /* CanoScan 8000F */ + { USB_DEVICE(0x04a9, 0x2210) }, /* CanoScan 9900F */ + { USB_DEVICE(0x04a9, 0x2212) }, /* CanoScan 5000F */ { USB_DEVICE(0x04a9, 0x2213) }, /* LIDE 50 */ + { USB_DEVICE(0x04a9, 0x2215) }, /* CanoScan 3000 */ { USB_DEVICE(0x04a9, 0x3042) }, /* FS4000US */ /* Colorado -- See Primax/Colorado below */ /* Compaq */ @@ -158,7 +161,9 @@ static struct usb_device_id scanner_device_ids [] = { // { USB_DEVICE(0x03f0, 0x0701) }, /* ScanJet 5300C - NOT SUPPORTED - use hpusbscsi driver */ { USB_DEVICE(0x03f0, 0x0705) }, /* ScanJet 4400C */ // { USB_DEVICE(0x03f0, 0x0801) }, /* ScanJet 7400C - NOT SUPPORTED - use hpusbscsi driver */ + { USB_DEVICE(0x03f0, 0x0805) }, /* ScanJet 4470c */ { USB_DEVICE(0x03f0, 0x0901) }, /* ScanJet 2300C */ + { USB_DEVICE(0x03f0, 0x0a01) }, /* ScanJet 2400c */ { USB_DEVICE(0x03F0, 0x1005) }, /* ScanJet 5400C */ { USB_DEVICE(0x03F0, 0x1105) }, /* ScanJet 5470C */ { USB_DEVICE(0x03f0, 0x1205) }, /* ScanJet 5550C */ @@ -177,9 +182,11 @@ static struct usb_device_id scanner_device_ids [] = { /* Memorex */ { USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */ /* Microtek */ + { USB_DEVICE(0x05da, 0x20a7) }, /* ScanMaker 5600 */ { USB_DEVICE(0x05da, 0x20c9) }, /* ScanMaker 6700 */ { USB_DEVICE(0x05da, 0x30ce) }, /* ScanMaker 3800 */ { USB_DEVICE(0x05da, 0x30cf) }, /* ScanMaker 4800 */ + { USB_DEVICE(0x05da, 0x30d4) }, /* ScanMaker 3830 + 3840 */ { USB_DEVICE(0x04a7, 0x0224) }, /* Scanport 3000 (actually Visioneer?)*/ /* The following SCSI-over-USB Microtek devices are supported by the microtek driver: Enable SCSI and USB Microtek in kernel config */ @@ -214,6 +221,7 @@ static struct usb_device_id scanner_device_ids [] = { { USB_DEVICE(0x055f, 0x021e) }, /* BearPaw 1200 TA/CS */ { USB_DEVICE(0x055f, 0x0400) }, /* BearPaw 2400 TA PRO */ { USB_DEVICE(0x055f, 0x0401) }, /* P 3600 A3 Pro */ + { USB_DEVICE(0x055f, 0x0409) }, /* BearPaw 2448TA Pro */ { USB_DEVICE(0x055f, 0x0873) }, /* ScanExpress 600 USB */ { USB_DEVICE(0x055f, 0x1000) }, /* BearPaw 4800 TA PRO */ // { USB_DEVICE(0x05d8, 0x4002) }, /* BearPaw 1200 CU and ScanExpress 1200 UB Plus (see Artec) */ @@ -279,6 +287,9 @@ static struct usb_device_id scanner_device_ids [] = { { USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */ { USB_DEVICE(0x04b8, 0x0801) }, /* Stylus CX5200 */ { USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */ + /* Siemens */ + { USB_DEVICE(0x0681, 0x0005) }, /* ID Mouse Professional */ + { USB_DEVICE(0x0681, 0x0010) }, /* Cherry FingerTIP ID Board - Sensor */ /* SYSCAN */ { USB_DEVICE(0x0a82, 0x4600) }, /* TravelScan 460/464 */ /* Trust */ @@ -289,6 +300,7 @@ static struct usb_device_id scanner_device_ids [] = { { USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */ { USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */ { USB_DEVICE(0x1606, 0x0060) }, /* Astra 3400U/3450U */ + { USB_DEVICE(0x1606, 0x0070) }, /* Astra 4400 */ { USB_DEVICE(0x1606, 0x0130) }, /* Astra 2100U */ { USB_DEVICE(0x1606, 0x0160) }, /* Astra 5400U */ { USB_DEVICE(0x1606, 0x0230) }, /* Astra 2200U */ @@ -296,7 +308,8 @@ static struct usb_device_id scanner_device_ids [] = { { USB_DEVICE(0x04a7, 0x0211) }, /* OneTouch 7600 USB */ { USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */ { USB_DEVICE(0x04a7, 0x0224) }, /* OneTouch 4800 USB */ - { USB_DEVICE(0x04a7, 0x0226) }, /* OneTouch 5300 USB */ + { USB_DEVICE(0x04a7, 0x0226) }, /* OneTouch 5800 USB */ + { USB_DEVICE(0x04a7, 0x022c) }, /* OneTouch 9020 USB */ { USB_DEVICE(0x04a7, 0x0231) }, /* 6100 USB */ { USB_DEVICE(0x04a7, 0x0311) }, /* 6200 EPP/USB */ { USB_DEVICE(0x04a7, 0x0321) }, /* OneTouch 8100 EPP/USB */ diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index f469397c5780..0dfadc07c43a 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -112,8 +112,8 @@ config USB_MOUSE depends on USB && INPUT ---help--- Say Y here only if you are absolutely sure that you don't want - to use the generic HID driver for your USB keyboard and prefer - to use the keyboard in its limited Boot Protocol mode instead. + to use the generic HID driver for your USB mouse and prefer + to use the mouse in its limited Boot Protocol mode instead. This is almost certainly not what you want. This is mostly useful for embedded applications or simple mice. diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index a1d356bbd0bd..16dcb976d38e 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -7,25 +7,6 @@ comment "USB Network adaptors" comment "Networking support is needed for USB Networking device support" depends on USB && !NET -config USB_AX8817X_STANDALONE - tristate "USB ASIX AX8817X Ethernet device support (EXPERIMENTAL)" - depends on USB && NET && EXPERIMENTAL - ---help--- - Say Y if you want to use one of the following 10/100Mps USB - Ethernet devices based on the ASIX AX88172 chip. Supported - devices are: - ASIX AX88172 - D-Link DUB-E100 - Hawking UF200 - Netgear FA120 - - This driver makes the adapter appear as a normal Ethernet interface, - typically on eth0, if it is the only ethernet device, or perhaps on - eth1, if you have a PCI or ISA ethernet card installed. - - To compile this driver as a module, choose M here: the - module will be called ax8817x. - config USB_CATC tristate "USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)" depends on USB && NET && EXPERIMENTAL diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index 3956f8655d7d..5eec1ed7e40a 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -2,7 +2,6 @@ # Makefile for USB Network drivers # -obj-$(CONFIG_USB_AX8817X_STANDALONE) += ax8817x.o obj-$(CONFIG_USB_CATC) += catc.o obj-$(CONFIG_USB_KAWETH) += kaweth.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o diff --git a/drivers/usb/net/Makefile.mii b/drivers/usb/net/Makefile.mii index 34c2f5585d10..20cf79adacc2 100644 --- a/drivers/usb/net/Makefile.mii +++ b/drivers/usb/net/Makefile.mii @@ -2,6 +2,5 @@ # Makefile for USB Network drivers which require generic MII code. # -obj-$(CONFIG_USB_AX8817X) += mii.o obj-$(CONFIG_USB_PEGASUS) += mii.o obj-$(CONFIG_USB_USBNET) += mii.o diff --git a/drivers/usb/net/ax8817x.c b/drivers/usb/net/ax8817x.c deleted file mode 100644 index e73ba35f691c..000000000000 --- a/drivers/usb/net/ax8817x.c +++ /dev/null @@ -1,1340 +0,0 @@ -/* - * ASIX AX8817x USB 2.0 10/100/HomePNA Ethernet controller driver - * - * $Id: ax8817x.c,v 1.18 2003/07/24 11:08:17 dhollis Exp $ - * - * Copyright (c) 2002-2003 TiVo Inc. - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * History - * - * 2003-07-24 - Dave Hollis <dhollis@davehollis.com> 2.0.2 - * * Minor fix that greatly increases rx performance - - * 2003-07-22 - Dave Hollis <dhollis@davehollis.com> 2.0.1 - * * Add Intellinet USB ids - * * Fix mii/ethtool support - link check works! - * * Add msglevel support - * * Shamelessly 'borrowed' devdbg/err/info macros from usbnet - * * Change strlcpy to strncpy - * 2003-06-15 - Dave Hollis <dhollis@davehollis.com> 2.0.0 - * * Remove crc32 inline function, use core kernel instead - * * Set sane defaults for rx_buffers - * * Fix ethtool GETDRVINFO bits - use strlcpy and - * usb_make_path - * - * 2003-06-05 - Dave Hollis <dhollis@davehollis.com> 0.10.0 - * * Port to 2.5 series kernels - * * Remove #if 0 blocks that are confirmed - * unnecessary - * * Re-did tx routines based off pegasus driver. - * This resolved hard crashes and greatly simplified - * things. - * * Redo mii/ethtool routines - * - * 2003-05-31 - Dave Hollis <dhollis@davehollis.com> 0.9.8 - * * Don't stop/start the queue in start_xmit - * * Swallow URB status upon hard removal - * * Cleanup remaining comments (kill // style) - * - * 2003-05-29 - Dave Hollis <dhollis@davehollis.com> 0.9.7 - * * Set module owner - * * Follow-up on suggestions from David Brownell & - * Oliver Neukum which should help with robustness - * * Use ether_crc from stock kernel if available - * - * 2003-05-28 - Dave Hollis <dhollis@davehollis.com> 0.9.6 - * * Added basic ethtool & mii support - * - * 2003-05-28 - Dave Hollis <dhollis@davehollis.com> 0.9.5 - * * Workout devrequest change to usb_ctrlrequest structure - * * Replace FILL_BULK_URB macros to non-deprecated - * usb_fill_bulk_urb macros - * * Replace printks with equivalent macros - * * Use defines for module description, version, author to - * simplify future changes - * - * Known Issues - * - * Todo - * Fix receive performance on OHCI -*/ - -#include <linux/slab.h> - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/usb.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/skbuff.h> -#include <linux/mii.h> -#include <linux/crc32.h> -#include <asm/uaccess.h> - -/* Version Information */ -#define DRIVER_VERSION "v2.0.2" -#define DRIVER_AUTHOR "TiVo, Inc." -#define DRIVER_DESC "ASIX AX8817x USB Ethernet driver" -#define DRIVER_NAME "ax8817x" - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_LICENSE("GPL"); - -#define AX_REQ_READ ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE ) -#define AX_REQ_WRITE ( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ) - -#define AX_CMD_SET_SW_MII 0x06 -#define AX_CMD_READ_MII_REG 0x07 -#define AX_CMD_WRITE_MII_REG 0x08 -#define AX_CMD_SET_HW_MII 0x0a -#define AX_CMD_WRITE_RX_CTL 0x10 -#define AX_CMD_WRITE_MULTI_FILTER 0x16 -#define AX_CMD_READ_NODE_ID 0x17 -#define AX_CMD_READ_PHY_ID 0x19 -#define AX_CMD_WRITE_MEDIUM_MODE 0x1b -#define AX_CMD_WRITE_GPIOS 0x1f - -#define AX_RX_MAX ETH_FRAME_LEN -#define AX_TIMEOUT_CMD ( HZ / 10 ) -#define AX_TIMEOUT_TX ( HZ * 2 ) -#define AX_MCAST_FILTER_SIZE 8 -#define AX_MAX_MCAST 64 - -#define AX_DRV_STATE_INITIALIZING 0x00 -#define AX_DRV_STATE_RUNNING 0x01 -#define AX_DRV_STATE_EXITING 0x02 - -#define AX_PHY_STATE_INITIALIZING 0x00 -#define AX_PHY_STATE_NO_LINK 0x01 -#define AX_PHY_STATE_POLLING_1 0x02 -#define AX_PHY_STATE_POLLING_2 0x03 -#define AX_PHY_STATE_POLLING_3 0x04 -#define AX_PHY_STATE_POLLING_4 0x05 -#define AX_PHY_STATE_SETTING_MAC 0x06 -#define AX_PHY_STATE_LINK 0x07 -#define AX_PHY_STATE_ABORT_POLL 0x08 -#define AX_PHY_STATE_ABORTING 0x09 - -#define AX_MAX_PHY_RETRY 50 - -#define AX_RX_URBS_DEFAULT 2 - -static int n_rx_urbs = AX_RX_URBS_DEFAULT; - -MODULE_PARM(n_rx_urbs, "i"); -MODULE_PARM_DESC(n_rx_urbs, - "Number of rx buffers to queue at once (def 2)"); - -struct ax8817x_info; -struct ax_cmd_req; -typedef int (*ax_cmd_callback_t) (struct ax8817x_info *, - struct ax_cmd_req *); - -struct ax_cmd_req { - struct list_head list; - ax_cmd_callback_t cmd_callback; - void *priv; - int status; - void *data; - int data_size; - int timeout; - struct usb_ctrlrequest devreq; -}; - -struct ax8817x_info { - struct usb_device *usb; - struct net_device *net; - struct net_device_stats stats; - struct mii_if_info mii; - struct urb **rx_urbs; - struct urb *int_urb; - struct urb *tx_urb; - u8 *int_buf; - struct urb *ctl_urb; - struct list_head ctl_queue; - spinlock_t ctl_lock; - atomic_t rx_refill_cnt; - struct ax_cmd_req phy_req; - u8 phy_id; - u8 phy_state; - u8 drv_state; - int msg_level; -}; - - -const struct usb_device_id ax8817x_id_table[] = { - /* Linksys USB200M */ - {USB_DEVICE(0x077b, 0x2226), driver_info:0x00130103}, - /* Hawking UF200, TRENDnet TU2-ET100 */ - {USB_DEVICE(0x07b8, 0x420a), driver_info:0x001f1d1f}, - /* NETGEAR FA120 */ - {USB_DEVICE(0x0846, 0x1040), driver_info:0x00130103}, - /* D-Link DUB-E100 */ - {USB_DEVICE(0x2001, 0x1a00), driver_info:0x009f9d9f}, - /* Intellinet USB Ethernet */ - {USB_DEVICE(0x0b95, 0x1720), driver_info:0x00130103}, - {} -}; - -MODULE_DEVICE_TABLE(usb, ax8817x_id_table); - -/* The space before the ", ## arg" is deliberate: gcc-2.9x needs it */ - -#ifdef DEBUG -#define devdbg(ax_info, fmt, arg...) \ - printk(KERN_DEBUG "%s: " fmt "\n" , (ax_info)->net->name , ## arg) -#else -#define devdbg(ax_info, fmt, arg...) do {} while(0) -#endif - -#define deverr(ax_info, fmt, arg...) \ - printk(KERN_ERR "%s: " fmt "\n", (ax_info)->net->name , ## arg) - -#define devinfo(ax_info, fmt, arg...) \ - do { if ((ax_info)->msg_level >= 1) \ - printk(KERN_INFO "%s: " fmt "\n", \ - (ax_info)->net->name , ## arg); \ - } while (0) - -static void ax_run_ctl_queue(struct ax8817x_info *, struct ax_cmd_req *, - int); -static void ax_rx_callback(struct urb *, struct pt_regs *); - -static void ax_ctl_callback(struct urb *urb, struct pt_regs *regs) -{ - struct ax8817x_info *ax_info = - (struct ax8817x_info *) urb->context; - - ax_run_ctl_queue(ax_info, NULL, - urb->status ? urb->status : urb->actual_length); -} - -/* - * Queue a new ctl request, or dequeue the first in the list -*/ -static void ax_run_ctl_queue(struct ax8817x_info *ax_info, - struct ax_cmd_req *req, int status) -{ - struct ax_cmd_req *next_req = NULL; - struct ax_cmd_req *last_req = NULL; - unsigned long flags; - - /* Need to lock around queue list manipulation */ - spin_lock_irqsave(&ax_info->ctl_lock, flags); - - if (req == NULL) { - last_req = - list_entry(ax_info->ctl_queue.next, struct ax_cmd_req, - list); - } else { - if (list_empty(&ax_info->ctl_queue)) { - next_req = req; - } - - req->status = -EINPROGRESS; - list_add_tail(&req->list, &ax_info->ctl_queue); - } - - while (1) { - if (last_req != NULL) { - /* dequeue completed entry */ - list_del(&last_req->list); - - last_req->status = status; - if (last_req->cmd_callback(ax_info, last_req)) { - /* requeue if told to do so */ - last_req->status = -EINPROGRESS; - list_add_tail(&last_req->list, - &ax_info->ctl_queue); - } - - if (list_empty(&ax_info->ctl_queue)) { - next_req = NULL; - } else { - next_req = - list_entry(ax_info->ctl_queue.next, - struct ax_cmd_req, list); - } - } - - spin_unlock_irqrestore(&ax_info->ctl_lock, flags); - - if (next_req == NULL) { - break; - } - - /* XXX: do something with timeout */ - usb_fill_control_urb(ax_info->ctl_urb, ax_info->usb, - next_req->devreq. - bRequestType & USB_DIR_IN ? - usb_rcvctrlpipe(ax_info->usb, - 0) : - usb_sndctrlpipe(ax_info->usb, 0), - (void *) &next_req->devreq, - next_req->data, next_req->data_size, - ax_ctl_callback, ax_info); - - status = usb_submit_urb(ax_info->ctl_urb, GFP_ATOMIC); - if (status >= 0) { - break; - } - - last_req = next_req; - - spin_lock_irqsave(&ax_info->ctl_lock, flags); - } -} - -static int ax_sync_cmd_callback(struct ax8817x_info *unused, - struct ax_cmd_req *req) -{ - wait_queue_head_t *wq = (wait_queue_head_t *) req->priv; - - wake_up(wq); - - return 0; -} - -static int ax_async_cmd_callback(struct ax8817x_info *unused, - struct ax_cmd_req *req) -{ - if (req->status < 0) { - err("%s: Async command %d failed: %d\n", __FUNCTION__, - req->devreq.bRequest, req->status); - } - - /* Nothing else to do here, just need to free the request (and its - allocated data) */ - if (req->data != NULL) { - kfree(req->data); - } - kfree(req); - - return 0; -} - -/* - * This is mostly the same as usb_control_msg(), except that it is able - * to queue control messages -*/ -static int ax_control_msg(struct ax8817x_info *ax_info, u8 requesttype, - u8 request, u16 value, u16 index, void *data, - u16 size, int timeout) -{ - struct ax_cmd_req *req; - DECLARE_WAIT_QUEUE_HEAD(wq); - DECLARE_WAITQUEUE(wait, current); - int ret; - - req = kmalloc(sizeof(struct ax_cmd_req), GFP_KERNEL); - if (req == NULL) { - return -ENOMEM; - } - - req->devreq.bRequestType = requesttype; - req->devreq.bRequest = request; - req->devreq.wValue = cpu_to_le16(value); - req->devreq.wIndex = cpu_to_le16(index); - req->devreq.wLength = cpu_to_le16(size); - req->data = data; - req->data_size = size; - req->timeout = timeout; - - req->priv = &wq; - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&wq, &wait); - - req->cmd_callback = ax_sync_cmd_callback; - - ax_run_ctl_queue(ax_info, req, 0); - schedule(); - - ret = req->status; - - kfree(req); - - return ret; -} - -/* - * Same, but can be used asynchronously, may fail, and returns no exit - * status -*/ -static void ax_control_msg_async(struct ax8817x_info *ax_info, - u8 requesttype, u8 request, u16 value, - u16 index, void *data, u16 size, - int timeout) -{ - struct ax_cmd_req *req; - - req = kmalloc(sizeof(struct ax_cmd_req), GFP_ATOMIC); - if (req == NULL) { - /* There's not much else we can do here... */ - err("%s: Failed alloc\n", __FUNCTION__); - return; - } - - req->devreq.bRequestType = requesttype; - req->devreq.bRequest = request; - req->devreq.wValue = cpu_to_le16(value); - req->devreq.wIndex = cpu_to_le16(index); - req->devreq.wLength = cpu_to_le16(size); - req->data = data; - req->data_size = size; - req->timeout = timeout; - - req->cmd_callback = ax_async_cmd_callback; - - ax_run_ctl_queue(ax_info, req, 0); -} - -static inline int ax_read_cmd(struct ax8817x_info *ax_info, u8 cmd, - u16 value, u16 index, u16 size, void *data) -{ - return ax_control_msg(ax_info, AX_REQ_READ, cmd, value, index, - data, size, AX_TIMEOUT_CMD); -} - -static inline int ax_write_cmd(struct ax8817x_info *ax_info, u8 cmd, - u16 value, u16 index, u16 size, void *data) -{ - return ax_control_msg(ax_info, AX_REQ_WRITE, cmd, value, index, - data, size, AX_TIMEOUT_CMD); -} - -static inline void ax_write_cmd_async(struct ax8817x_info *ax_info, u8 cmd, - u16 value, u16 index, u16 size, - void *data) -{ - ax_control_msg_async(ax_info, AX_REQ_WRITE, cmd, value, index, - data, size, AX_TIMEOUT_CMD); -} - -static int ax_refill_rx_urb(struct ax8817x_info *ax_info, struct urb *urb) -{ - struct sk_buff *skb; - int ret; - - skb = dev_alloc_skb(AX_RX_MAX + 2); - if (skb != NULL) { - skb_reserve(skb, 2); /* for IP header alignment */ - skb->dev = ax_info->net; - - usb_fill_bulk_urb(urb, ax_info->usb, - usb_rcvbulkpipe(ax_info->usb, 3), - skb->data, AX_RX_MAX, ax_rx_callback, - skb); - - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret < 0) { - err("Failed submit rx URB (%d)\n", ret); - dev_kfree_skb_irq(skb); - urb->context = NULL; - } else { - ret = 0; - } - } else { - /* this just means we're low on memory at the moment. Try to - handle it gracefully. */ - urb->context = NULL; - ret = 1; - } - - return ret; -} - -static int ax_phy_cmd_callback(struct ax8817x_info *ax_info, - struct ax_cmd_req *req) -{ - int full_duplex; - int flow_control; - u16 mii_data_le; - - if (req->status < 0) { - err("%s: Failed at state %d: %d\n", __FUNCTION__, - ax_info->phy_state, req->status); - /* Not sure what else we can do, so just bail */ - ax_info->phy_state = AX_PHY_STATE_ABORTING; - } - - switch (ax_info->phy_state) { - /* Now that we're in software MII mode, read the BMSR */ - case AX_PHY_STATE_POLLING_1: - ax_info->phy_state = AX_PHY_STATE_POLLING_2; - req->devreq.bRequestType = AX_REQ_READ; - req->devreq.bRequest = AX_CMD_READ_MII_REG; - req->devreq.wValue = cpu_to_le16(ax_info->phy_id); - req->devreq.wIndex = cpu_to_le16(MII_BMSR); - req->devreq.wLength = cpu_to_le16(2); - req->data_size = 2; - req->priv = 0; /* This is the retry count */ - return 1; - - /* Done reading BMSR */ - case AX_PHY_STATE_POLLING_2: - mii_data_le = *(u16 *) req->data; - if ((mii_data_le & - cpu_to_le16(BMSR_LSTATUS | BMSR_ANEGCAPABLE)) - == cpu_to_le16(BMSR_LSTATUS | BMSR_ANEGCAPABLE)) { - if (mii_data_le & cpu_to_le16(BMSR_ANEGCOMPLETE)) { - /* Autonegotiation done, go on to read LPA */ - ax_info->phy_state = - AX_PHY_STATE_POLLING_3; - req->devreq.wIndex = cpu_to_le16(MII_LPA); - return 1; - } else if ((long) req->priv++ < AX_MAX_PHY_RETRY) { - /* Reread BMSR if it's still autonegotiating. This is - probably unnecessary logic, I've never seen it take - more than 1 try... */ - return 1; - } - /* else fall through to abort */ - } - /* XXX: should probably handle auto-neg failure better, - by reverting to manual setting of something safe. (?) */ - - ax_info->phy_state = AX_PHY_STATE_ABORT_POLL; - /* and then fall through to set hw MII */ - - /* Got what we needed from PHY, set back to hardware MII mode - (Do same for abort in mid-poll) */ - case AX_PHY_STATE_POLLING_3: - case AX_PHY_STATE_ABORT_POLL: - ax_info->phy_state += 1; - req->devreq.bRequestType = AX_REQ_WRITE; - req->devreq.bRequest = AX_CMD_SET_HW_MII; - req->devreq.wValue = cpu_to_le16(0); - req->devreq.wIndex = cpu_to_le16(0); - req->devreq.wLength = cpu_to_le16(0); - req->data_size = 0; - return 1; - - /* The end result, set the right duplex and flow control mode in the - MAC (based on the PHY's LPA reg, which should still be in the data - buffer) */ - case AX_PHY_STATE_POLLING_4: - mii_data_le = *(u16 *) req->data; - ax_info->phy_state = AX_PHY_STATE_SETTING_MAC; - req->devreq.bRequest = AX_CMD_WRITE_MEDIUM_MODE; - full_duplex = mii_data_le & cpu_to_le16(LPA_DUPLEX); - flow_control = full_duplex && - (mii_data_le & cpu_to_le16(0x0400)); - req->devreq.wValue = cpu_to_le16(0x04) | - (full_duplex ? cpu_to_le16(0x02) : 0) | - (flow_control ? cpu_to_le16(0x10) : 0); - info("%s: Link established, %s duplex, flow control %sabled\n", ax_info->net->name, full_duplex ? "full" : "half", flow_control ? "en" : "dis"); - return 1; - - /* All done */ - case AX_PHY_STATE_SETTING_MAC: - ax_info->phy_state = AX_PHY_STATE_LINK; - netif_carrier_on(ax_info->net); - return 0; - - default: - err("%s: Unknown state %d\n", __FUNCTION__, - ax_info->phy_state); - /* fall through */ - case AX_PHY_STATE_ABORTING: - ax_info->phy_state = AX_PHY_STATE_NO_LINK; - return 0; - } -} - -static void ax_int_callback(struct urb *urb, struct pt_regs *regs) -{ - struct ax8817x_info *ax_info = - (struct ax8817x_info *) urb->context; - u8 phy_link; - - if (ax_info->drv_state == AX_DRV_STATE_EXITING || - urb->actual_length < 3) { - return; - } - - /* Ignore the first PHY link report, it will sometimes be reported as - link active, even though we just told the PHY to reset. If it - really has link, we'll pick it up next int callback. - */ - if (ax_info->phy_state == AX_PHY_STATE_INITIALIZING) { - netif_carrier_off(ax_info->net); - ax_info->phy_state = AX_PHY_STATE_NO_LINK; - return; - } - - /* Assume we're only interested in the primary PHY for now. */ - phy_link = ax_info->int_buf[2] & 1; - - if (phy_link == - (ax_info->phy_state == AX_PHY_STATE_NO_LINK) ? 0 : 1) { - /* Common case, no change */ - return; - } - - if (phy_link == 0) { - netif_carrier_off(ax_info->net); - /* Abort an in-progress poll of the PHY if necessary */ - switch (ax_info->phy_state) { - case AX_PHY_STATE_POLLING_1: - case AX_PHY_STATE_POLLING_2: - case AX_PHY_STATE_POLLING_3: - ax_info->phy_state = AX_PHY_STATE_ABORT_POLL; - break; - - case AX_PHY_STATE_POLLING_4: - case AX_PHY_STATE_SETTING_MAC: - ax_info->phy_state = AX_PHY_STATE_ABORTING; - break; - - case AX_PHY_STATE_LINK: - ax_info->phy_state = AX_PHY_STATE_NO_LINK; - break; - - default: - /* If we're already aborting, continue aborting */ - break; - } - } else { - /* Note that we only fall into this case if previous phy_state was - AX_PHY_STATE_NO_LINK. When the link is reported active while - we're still polling, or when we're aborting, the logic above - will just return, and we'll check again next int callback. */ - - ax_info->phy_state = AX_PHY_STATE_POLLING_1; - ax_info->phy_req.devreq.bRequestType = AX_REQ_WRITE; - ax_info->phy_req.devreq.bRequest = AX_CMD_SET_SW_MII; - ax_info->phy_req.devreq.wValue = cpu_to_le16(0); - ax_info->phy_req.devreq.wIndex = cpu_to_le16(0); - ax_info->phy_req.devreq.wLength = cpu_to_le16(0); - ax_info->phy_req.data_size = 0; - ax_info->phy_req.timeout = AX_TIMEOUT_CMD; - ax_info->phy_req.cmd_callback = ax_phy_cmd_callback; - - ax_run_ctl_queue(ax_info, &ax_info->phy_req, 0); - } -} - -static void ax_rx_callback(struct urb *urb, struct pt_regs *regs) -{ - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct net_device *net = skb->dev; - struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; - int ret, len, refill; - - switch (urb->status) { - case 0: - break; - - default: - err("%s: URB status %d\n", __FUNCTION__, urb->status); - /* It's not clear that we can do much in this case, the rx pipe - doesn't ever seem to stall, so if we got -ETIMEDOUT, that - usually means the device was unplugged, and we just haven't - noticed yet. - Just fall through and free skb without resubmitting urb. */ - case -ENOENT: /* */ - case -ECONNRESET: /* Async unlink */ - case -ESHUTDOWN: /* Hardware gone */ - case -EILSEQ: /* Get this when you yank it out on UHCI */ - case -ETIMEDOUT: /* OHCI */ - case -EPROTO: /* EHCI */ - case -EPIPE: - dev_kfree_skb_any(skb); - urb->context = NULL; - return; - } - - if (ax_info->drv_state == AX_DRV_STATE_INITIALIZING) { - /* Not really expecting this to ever happen, since we haven't yet - enabled receive in the rx_ctl register, but ya never know... */ - goto refill_same; - } else if (ax_info->drv_state == AX_DRV_STATE_EXITING) { - dev_kfree_skb_any(skb); - urb->context = NULL; - return; - } - - len = urb->actual_length; - if (len == 0) { - /* this shouldn't happen... */ - goto refill_same; - } - - refill = ax_refill_rx_urb(ax_info, urb); - - if (refill == 0 - || atomic_read(&ax_info->rx_refill_cnt) < n_rx_urbs) { - /* Send the receive buffer up the network stack */ - skb_put(skb, len); - skb->protocol = eth_type_trans(skb, net); - net->last_rx = jiffies; - ax_info->stats.rx_packets++; - ax_info->stats.rx_bytes += len; - - netif_rx(skb); - - if (refill == 0) { - int i; - - /* This is the common case. This URB got refilled OK, and - no other URBs need to be refilled. */ - if (atomic_read(&ax_info->rx_refill_cnt) == 0) { - return; - } - - for (i = 0; i < n_rx_urbs; i++) { - struct urb *urb = ax_info->rx_urbs[i]; - - if (urb->context == NULL) { - if (ax_refill_rx_urb(ax_info, urb) - == 0) { - atomic_dec(&ax_info-> - rx_refill_cnt); - } else { - break; - } - } - } - } else { - /* remember to refill this one later */ - atomic_inc(&ax_info->rx_refill_cnt); - } - - return; - } else { - ax_info->stats.rx_dropped++; - if (refill < 0) { - /* the error code was already printk'ed in ax_refill_rx_urb() - so just note the consequences here: */ - warn("Halting rx due to error\n"); - return; - } - - /* fall through to resubmit this URB with the existing skb - will try to reallocate skb's on next rx callback */ - } - -refill_same: - usb_fill_bulk_urb(urb, ax_info->usb, - usb_rcvbulkpipe(ax_info->usb, 3), skb->data, - AX_RX_MAX, ax_rx_callback, skb); - - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret < 0) { - err("Failed submit rx URB (%d)\n", ret); - } -} - -static int ax8817x_open(struct net_device *net) -{ - struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; - u8 buf[4]; - int i, ret; - - ret = ax_write_cmd(ax_info, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf); - if (ret < 0) { - return ret; - } - - ret = 0; - - ax_info->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ax_info->tx_urb == NULL) { - err("Error allocating tx_urb!"); - ret = -ENOMEM; - } - - atomic_set(&ax_info->rx_refill_cnt, 0); - - for (i = 0; i < n_rx_urbs && ret == 0; i++) { - struct urb *urb = ax_info->rx_urbs[i]; - - if (urb == NULL) { - urb = ax_info->rx_urbs[i] = - usb_alloc_urb(0, GFP_KERNEL); - if (urb == NULL) { - ret = -ENOMEM; - break; - } - if (n_rx_urbs > 1) { - urb->transfer_flags |= URB_ZERO_PACKET; - } - } - ret = ax_refill_rx_urb(ax_info, urb); - if (ret == 1) { - atomic_inc(&ax_info->rx_refill_cnt); - ret = 0; - } - } - - /* XXX: should handle the case where we couldn't allocate any skb's - better. They get allocated with GFP_ATOMIC, so they may all fail... */ - if (ret == 0 && atomic_read(&ax_info->rx_refill_cnt) < n_rx_urbs) { - netif_start_queue(net); - } else { - /* Error: clean up anything we allocated and bail. */ - usb_free_urb(ax_info->tx_urb); - - for (i = 0; i < n_rx_urbs; i++) { - struct urb *urb = ax_info->rx_urbs[i]; - - if (urb != NULL) { - /* skb gets freed in the URB callback */ - usb_unlink_urb(urb); - usb_free_urb(urb); - } - } - - err("%s: Failed start rx queue (%d)\n", __FUNCTION__, ret); - } - return ret; -} - -static int ax8817x_stop(struct net_device *net) -{ - struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; - u8 buf[4]; - int i, ret; - - netif_stop_queue(net); - - ret = ax_write_cmd(ax_info, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf); - if (ret < 0 && ax_info->drv_state != AX_DRV_STATE_EXITING) { - err("%s: Failed cmd (%d)\n", __FUNCTION__, ret); - } - if (ax_info->tx_urb != NULL) { - usb_unlink_urb(ax_info->tx_urb); - usb_free_urb(ax_info->tx_urb); - ax_info->tx_urb = NULL; - } - - for (i = 0; i < n_rx_urbs; i++) { - struct urb *urb = ax_info->rx_urbs[i]; - if (urb != NULL) { - /* skb gets freed in the URB callback */ - usb_unlink_urb(urb); - usb_free_urb(urb); - ax_info->rx_urbs[i] = NULL; - } - } - - return 0; -} - -static void write_bulk_callback(struct urb *urb, struct pt_regs *regs) -{ - struct ax8817x_info *ax_info = urb->context; - - if (!ax_info || (ax_info->drv_state == AX_DRV_STATE_EXITING)) - return; - - if (!netif_device_present(ax_info->net)) - return; - - if (urb->status) - info("%s: TX status %d", ax_info->net->name, urb->status); - - ax_info->net->trans_start = jiffies; - netif_wake_queue(ax_info->net); -} - -static int ax8817x_start_xmit(struct sk_buff *skb, struct net_device *net) -{ - struct ax8817x_info *ax_info = net->priv; - int res; - - netif_stop_queue(net); - - ax_info->tx_urb->transfer_flags |= URB_ZERO_PACKET; - usb_fill_bulk_urb(ax_info->tx_urb, ax_info->usb, - usb_sndbulkpipe(ax_info->usb, 2), - skb->data, skb->len, write_bulk_callback, - ax_info); - if ((res = usb_submit_urb(ax_info->tx_urb, GFP_ATOMIC))) { - warn("Failed tx_urb %d", res); - ax_info->stats.tx_errors++; - netif_start_queue(net); - } else { - ax_info->stats.tx_packets++; - ax_info->stats.tx_bytes += skb->len; - net->trans_start = jiffies; - } - dev_kfree_skb(skb); - - return 0; -} - -static void ax8817x_tx_timeout(struct net_device *net) -{ - struct ax8817x_info *ax_info = net->priv; - - if (!ax_info) - return; - - warn("%s: Tx timed out.", net->name); - ax_info->tx_urb->transfer_flags |= URB_ASYNC_UNLINK; - usb_unlink_urb(ax_info->tx_urb); - ax_info->stats.tx_errors++; -} - -static struct net_device_stats *ax8817x_stats(struct net_device *net) -{ - struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; - - return &ax_info->stats; -} - -static void ax8817x_set_multicast(struct net_device *net) -{ - struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; - u8 rx_ctl = 0x8c; - - if (net->flags & IFF_PROMISC) { - rx_ctl |= 0x01; - } else if (net->flags & IFF_ALLMULTI - || net->mc_count > AX_MAX_MCAST) { - rx_ctl |= 0x02; - } else if (net->mc_count == 0) { - /* just broadcast and directed */ - } else { - struct dev_mc_list *mc_list = net->mc_list; - u8 *multi_filter; - u32 crc_bits; - int i; - - multi_filter = kmalloc(AX_MCAST_FILTER_SIZE, GFP_ATOMIC); - if (multi_filter == NULL) { - /* Oops, couldn't allocate a DMA buffer for setting the multicast - filter. Try all multi mode, although the ax_write_cmd_async - will almost certainly fail, too... (but it will printk). */ - rx_ctl |= 0x02; - } else { - memset(multi_filter, 0, AX_MCAST_FILTER_SIZE); - - /* Build the multicast hash filter. */ - for (i = 0; i < net->mc_count; i++) { - crc_bits = - ether_crc(ETH_ALEN, - mc_list->dmi_addr) >> 26; - multi_filter[crc_bits >> 3] |= - 1 << (crc_bits & 7); - mc_list = mc_list->next; - } - - ax_write_cmd_async(ax_info, - AX_CMD_WRITE_MULTI_FILTER, 0, 0, - AX_MCAST_FILTER_SIZE, multi_filter); - - rx_ctl |= 0x10; - } - } - - ax_write_cmd_async(ax_info, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, - NULL); -} - -static int read_mii_word(struct ax8817x_info *ax_info, __u8 phy, __u8 indx, - __u16 * regd) -{ - int ret; - u8 buf[4]; - - devdbg(ax_info,"read_mii_word: phy=%02x, indx=%02x, regd=%04x", phy, indx, *regd); - - ax_write_cmd(ax_info, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); - - ret = ax_read_cmd(ax_info, AX_CMD_READ_MII_REG, ax_info->phy_id, (__u16)indx, 2, regd); - devdbg(ax_info,"read_mii_word: AX_CMD_READ_MII_REG ret=%02x, regd=%04x", ret, *regd); - - ax_write_cmd(ax_info, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); - - return ret; -} - -static int write_mii_word(struct ax8817x_info *ax_info, __u8 phy, - __u8 indx, __u16 regd) -{ - deverr(ax_info, "write_mii_word - not implemented!"); - return 0; -} - -static int mdio_read(struct net_device *dev, int phy_id, int loc) -{ - struct ax8817x_info *ax_info = dev->priv; - int res; - - devdbg(ax_info, "mdio_read: phy_id=%02x, loc=%02x", phy_id, loc); - - read_mii_word(ax_info, phy_id, loc, (u16 *) & res); - return res & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int loc, - int val) -{ - struct ax8817x_info *ax_info = dev->priv; - - devdbg(ax_info, "mdio_write: phy_id=%02x, loc=%02x", phy_id, loc); - write_mii_word(ax_info, phy_id, loc, val); -} - -static int ax8817x_ethtool_ioctl(struct net_device *net, void __user *uaddr) -{ - struct ax8817x_info *ax_info; - int cmd; - - ax_info = net->priv; - if (get_user(cmd, (int *) uaddr)) - return -EFAULT; - - switch (cmd) { - case ETHTOOL_GDRVINFO:{ - struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; - - strncpy(info.driver, DRIVER_NAME, - sizeof(info.driver) - 1); - strncpy(info.version, DRIVER_VERSION, - sizeof(info.version) - 1); - usb_make_path(ax_info->usb, info.bus_info,sizeof info.bus_info); - if (copy_to_user(uaddr, &info, sizeof(info))) - return -EFAULT; - return 0; - } - case ETHTOOL_GSET:{ - struct ethtool_cmd ecmd; - - mii_ethtool_gset(&ax_info->mii, &ecmd); - if (copy_to_user(uaddr, &ecmd, sizeof(ecmd))) - return -EFAULT; - return 0; - } - case ETHTOOL_SSET:{ - int r; - struct ethtool_cmd ecmd; - - if (copy_from_user(&ecmd, uaddr, sizeof(ecmd))) - return -EFAULT; - r = mii_ethtool_sset(&ax_info->mii, &ecmd); - return r; - } - case ETHTOOL_NWAY_RST:{ - return mii_nway_restart(&ax_info->mii); - } - case ETHTOOL_GLINK:{ - struct ethtool_value edata = { ETHTOOL_GLINK }; - - edata.data = mii_link_ok(&ax_info->mii); - if (copy_to_user(uaddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - case ETHTOOL_GMSGLVL:{ - struct ethtool_value edata = { ETHTOOL_GMSGLVL }; - edata.data = ax_info->msg_level; - if (copy_to_user(uaddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - case ETHTOOL_SMSGLVL:{ - struct ethtool_value edata; - - if (copy_from_user(&edata, uaddr, sizeof(edata))) - return -EFAULT; - ax_info->msg_level = edata.data; - return 0; - } - } - return -EOPNOTSUPP; -} - -static int ax8817x_ioctl(struct net_device *net, struct ifreq *ifr, - int cmd) -{ - struct ax8817x_info *ax_info; - - ax_info = net->priv; - - if (cmd == SIOCETHTOOL) - return ax8817x_ethtool_ioctl(net, (void __user *) ifr->ifr_data); - - return generic_mii_ioctl(&ax_info->mii, (struct mii_ioctl_data *) &ifr->ifr_data, cmd, NULL); -} - -static int ax8817x_net_init(struct net_device *net) -{ - struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; - u8 buf[6]; - u16 *buf16 = (u16 *) buf; - int ret; - - ret = ax_write_cmd(ax_info, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf); - if (ret < 0) { - return ret; - } - - memset(buf, 0, 6); - - /* Get the MAC address */ - ret = ax_read_cmd(ax_info, AX_CMD_READ_NODE_ID, 0, 0, 6, buf); - if (ret < 0) { - return ret; - } - - memcpy(net->dev_addr, buf, 6); - - /* Get the PHY id */ - ret = ax_read_cmd(ax_info, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); - if (ret < 0) { - return ret; - } else if (ret < 2) { - /* this should always return 2 bytes */ - return -EIO; - } - - /* Reset the PHY, and drop it into auto-negotiation mode */ - ax_info->phy_id = buf[1]; - ax_info->phy_state = AX_PHY_STATE_INITIALIZING; - - ret = ax_write_cmd(ax_info, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); - if (ret < 0) { - return ret; - } - - *buf16 = cpu_to_le16(BMCR_RESET); - ret = ax_write_cmd(ax_info, AX_CMD_WRITE_MII_REG, - ax_info->phy_id, MII_BMCR, 2, buf16); - if (ret < 0) { - return ret; - } - - /* Advertise that we can do full-duplex pause */ - *buf16 = cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400); - ret = ax_write_cmd(ax_info, AX_CMD_WRITE_MII_REG, - ax_info->phy_id, MII_ADVERTISE, 2, buf16); - if (ret < 0) { - return ret; - } - - *buf16 = cpu_to_le16(BMCR_ANENABLE | BMCR_ANRESTART); - ret = ax_write_cmd(ax_info, AX_CMD_WRITE_MII_REG, - ax_info->phy_id, MII_BMCR, 2, buf16); - if (ret < 0) { - return ret; - } - - ret = ax_write_cmd(ax_info, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); - if (ret < 0) { - return ret; - } - - net->open = ax8817x_open; - net->stop = ax8817x_stop; - net->hard_start_xmit = ax8817x_start_xmit; - net->tx_timeout = ax8817x_tx_timeout; - net->watchdog_timeo = AX_TIMEOUT_TX; - net->get_stats = ax8817x_stats; - net->do_ioctl = ax8817x_ioctl; - net->set_multicast_list = ax8817x_set_multicast; - - return 0; -} - -static int ax8817x_bind(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *usb = interface_to_usbdev(intf); - struct ax8817x_info *ax_info; - struct net_device *net; - int i, ret; - unsigned long gpio_bits = id->driver_info; - u8 buf[2]; - - /* Allocate the URB lists along with the device info struct */ - ax_info = kmalloc(sizeof(struct ax8817x_info) + - n_rx_urbs * sizeof(struct urb *), GFP_KERNEL); - if (ax_info == NULL) { - err("%s: Failed ax alloc\n", __FUNCTION__); - goto exit_err; - } - - memset(ax_info, 0, sizeof(struct ax8817x_info) + - n_rx_urbs * sizeof(struct urb *)); - - ax_info->drv_state = AX_DRV_STATE_INITIALIZING; - ax_info->rx_urbs = (struct urb **) (ax_info + 1); - ax_info->usb = usb; - - /* Set up the control URB queue */ - - INIT_LIST_HEAD(&ax_info->ctl_queue); - spin_lock_init(&ax_info->ctl_lock); - ax_info->ctl_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ax_info->ctl_urb == NULL) { - goto exit_err_free_ax; - } - - /* Toggle the GPIOs in a manufacturer/model specific way */ - - for (i = 2; i >= 0; i--) { - ret = ax_write_cmd(ax_info, AX_CMD_WRITE_GPIOS, - (gpio_bits >> (i * 8)) & 0xff, 0, 0, - buf); - if (ret < 0) { - goto exit_err_free_ax; - } - wait_ms(5); - } - - /* Set up the net device */ - - net = alloc_etherdev(0); - if (net == NULL) { - err("%s: Failed net alloc\n", __FUNCTION__); - goto exit_err_free_ax; - } - - ax_info->net = net; - - SET_MODULE_OWNER(net); - net->init = ax8817x_net_init; - net->priv = ax_info; - - SET_NETDEV_DEV(net, &intf->dev); - ret = register_netdev(net); - if (ret < 0) { - err("%s: Failed net init (%d)\n", __FUNCTION__, ret); - goto exit_err_free_net; - } - - /* Setup mii structure */ - ax_info->mii.dev = net; - ax_info->mii.mdio_read = mdio_read; - ax_info->mii.mdio_write = mdio_write; - ax_info->mii.phy_id = ax_info->phy_id; - ax_info->mii.phy_id_mask = 0x3f; - ax_info->mii.reg_num_mask = 0x1f; - - /* Set up the interrupt URB, and start PHY state monitoring */ - - ax_info->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ax_info->int_urb == NULL) { - goto exit_err_unregister_net; - } - ax_info->int_buf = kmalloc(8, GFP_KERNEL); - if (ax_info->int_buf == NULL) { - goto exit_err_free_int_urb; - } - ax_info->phy_req.data = kmalloc(2, GFP_KERNEL); - if (ax_info->phy_req.data == NULL) { - goto exit_err_free_int_buf; - } - - usb_fill_int_urb(ax_info->int_urb, usb, usb_rcvintpipe(usb, 1), - ax_info->int_buf, 8, ax_int_callback, ax_info, - usb->speed == USB_SPEED_HIGH? 8: 100); - - ret = usb_submit_urb(ax_info->int_urb, GFP_ATOMIC); - if (ret < 0) { - err("%s: Failed int URB submit (%d)\n", __FUNCTION__, ret); - goto exit_err_free_phy_buf; - } - - ax_info->drv_state = AX_DRV_STATE_RUNNING; - usb_set_intfdata(intf, ax_info); - - return 0; - - exit_err_free_phy_buf: - kfree(ax_info->phy_req.data); - - exit_err_free_int_buf: - kfree(ax_info->int_buf); - - exit_err_free_int_urb: - usb_free_urb(ax_info->int_urb); - - exit_err_unregister_net: - ax_info->drv_state = AX_DRV_STATE_EXITING; - unregister_netdev(net); - - exit_err_free_net: - kfree(net); - - exit_err_free_ax: - if (ax_info->ctl_urb != NULL) { - /* no need to unlink, since there should not be any ctl URBs - pending at this point */ - usb_free_urb(ax_info->ctl_urb); - } - - kfree(ax_info); - -exit_err: - err("%s: Failed to initialize\n", __FUNCTION__); - return -EIO; -} - -static void ax8817x_disconnect(struct usb_interface *intf) -{ - struct ax8817x_info *ax_info = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - if (ax_info) { - ax_info->drv_state = AX_DRV_STATE_EXITING; - - if (ax_info->int_urb != NULL) { - usb_unlink_urb(ax_info->int_urb); - usb_free_urb(ax_info->int_urb); - kfree(ax_info->int_buf); - } - - unregister_netdev(ax_info->net); - - /* XXX: hmmm... need to go through and clear out the ctl queue, too... */ - if (ax_info->ctl_urb != NULL) { - usb_unlink_urb(ax_info->ctl_urb); - usb_free_urb(ax_info->ctl_urb); - } - - kfree(ax_info); - } -} - -static struct usb_driver ax8817x_driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - .probe = ax8817x_bind, - .disconnect = ax8817x_disconnect, - .id_table = ax8817x_id_table, -}; - -static int __init ax8817x_init(void) -{ - int ret; - - if (n_rx_urbs < 1) - n_rx_urbs = AX_RX_URBS_DEFAULT; - - ret = usb_register(&ax8817x_driver); - if (ret < 0) { - err("%s: Failed to register\n", __FUNCTION__); - } else { - info(DRIVER_DESC " " DRIVER_VERSION); - } - - return ret; -} - -static void __exit ax8817x_exit(void) -{ - usb_deregister(&ax8817x_driver); -} - -module_init(ax8817x_init); -module_exit(ax8817x_exit); diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index d9abf8afdcad..07f227d3c64d 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -594,8 +594,6 @@ static inline long cond_wait_interruptible_timeout_irqrestore( timeout = schedule_timeout(timeout); - set_current_state( TASK_RUNNING ); - remove_wait_queue( q, &wait ); return( timeout ); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ef813e60a286..95d984b0f8d1 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -17,6 +17,11 @@ * See http://ftdi-usb-sio.sourceforge.net for upto date testing info * and extra documentation * + * (21/Sep/2003) Ian Abbott + * Added VID/PID for Omnidirectional Control Technology US101 USB to + * RS-232 adapter (also rebadged as Dick Smith Electronics XH6381). + * VID/PID supplied by Donald Gordon. + * * (19/Aug/2003) Ian Abbott * Freed urb's transfer buffer in write bulk callback. * Omitted some paranoid checks in write bulk callback that don't matter. @@ -334,6 +339,7 @@ static struct usb_device_id id_table_8U232AM [] = { { 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) }, { } /* Terminating entry */ }; @@ -406,6 +412,7 @@ static struct usb_device_id id_table_FT232BM [] = { { 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) }, { } /* Terminating entry */ }; @@ -491,6 +498,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) }, { 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) }, { } /* Terminating entry */ diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index ae5e8df54a99..64ad4790fe86 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -133,6 +133,13 @@ #define IDTECH_VID 0x0ACD /* ID TECH Vendor ID */ #define IDTECH_IDT1221U_PID 0x0300 /* IDT1221U USB to RS-232 adapter */ +/* + * Definitions for Omnidirectional Control Technology, Inc. devices + */ +#define OCT_VID 0x0B39 /* OCT vendor ID */ +/* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */ +#define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */ + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index e9a4282d89c7..96747544c788 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1019,10 +1019,10 @@ int usb_serial_probe(struct usb_interface *interface, retval = type->probe (serial, id_pattern); module_put(type->owner); - if (retval < 0) { + if (retval) { dbg ("sub driver rejected device"); kfree (serial); - return -ENODEV; + return retval; } } diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 81e6c62a28ee..abbb98ce53e3 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1074,7 +1074,6 @@ static int usb_stor_reset_common(struct us_data *us, up(&us->dev_semaphore); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ*6); - set_current_state(TASK_RUNNING); down(&us->dev_semaphore); if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { US_DEBUGP("Reset interrupted by disconnect\n"); |
