Info (mostly for Gerg K-H)
Nathael Pajani <[email protected]>
| Newsgroups | gmane.linux.usb.devel |
|---|---|
| Message-ID | <[email protected]> |
I have discussed about "static ttyUSB numbers allocation depending on hardware position" with Greg K-H in the past (26.01.2007) and he asked me to send the code. Here it is at last, tested. I had no way to perform the final tests as the hardware was not available. Now it is, and I ported the patch to the last kernel (2.6.23-rc4) This code is NOT for inclusion in the kernel (not as is at least), just for info. Background: This is for a customer who has up to 64 identical USB devices connected to one single computer. The device can have many interfaces (sometimes more than 4) His needs are: * when a device is plugged in physical port NN he should be able to compute easily the YYY numbers corresponding to the ttyUSBYYY used for the interfaces. * when a device crashes (they are development devices) he should be able to "eject" the device and "insert" it again by software. * he does noes not want udev (which will not solve the problem) or sysfs parsing (which will be tricky, and depend on which PCI board is present and so on, and I'm not sure it will be OK). * he must not have to remember which device has been connected first, second, on so on. So, once again, this is just for info, this is not a feature request I want implemented in the kernel. Then, It may be possible to use a define CONFIG_STATIC_TTY_USB if you think that this could be a nice feature (for users with many USB to serial adapters for example, and who want to know which adapter is which cable, though this may be possible with udev in some cases, if the adapter are always the same physical ones (same serial number).) Have fun. ++++ Nathael Pajani. ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ [email protected] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
static_usb.patch
(text/x-patch, 22.9 KB)
diff -urN a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c 2007-08-30 20:10:37.000000000 +0100
+++ b/drivers/usb/core/hcd.c 2007-08-30 10:31:41.000000000 +0200
@@ -86,7 +86,7 @@
EXPORT_SYMBOL_GPL (usb_bus_list);
/* used when allocating bus numbers */
-#define USB_MAXBUS 64
+#define USB_MAXBUS 256 /* NATH USB 2.0 - was 64 */
struct usb_busmap {
unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))];
};
@@ -716,6 +716,38 @@
/*-------------------------------------------------------------------------*/
+/* NATH - ECRIN */
+/**
+ * Staticaly alocate USB bus number depending on PCI bus number. */
+static int find_bus_number(struct device* dev)
+{
+ unsigned int pci_bus = 0, pci_dev = 0;
+ unsigned int pci_par_func = 0, pci_func = 0;
+ int fields = 0;
+ int usb_static_busnum = 0;
+
+ fields = sscanf( dev->bus_id, "0000:%02x:%02x.%01x", &pci_bus, &pci_dev, &pci_func );
+ if( pci_dev != 0 ){
+ return 0;
+ }
+ fields = sscanf( dev->parent->bus_id, "0000:%02x:%02x.%01x", &pci_bus, &pci_dev, &pci_par_func );
+
+ usb_static_busnum = ( 0x20 | (((u8)pci_dev & 0x03) << 2) | ((u8)pci_func & 0x01) );
+ if( pci_bus != 2 ){
+ usb_static_busnum |= 0x10;
+ }
+ if( !((u8)pci_dev & 0x01) ){
+ usb_static_busnum |= (( (~((u8)pci_par_func)) & 0x01) << 1);
+ } else {
+ usb_static_busnum |= (( (u8)pci_par_func & 0x01) << 1);
+ }
+ /* Modification for USB 2.0 busses on function 2 */
+ if( ((u8)pci_func & 0x02) ){
+ usb_static_busnum |= 0x40;
+ }
+ return usb_static_busnum;
+}
+
/**
* usb_register_bus - registers the USB host controller with the usb core
* @bus: pointer to the bus to register
@@ -729,18 +761,34 @@
int busnum;
mutex_lock(&usb_bus_list_lock);
- busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
- if (busnum < USB_MAXBUS) {
- set_bit (busnum, busmap.busmap);
- bus->busnum = busnum;
- } else {
- printk (KERN_ERR "%s: too many buses\n", usbcore_name);
+ if( (busnum = find_bus_number(bus->controller)) < 0 ){
mutex_unlock(&usb_bus_list_lock);
- return -E2BIG;
+ return -ENODEV;
+ }
+ if( busnum == 0 ){
+ busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
+ if( busnum >= 32 ){
+ printk( KERN_ERR "USB dynamic bus allocation error: reached static range (32 - 64) : %d.\n", busnum );
+ mutex_unlock(&usb_bus_list_lock);
+ return -E2BIG;
+ }
+ } else {
+ if( (busnum < 32) || (busnum >= USB_MAXBUS) ){
+ printk( KERN_ERR "USB static bus allocation error: busnum out of static range [32 - 64] : %d.\n", busnum );
+ mutex_unlock(&usb_bus_list_lock);
+ return -E2BIG;
+ }
+ if( test_bit(busnum, busmap.busmap) ){
+ printk( KERN_ERR "USB static bus allocation error: bus already present !!!! \n" );
+ mutex_unlock(&usb_bus_list_lock);
+ return -EINVAL;
+ }
}
- bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
- bus->controller, "usb_host%d", busnum);
+ set_bit( busnum, busmap.busmap );
+ bus->busnum = busnum;
+
+ bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), bus->controller, "usb_host%d", busnum);
if (IS_ERR(bus->class_dev)) {
clear_bit(busnum, busmap.busmap);
mutex_unlock(&usb_bus_list_lock);
@@ -1226,17 +1274,22 @@
if (tmp == -EINPROGRESS) {
tmp = urb->pipe;
unlink1 (hcd, urb);
- dev_dbg (hcd->self.controller,
- "shutdown urb %p pipe %08x ep%d%s%s\n",
- urb, tmp, usb_pipeendpoint (tmp),
- (tmp & USB_DIR_IN) ? "in" : "out",
- ({ char *s; \
- switch (usb_pipetype (tmp)) { \
- case PIPE_CONTROL: s = ""; break; \
- case PIPE_BULK: s = "-bulk"; break; \
- case PIPE_INTERRUPT: s = "-intr"; break; \
- default: s = "-iso"; break; \
- }; s;}));
+#ifdef DEBUG
+ {
+ char *s;
+ switch (usb_pipetype (tmp)) {
+ case PIPE_CONTROL: s = ""; break;
+ case PIPE_BULK: s = "-bulk"; break;
+ case PIPE_INTERRUPT: s = "-intr"; break;
+ default: s = "-iso"; break;
+ }
+
+ dev_dbg (hcd->self.controller,
+ "shutdown urb %p pipe %08x ep%d%s%s\n",
+ urb, tmp, usb_pipeendpoint (tmp),
+ (tmp & USB_DIR_IN) ? "in" : "out", s );
+ }
+#endif
}
usb_put_urb (urb);
diff -urN a/drivers/usb/serial/alcatel.c b/drivers/usb/serial/alcatel.c
--- a/drivers/usb/serial/alcatel.c 1970-01-01 01:00:00.000000000 +0100
+++ b/drivers/usb/serial/alcatel.c 2007-08-30 11:06:51.000000000 +0200
@@ -0,0 +1,253 @@
+/*
+ * USB Serial Converter Alcatel-generic
+ *
+ * Copyright (C) 1999 - 2002 Greg Kroah-Hartman ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/sysctl.h>
+#include <asm/uaccess.h>
+
+/* #define DEBUG_ALCATEL */
+
+#ifdef DEBUG_ALCATEL
+#define alprintk printk
+#else
+#define alprintk( ... ) do{}while(0)
+#endif
+
+static __u16 vendor = 0x0000;
+static __u16 product = 0x0000;
+
+module_param(vendor, ushort, 0);
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+module_param(product, ushort, 0);
+MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+
+
+static struct usb_device_id alcatel_device_ids[2]; /* Initially all zeroes. */
+
+/* we want to look at all devices, as the vendor/product id can change
+ * depending on the command line argument and the dynamicaly added
+ * devices. */
+static struct usb_device_id alcatel_serial_check_all_ids[] = {
+ { .driver_info = 42 },
+ { }
+};
+
+static int alcatel_attach( struct usb_serial* serial );
+static int alcatel_serial_calc_num_ports( struct usb_serial* serial );
+
+static struct usb_driver alcatel_driver = {
+ .name = "alcatel",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = alcatel_serial_check_all_ids,
+ .no_dynamic_id = 0,
+};
+
+/* All of the device info needed for the Generic Serial Converter */
+struct usb_serial_driver usb_serial_alcatel_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "usbserial_alcatel",
+ },
+ .usb_driver = &alcatel_driver,
+ .description = "generic serial device - alcatel driver",
+ .id_table = alcatel_device_ids, /* The static one */
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_interrupt_out = NUM_DONT_CARE,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+ .num_ports = 1,
+ .attach = alcatel_attach,
+ .calc_num_ports = alcatel_serial_calc_num_ports,
+};
+
+
+static ssize_t reset_id(struct device_driver *driver, const char *buf, size_t count)
+{
+ unsigned int minor = 0;
+ int fields = 0;
+ struct usb_serial* serial = NULL;
+ struct usb_interface* intf = NULL;
+ struct usb_device* usbdev = NULL;
+ int unlock = 0;
+
+ int i = 0, inc = 0;
+ int min_minor_of_dev = 0, max_minor_of_dev = 0;
+
+ struct usb_serial* saved_serial = NULL;
+ struct usb_interface* saved_intf = NULL;
+
+
+ fields = sscanf( buf, "%d", &minor );
+ if( fields < 1 ){
+ return -EINVAL;
+ }
+
+ saved_serial = usb_serial_get_by_index( minor );
+ if( saved_serial == NULL ){
+ printk("%s: Got request to reset Id: %d. No such device.\n", alcatel_driver.name, minor );
+ return -ENODEV;
+ }
+ saved_intf = saved_serial->interface;
+
+ inc = usb_serial_get_increment();
+ min_minor_of_dev = ( ((int)(minor / inc)) * inc );
+ max_minor_of_dev = ( min_minor_of_dev + inc - 1 );
+
+ printk("%s: Got request to reset Id: %d. Reset range from %d to %d.\n",
+ alcatel_driver.name, minor, min_minor_of_dev, max_minor_of_dev );
+
+ for( i = min_minor_of_dev; i <= max_minor_of_dev; i++ ){
+ serial = usb_serial_get_by_index( i );
+ if( serial == NULL ){
+ continue;
+ }
+ printk("%s: performing reset of Id: %d\n", alcatel_driver.name, i );
+ usb_serial_alcatel_driver.shutdown( serial );
+ printk("%s: ttyUSB%d has been shutdown.\n", alcatel_driver.name, i );
+
+ intf = serial->interface;
+ usb_serial_put( serial ); /* Let the serial be freeed */
+ usbdev = interface_to_usbdev( intf );
+
+ down_write( &(driver->bus->subsys.rwsem) );
+ usb_driver_release_interface( usb_serial_alcatel_driver.usb_driver, intf );
+ up_write( &(driver->bus->subsys.rwsem) );
+
+ printk("%s: interface %d has been released.\n", alcatel_driver.name, intf->cur_altsetting->desc.bInterfaceNumber);
+ if( (unlock = usb_lock_device_for_reset(usbdev, NULL)) >= 0 ){
+ int ret = 0;
+
+ ret = usb_reset_composite_device( usbdev, NULL );
+ if( ret == 0 ){
+ printk("%s: device %d reseted\n", alcatel_driver.name, i );
+ } else if( ret == -ENODEV ){
+ printk("%s: device %d has been flagged for logical disconnection.\n",
+ alcatel_driver.name, i );
+ } else {
+ printk("%s: device %d: reset error: %d\n", alcatel_driver.name, i, ret );
+ count = -EFAULT;
+ }
+
+ if( unlock ){
+ usb_unlock_device( usbdev );
+ }
+ }
+ }
+
+ usb_serial_put( saved_serial ); /* Let the serial be freeed */
+
+ /* And now try to find the device back. (this is reset, not stop) */
+ if( bus_rescan_devices(saved_intf->dev.bus) < 0 ){
+ printk("%s: error while rescanning devices\n", alcatel_driver.name);
+ return -EFAULT;
+ }
+
+ return count;
+}
+
+static DRIVER_ATTR(reset, S_IWUSR, NULL, reset_id);
+
+static int alcatel_create_reset_file(struct usb_driver *usb_drv)
+{
+ alprintk("%s: creating reset file in sysfs\n", alcatel_driver.name);
+ return sysfs_create_file( &usb_drv->drvwrap.driver.kobj, &driver_attr_reset.attr );
+}
+
+static void alcatel_remove_reset_file(struct usb_driver *usb_drv)
+{
+ sysfs_remove_file( &usb_drv->drvwrap.driver.kobj, &driver_attr_reset.attr );
+}
+
+static int alcatel_attach( struct usb_serial* serial )
+{
+ alprintk("%s: driver attached\n", alcatel_driver.name);
+ return 0;
+}
+
+static int alcatel_serial_calc_num_ports( struct usb_serial* serial )
+{
+ return( serial->num_bulk_out );
+}
+
+static int __init usb_serial_alcatel_init( void )
+{
+ int retval = 0;
+
+ /* add the device(s) given as argument if any */
+ if( vendor || product ){
+ alcatel_device_ids[0].idVendor = vendor;
+ alcatel_device_ids[0].idProduct = product;
+ if( (vendor != 0x0000) && (product != 0x0000) ){
+ alcatel_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+ } else if( vendor != 0x0000 ){
+ alcatel_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR;
+ } else {
+ alcatel_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_PRODUCT;
+ }
+ }
+
+ INIT_LIST_HEAD( &(alcatel_driver.dynids.list) );
+
+ retval = usb_serial_register( &usb_serial_alcatel_driver );
+ if( retval != 0 )
+ goto usb_serial_reg_failed;
+
+ retval = usb_register( &alcatel_driver );
+ if( retval )
+ goto usb_reg_failed;
+
+ retval = alcatel_create_reset_file( &alcatel_driver );
+ if( retval )
+ goto usb_sysfs_failed;
+
+ printk("Alcatel multi serial devices driver registered.\n");
+
+ return retval;
+
+usb_sysfs_failed:
+ alprintk("%s: init failed: usb_sysfs_failed\n", alcatel_driver.name);
+ usb_deregister( &alcatel_driver );
+usb_reg_failed:
+ alprintk("%s: init failed: usb_reg_failed\n", alcatel_driver.name);
+ usb_serial_deregister( &usb_serial_alcatel_driver );
+usb_serial_reg_failed:
+ alprintk("%s: init failed: usb_serial_reg_failed\n", alcatel_driver.name);
+ return retval;
+}
+
+static void __exit usb_serial_alcatel_exit( void )
+{
+ /* remove our alcatel driver */
+ alprintk("%s: exiting\n", alcatel_driver.name);
+ alcatel_remove_reset_file( &alcatel_driver );
+ usb_deregister( &alcatel_driver );
+ usb_serial_deregister( &usb_serial_alcatel_driver );
+}
+
+module_init( usb_serial_alcatel_init );
+module_exit( usb_serial_alcatel_exit );
+
+/* Module information */
+MODULE_AUTHOR( "Nathael PAJANI" );
+MODULE_DESCRIPTION( "Generic driver improvement for multi serial devices" );
+MODULE_LICENSE("GPL");
+
diff -urN a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
--- a/drivers/usb/serial/Kconfig 2007-08-30 20:10:37.000000000 +0100
+++ b/drivers/usb/serial/Kconfig 2007-08-30 18:29:24.000000000 +0200
@@ -53,6 +53,22 @@
support" be compiled as a module for this driver to be used
properly.
+config USB_SERIAL_ALCATEL
+ tristate "USB Alcatel serial driver"
+ depends on USB_SERIAL
+ help
+ Say Y here if you want to use your ttyUSB device in a way that
+ devices are allocated statically to ttyUSBxx depending on the
+ position on the USB BUS
+ Say Y here if you want to add dynamicaly device vendor/product codes
+ for devices supporting generic serial interface.
+ Say Y here if you want to be able to handle many different devices
+ with the generic serial driver.
+
+ To compile this driver as a module, choose M here: the module will
+ be called alcatel.
+
+
config USB_SERIAL_AIRCABLE
tristate "USB AIRcable Bluetooth Dongle Driver (EXPERIMENTAL)"
depends on USB_SERIAL && EXPERIMENTAL
diff -urN a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
--- a/drivers/usb/serial/Makefile 2007-08-30 20:10:37.000000000 +0100
+++ b/drivers/usb/serial/Makefile 2007-08-30 18:29:24.000000000 +0200
@@ -11,6 +11,7 @@
usbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y)
+obj-$(CONFIG_USB_SERIAL_ALCATEL) += alcatel.o
obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o
obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o
obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
diff -urN a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
--- a/drivers/usb/serial/usb-serial.c 2007-08-30 20:10:37.000000000 +0100
+++ b/drivers/usb/serial/usb-serial.c 2007-08-30 18:29:24.000000000 +0200
@@ -58,8 +58,13 @@
drivers depend on it.
*/
+static ushort maxSize = 0;
+static int usb_if_max = 2;
+static int max_ep_per_port = 1;
+static int usb_port_max = 3; /* Number of USB ports allowed per controler */
+static int minor_max = SERIAL_TTY_MINORS;
static int debug;
-static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
+static struct usb_serial** serial_table; /* initially all NULL */
static DEFINE_MUTEX(table_lock);
static LIST_HEAD(usb_serial_driver_list);
@@ -75,40 +80,68 @@
mutex_unlock(&table_lock);
return serial;
}
+EXPORT_SYMBOL_GPL_FUTURE(usb_serial_get_by_index);
+
+int usb_serial_get_increment(void)
+{
+ return ( usb_if_max * max_ep_per_port );
+}
+EXPORT_SYMBOL_GPL_FUTURE(usb_serial_get_increment);
-static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_ports, unsigned int *minor)
+static struct usb_serial *get_free_serial( struct usb_serial *serial, int *minor )
{
unsigned int i, j;
- int good_spot;
+ int num_ports = serial->num_ports;
+
+ int tmp_calc_port = 0;
+ int tmp_calc_iface = 0;
+ int ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
dbg("%s %d", __FUNCTION__, num_ports);
+
+ tmp_calc_port = ( serial->dev->bus->busnum * usb_port_max );
+ tmp_calc_iface = ( (tmp_calc_port + (serial->dev->portnum - 1)) * usb_if_max );
+ *minor = (int)( (tmp_calc_iface + ifnum) * max_ep_per_port );
+
+ /* NOTE that num_ports is the number of endpoints we decided to handle */
+ printk("%s portnum: %d/%d, ifnum: %d/%d, endpoints: %d/%d, minor: %d/%d.\n",
+ __FUNCTION__, serial->dev->portnum, usb_port_max, (ifnum + 1), usb_if_max,
+ num_ports, max_ep_per_port, *minor, minor_max );
+
- *minor = 0;
- mutex_lock(&table_lock);
- for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
- if (serial_table[i])
- continue;
+ /* portnum ranges from 1 to N */
+ if( serial->dev->portnum > usb_port_max ){
+ return NULL;
+ }
+ /* ifnum ranges from 0 to N */
+ if( ifnum >= usb_if_max ){
+ return NULL;
+ }
- good_spot = 1;
- for (j = 1; j <= num_ports-1; ++j)
- if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) {
- good_spot = 0;
- i += j;
- break;
- }
- if (good_spot == 0)
- continue;
+ /* NOTE: minor is the base used for all the endpoints,
+ * but each endpoint will have (minor + endpoint_number) as minor number. */
+ if( (*minor + num_ports) >= minor_max ){
+ return NULL;
+ }
- *minor = i;
- j = 0;
- dbg("%s - minor base = %d", __FUNCTION__, *minor);
- for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) {
- serial_table[i] = serial;
- serial->port[j++]->number = i;
- }
- mutex_unlock(&table_lock);
- return serial;
+ mutex_lock(&table_lock);
+ for( i = *minor; (i < (*minor + num_ports)) && (i < minor_max); ++i ){
+ if( serial_table[ i ] ){
+ printk("%s error: usb serial port ttyUSB%d is in use.\n", __FUNCTION__, i);
+ goto unlock_exit;
+ }
+ }
+ j = 0;
+ for( i = *minor; (i < (*minor + num_ports)) && (i < minor_max); ++i ){
+ serial_table[i] = serial;
+ serial->port[j++]->number = i;
}
+
+ serial->minor = *minor;
+ mutex_unlock(&table_lock);
+ return serial;
+
+unlock_exit:
mutex_unlock(&table_lock);
return NULL;
}
@@ -176,6 +209,7 @@
kref_put(&serial->kref, destroy_serial);
mutex_unlock(&table_lock);
}
+EXPORT_SYMBOL_GPL_FUTURE(usb_serial_put);
/*****************************************************************************
* Driver tty interface functions
@@ -453,30 +487,37 @@
static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
{
struct usb_serial *serial;
+ struct usb_serial *old_serial = NULL;
int length = 0;
int i;
off_t begin = 0;
char tmp[40];
dbg("%s", __FUNCTION__);
- length += sprintf (page, "usbserinfo:1.0 driver:2.0\n");
- for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
+ length += sprintf (page, "usbserinfo:2.0 driver:2.2\n");
+ for (i = 0; i < minor_max && length < PAGE_SIZE; ++i) {
serial = usb_serial_get_by_index(i);
+
if (serial == NULL)
continue;
+
+ if (serial != old_serial) {
+ old_serial = serial;
+ length += sprintf( page+length, "\ndevice on bus %d, port %d. Id: %d\n",
+ serial->dev->bus->busnum, serial->dev->portnum, serial->minor );
+ if (serial->type->driver.owner)
+ length += sprintf( page+length, " module: %s", module_name(serial->type->driver.owner) );
+ length += sprintf( page+length, " name: \"%s\"\n", serial->type->description );
+ length += sprintf( page+length, " vendor: %04x product: %04x",
+ le16_to_cpu(serial->dev->descriptor.idVendor),
+ le16_to_cpu(serial->dev->descriptor.idProduct));
+ length += sprintf( page+length, " num_ports: %d\n", serial->num_ports);
+ }
- length += sprintf (page+length, "%d:", i);
- if (serial->type->driver.owner)
- length += sprintf (page+length, " module:%s", module_name(serial->type->driver.owner));
- length += sprintf (page+length, " name:\"%s\"", serial->type->description);
- length += sprintf (page+length, " vendor:%04x product:%04x",
- le16_to_cpu(serial->dev->descriptor.idVendor),
- le16_to_cpu(serial->dev->descriptor.idProduct));
- length += sprintf (page+length, " num_ports:%d", serial->num_ports);
- length += sprintf (page+length, " port:%d", i - serial->minor + 1);
+ length += sprintf( page+length, " port %d on ttyUSB%d,", i - serial->minor + 1, i);
- usb_make_path(serial->dev, tmp, sizeof(tmp));
- length += sprintf (page+length, " path:%s", tmp);
+ usb_make_path( serial->dev, tmp, sizeof(tmp));
+ length += sprintf( page+length, " path: %s", tmp);
length += sprintf (page+length, "\n");
if ((length + begin) > (off + count)) {
@@ -814,6 +862,19 @@
}
}
#endif
+
+ /* We won't handle more than "max_ep_per_port" ports from the device */
+ /* Do it here, so the calc_num_ports function can make use of these */
+ num_bulk_in = min( num_bulk_in, max_ep_per_port );
+ num_bulk_out = min( num_bulk_out, max_ep_per_port );
+ num_interrupt_in = min( num_interrupt_in, max_ep_per_port );
+ num_interrupt_out = min( num_interrupt_out, max_ep_per_port );
+
+ serial->num_bulk_in = num_bulk_in;
+ serial->num_bulk_out = num_bulk_out;
+ serial->num_interrupt_in = num_interrupt_in;
+ serial->num_interrupt_out = num_interrupt_out;
+
if (!num_ports) {
/* if this device type has a calc_num_ports function, call it */
if (type->calc_num_ports) {
@@ -830,11 +891,8 @@
num_ports = type->num_ports;
}
+ num_ports = min( num_ports, max_ep_per_port );
serial->num_ports = num_ports;
- serial->num_bulk_in = num_bulk_in;
- serial->num_bulk_out = num_bulk_out;
- serial->num_interrupt_in = num_interrupt_in;
- serial->num_interrupt_out = num_interrupt_out;
/* create our ports, we need as many as the max endpoints */
/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
@@ -866,7 +924,11 @@
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
+ if( endpoint->wMaxPacketSize > maxSize ){
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ } else {
+ buffer_size = maxSize;
+ }
port->bulk_in_size = buffer_size;
port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
@@ -1124,12 +1186,13 @@
int i;
int result;
- usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
+ usb_serial_tty_driver = alloc_tty_driver(minor_max);
if (!usb_serial_tty_driver)
return -ENOMEM;
/* Initialize our global data */
- for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
+ serial_table = kmalloc( (minor_max*sizeof(void*)), GFP_KERNEL);
+ for (i = 0; i < minor_max; ++i) {
serial_table[i] = NULL;
}
@@ -1243,9 +1306,9 @@
if (retval) {
err("problem %d when registering driver %s", retval, driver->description);
list_del(&driver->driver_list);
- }
- else
+ } else {
info("USB Serial support registered for %s", driver->description);
+ }
return retval;
}
@@ -1276,3 +1339,18 @@
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+module_param(maxSize, ushort, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(maxSize,"User specified USB endpoint size");
+
+module_param(usb_if_max, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(usb_if_max,"Number of interfaces handled, default is 2");
+
+module_param(max_ep_per_port, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_ep_per_port,"Number of endpoint translated to ttyUSB serial ports, default is 1");
+
+module_param(usb_port_max, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(usb_port_max,"Number of USB ports allowed per controler, default is 3");
+
+module_param(minor_max, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(minor_max,"Maximum number of ttyUSB on the system");
diff -urN a/include/linux/usb/serial.h b/include/linux/usb/serial.h
--- a/include/linux/usb/serial.h 2007-08-30 20:10:37.000000000 +0100
+++ b/include/linux/usb/serial.h 2007-08-30 15:44:59.000000000 +0200
@@ -271,6 +271,7 @@
/* Functions needed by other parts of the usbserial core */
extern struct usb_serial *usb_serial_get_by_index (unsigned int minor);
+extern int usb_serial_get_increment(void);
extern void usb_serial_put(struct usb_serial *serial);
extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count);