diff options
Diffstat (limited to 'drivers/usb/serial')
43 files changed, 683 insertions, 173 deletions
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 86bcf63b6ba5..11dad42c3c60 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -572,8 +572,20 @@ static void aircable_unthrottle(struct usb_serial_port *port) schedule_work(&priv->rx_work); } +static struct usb_driver aircable_driver = { + .name = "aircable", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver aircable_device = { - .description = "aircable", + .driver = { + .owner = THIS_MODULE, + .name = "aircable", + }, + .usb_driver = &aircable_driver, .id_table = id_table, .num_ports = 1, .attach = aircable_attach, @@ -587,13 +599,6 @@ static struct usb_serial_driver aircable_device = { .unthrottle = aircable_unthrottle, }; -static struct usb_driver aircable_driver = { - .name = "aircable", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static int __init aircable_init (void) { int retval; diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index f2ca76a9cbac..0af42e32fa0a 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -277,6 +277,7 @@ static struct usb_serial_driver airprime_device = { .owner = THIS_MODULE, .name = "airprime", }, + .usb_driver = &airprime_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 5261cd22ee6b..edd685791a6b 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -444,6 +444,7 @@ static struct usb_driver ark3116_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, + .no_dynamic_id = 1, }; static struct usb_serial_driver ark3116_device = { @@ -452,6 +453,7 @@ static struct usb_serial_driver ark3116_device = { .name = "ark3116", }, .id_table = id_table, + .usb_driver = &ark3116_driver, .num_interrupt_in = 1, .num_bulk_in = 1, .num_bulk_out = 1, diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 38b4dae319ee..3b800d277c4b 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -126,6 +126,7 @@ static struct usb_serial_driver belkin_device = { .name = "belkin", }, .description = "Belkin / Peracom / GoHubs USB Serial Adapter", + .usb_driver = &belkin_driver, .id_table = id_table_combined, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 6542f220468f..c08a38402b93 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -103,11 +103,52 @@ exit: return retval; } +#ifdef CONFIG_HOTPLUG +static ssize_t store_new_id(struct device_driver *driver, + const char *buf, size_t count) +{ + struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver); + ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count); + + if (retval >= 0 && usb_drv->usb_driver != NULL) + retval = usb_store_new_id(&usb_drv->usb_driver->dynids, + &usb_drv->usb_driver->drvwrap.driver, + buf, count); + return retval; +} + +static struct driver_attribute drv_attrs[] = { + __ATTR(new_id, S_IWUSR, NULL, store_new_id), + __ATTR_NULL, +}; + +static void free_dynids(struct usb_serial_driver *drv) +{ + struct usb_dynid *dynid, *n; + + spin_lock(&drv->dynids.lock); + list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { + list_del(&dynid->node); + kfree(dynid); + } + spin_unlock(&drv->dynids.lock); +} + +#else +static struct driver_attribute drv_attrs[] = { + __ATTR_NULL, +}; +static inline void free_dynids(struct usb_driver *drv) +{ +} +#endif + struct bus_type usb_serial_bus_type = { .name = "usb-serial", .match = usb_serial_device_match, .probe = usb_serial_device_probe, .remove = usb_serial_device_remove, + .drv_attrs = drv_attrs, }; int usb_serial_bus_register(struct usb_serial_driver *driver) @@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) int retval; driver->driver.bus = &usb_serial_bus_type; + spin_lock_init(&driver->dynids.lock); + INIT_LIST_HEAD(&driver->dynids.list); + retval = driver_register(&driver->driver); return retval; @@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) void usb_serial_bus_deregister(struct usb_serial_driver *driver) { + free_dynids(driver); driver_unregister(&driver->driver); } diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 7ebaffd6ed86..06b4fffc189c 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -89,6 +89,7 @@ static struct usb_serial_driver cp2101_device = { .owner = THIS_MODULE, .name = "cp2101", }, + .usb_driver = &cp2101_driver, .id_table = id_table, .num_interrupt_in = 0, .num_bulk_in = 0, diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index a63c3286caa0..4167753ed31f 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -88,6 +88,7 @@ static struct usb_serial_driver cyberjack_device = { .name = "cyberjack", }, .description = "Reiner SCT Cyberjack USB card reader", + .usb_driver = &cyberjack_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -98,7 +99,7 @@ static struct usb_serial_driver cyberjack_device = { .open = cyberjack_open, .close = cyberjack_close, .write = cyberjack_write, - .write_room = cyberjack_write_room, + .write_room = cyberjack_write_room, .read_int_callback = cyberjack_read_int_callback, .read_bulk_callback = cyberjack_read_bulk_callback, .write_bulk_callback = cyberjack_write_bulk_callback, diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 6bc1f404e186..57b8e27285fc 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -193,6 +193,7 @@ static struct usb_serial_driver cypress_earthmate_device = { .name = "earthmate", }, .description = "DeLorme Earthmate USB", + .usb_driver = &cypress_driver, .id_table = id_table_earthmate, .num_interrupt_in = 1, .num_interrupt_out = 1, @@ -222,6 +223,7 @@ static struct usb_serial_driver cypress_hidcom_device = { .name = "cyphidcom", }, .description = "HID->COM RS232 Adapter", + .usb_driver = &cypress_driver, .id_table = id_table_cyphidcomrs232, .num_interrupt_in = 1, .num_interrupt_out = 1, @@ -251,6 +253,7 @@ static struct usb_serial_driver cypress_ca42v2_device = { .name = "nokiaca42v2", }, .description = "Nokia CA-42 V2 Adapter", + .usb_driver = &cypress_driver, .id_table = id_table_nokiaca42v2, .num_interrupt_in = 1, .num_interrupt_out = 1, diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index efd9ce3f931f..0b0fb51bad3e 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -509,6 +509,7 @@ static struct usb_serial_driver digi_acceleport_2_device = { .name = "digi_2", }, .description = "Digi 2 port USB adapter", + .usb_driver = &digi_driver, .id_table = id_table_2, .num_interrupt_in = 0, .num_bulk_in = 4, @@ -538,6 +539,7 @@ static struct usb_serial_driver digi_acceleport_4_device = { .name = "digi_4", }, .description = "Digi 4 port USB adapter", + .usb_driver = &digi_driver, .id_table = id_table_4, .num_interrupt_in = 0, .num_bulk_in = 5, diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 92beeb19795f..4703c8f85383 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -117,6 +117,7 @@ static struct usb_serial_driver empeg_device = { .name = "empeg", }, .id_table = id_table, + .usb_driver = &empeg_driver, .num_interrupt_in = 0, .num_bulk_in = 1, .num_bulk_out = 1, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 6986e756f7c0..4695952b6470 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -464,7 +464,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) }, - { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) }, @@ -615,6 +614,7 @@ static struct usb_serial_driver ftdi_sio_device = { .name = "ftdi_sio", }, .description = "FTDI USB Serial Device", + .usb_driver = &ftdi_driver , .id_table = id_table_combined, .num_interrupt_in = 0, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 40dd394de58d..7eff1c03ba80 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -364,7 +364,6 @@ * USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices * and I'm not entirely sure which are used by which. */ -#define FTDI_4N_GALAXY_DE_0_PID 0x8372 #define FTDI_4N_GALAXY_DE_1_PID 0xF3C0 #define FTDI_4N_GALAXY_DE_2_PID 0xF3C1 diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 2bebd63d5ed1..4092f6dc9efd 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -58,6 +58,7 @@ static struct usb_serial_driver funsoft_device = { .name = "funsoft", }, .id_table = id_table, + .usb_driver = &funsoft_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 6530d391ebed..74660a3aa670 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1566,6 +1566,7 @@ static struct usb_serial_driver garmin_device = { .name = "garmin_gps", }, .description = "Garmin GPS usb/tty", + .usb_driver = &garmin_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 36042937e77f..601e0648dec6 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -20,6 +20,10 @@ #include <linux/usb/serial.h> #include <asm/uaccess.h> +static int generic_probe(struct usb_interface *interface, + const struct usb_device_id *id); + + static int debug; #ifdef CONFIG_USB_SERIAL_GENERIC @@ -34,6 +38,21 @@ MODULE_PARM_DESC(product, "User specified USB idProduct"); static struct usb_device_id generic_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 */ +static struct usb_device_id generic_serial_ids[] = { + {.driver_info = 42}, + {} +}; + +static struct usb_driver generic_driver = { + .name = "usbserial_generic", + .probe = generic_probe, + .disconnect = usb_serial_disconnect, + .id_table = generic_serial_ids, + .no_dynamic_id = 1, +}; + /* All of the device info needed for the Generic Serial Converter */ struct usb_serial_driver usb_serial_generic_device = { .driver = { @@ -41,6 +60,7 @@ struct usb_serial_driver usb_serial_generic_device = { .name = "generic", }, .id_table = generic_device_ids, + .usb_driver = &generic_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, @@ -48,13 +68,6 @@ struct usb_serial_driver usb_serial_generic_device = { .shutdown = usb_serial_generic_shutdown, }; -/* we want to look at all devices, as the vendor/product id can change - * depending on the command line argument */ -static struct usb_device_id generic_serial_ids[] = { - {.driver_info = 42}, - {} -}; - static int generic_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -65,14 +78,6 @@ static int generic_probe(struct usb_interface *interface, return usb_serial_probe(interface, id); return -ENODEV; } - -static struct usb_driver generic_driver = { - .name = "usbserial_generic", - .probe = generic_probe, - .disconnect = usb_serial_disconnect, - .id_table = generic_serial_ids, - .no_dynamic_id = 1, -}; #endif int usb_serial_generic_register (int _debug) diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c index ebcac701b069..6c6ebae741c9 100644 --- a/drivers/usb/serial/hp4x.c +++ b/drivers/usb/serial/hp4x.c @@ -49,6 +49,7 @@ static struct usb_serial_driver hp49gp_device = { .name = "hp4X", }, .id_table = id_table, + .usb_driver = &hp49gp_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index f623d58370a4..6a26a2e683a6 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -146,6 +146,8 @@ struct edgeport_serial { struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */ struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */ struct edgeport_product_info product_info; /* Product Info */ + struct edge_compatibility_descriptor epic_descriptor; /* Edgeport compatible descriptor */ + int is_epic; /* flag if EPiC device or not */ __u8 interrupt_in_endpoint; /* the interrupt endpoint handle */ unsigned char * interrupt_in_buffer; /* the buffer we use for the interrupt endpoint */ @@ -240,14 +242,6 @@ static void edge_shutdown (struct usb_serial *serial); #include "io_tables.h" /* all of the devices that this driver supports */ -static struct usb_driver io_driver = { - .name = "io_edgeport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; - /* function prototypes for all of our local functions */ static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength); static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3); @@ -397,6 +391,7 @@ static int get_string (struct usb_device *dev, int Id, char *string, int buflen) unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2); kfree(pStringDesc); + dbg("%s - USB String %s", __FUNCTION__, string); return strlen(string); } @@ -434,6 +429,34 @@ static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_de } #endif +static void dump_product_info(struct edgeport_product_info *product_info) +{ + // Dump Product Info structure + dbg("**Product Information:"); + dbg(" ProductId %x", product_info->ProductId ); + dbg(" NumPorts %d", product_info->NumPorts ); + dbg(" ProdInfoVer %d", product_info->ProdInfoVer ); + dbg(" IsServer %d", product_info->IsServer); + dbg(" IsRS232 %d", product_info->IsRS232 ); + dbg(" IsRS422 %d", product_info->IsRS422 ); + dbg(" IsRS485 %d", product_info->IsRS485 ); + dbg(" RomSize %d", product_info->RomSize ); + dbg(" RamSize %d", product_info->RamSize ); + dbg(" CpuRev %x", product_info->CpuRev ); + dbg(" BoardRev %x", product_info->BoardRev); + dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion, + product_info->BootMinorVersion, + le16_to_cpu(product_info->BootBuildNumber)); + dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion, + product_info->FirmwareMinorVersion, + le16_to_cpu(product_info->FirmwareBuildNumber)); + dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0], + product_info->ManufactureDescDate[1], + product_info->ManufactureDescDate[2]+1900); + dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); + dbg(" EpicVer %d", product_info->EpicVer); +} + static void get_product_info(struct edgeport_serial *edge_serial) { struct edgeport_product_info *product_info = &edge_serial->product_info; @@ -495,30 +518,60 @@ static void get_product_info(struct edgeport_serial *edge_serial) break; } - // Dump Product Info structure - dbg("**Product Information:"); - dbg(" ProductId %x", product_info->ProductId ); - dbg(" NumPorts %d", product_info->NumPorts ); - dbg(" ProdInfoVer %d", product_info->ProdInfoVer ); - dbg(" IsServer %d", product_info->IsServer); - dbg(" IsRS232 %d", product_info->IsRS232 ); - dbg(" IsRS422 %d", product_info->IsRS422 ); - dbg(" IsRS485 %d", product_info->IsRS485 ); - dbg(" RomSize %d", product_info->RomSize ); - dbg(" RamSize %d", product_info->RamSize ); - dbg(" CpuRev %x", product_info->CpuRev ); - dbg(" BoardRev %x", product_info->BoardRev); - dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion, - product_info->BootMinorVersion, - le16_to_cpu(product_info->BootBuildNumber)); - dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion, - product_info->FirmwareMinorVersion, - le16_to_cpu(product_info->FirmwareBuildNumber)); - dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0], - product_info->ManufactureDescDate[1], - product_info->ManufactureDescDate[2]+1900); - dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); + dump_product_info(product_info); +} +static int get_epic_descriptor(struct edgeport_serial *ep) +{ + int result; + struct usb_serial *serial = ep->serial; + struct edgeport_product_info *product_info = &ep->product_info; + struct edge_compatibility_descriptor *epic = &ep->epic_descriptor; + struct edge_compatibility_bits *bits; + + ep->is_epic = 0; + result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + USB_REQUEST_ION_GET_EPIC_DESC, + 0xC0, 0x00, 0x00, + &ep->epic_descriptor, + sizeof(struct edge_compatibility_descriptor), + 300); + + dbg("%s result = %d", __FUNCTION__, result); + + if (result > 0) { + ep->is_epic = 1; + memset(product_info, 0, sizeof(struct edgeport_product_info)); + + product_info->NumPorts = epic->NumPorts; + product_info->ProdInfoVer = 0; + product_info->FirmwareMajorVersion = epic->MajorVersion; + product_info->FirmwareMinorVersion = epic->MinorVersion; + product_info->FirmwareBuildNumber = epic->BuildNumber; + product_info->iDownloadFile = epic->iDownloadFile; + product_info->EpicVer = epic->EpicVer; + product_info->Epic = epic->Supports; + product_info->ProductId = ION_DEVICE_ID_EDGEPORT_COMPATIBLE; + dump_product_info(product_info); + + bits = &ep->epic_descriptor.Supports; + dbg("**EPIC descriptor:"); + dbg(" VendEnableSuspend: %s", bits->VendEnableSuspend ? "TRUE": "FALSE"); + dbg(" IOSPOpen : %s", bits->IOSPOpen ? "TRUE": "FALSE" ); + dbg(" IOSPClose : %s", bits->IOSPClose ? "TRUE": "FALSE" ); + dbg(" IOSPChase : %s", bits->IOSPChase ? "TRUE": "FALSE" ); + dbg(" IOSPSetRxFlow : %s", bits->IOSPSetRxFlow ? "TRUE": "FALSE" ); + dbg(" IOSPSetTxFlow : %s", bits->IOSPSetTxFlow ? "TRUE": "FALSE" ); + dbg(" IOSPSetXChar : %s", bits->IOSPSetXChar ? "TRUE": "FALSE" ); + dbg(" IOSPRxCheck : %s", bits->IOSPRxCheck ? "TRUE": "FALSE" ); + dbg(" IOSPSetClrBreak : %s", bits->IOSPSetClrBreak ? "TRUE": "FALSE" ); + dbg(" IOSPWriteMCR : %s", bits->IOSPWriteMCR ? "TRUE": "FALSE" ); + dbg(" IOSPWriteLCR : %s", bits->IOSPWriteLCR ? "TRUE": "FALSE" ); + dbg(" IOSPSetBaudRate : %s", bits->IOSPSetBaudRate ? "TRUE": "FALSE" ); + dbg(" TrueEdgeport : %s", bits->TrueEdgeport ? "TRUE": "FALSE" ); + } + + return result; } @@ -1017,21 +1070,29 @@ static void edge_close (struct usb_serial_port *port, struct file * filp) edge_port->closePending = TRUE; - /* flush and chase */ - edge_port->chaseResponsePending = TRUE; - - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); - if (status == 0) { - // block until chase finished - block_until_chase_response(edge_port); - } else { - edge_port->chaseResponsePending = FALSE; + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPChase))) { + /* flush and chase */ + edge_port->chaseResponsePending = TRUE; + + dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); + if (status == 0) { + // block until chase finished + block_until_chase_response(edge_port); + } else { + edge_port->chaseResponsePending = FALSE; + } } - /* close the port */ - dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__); - send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPClose))) { + /* close the port */ + dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__); + send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0); + } //port->close = TRUE; edge_port->closePending = FALSE; @@ -1694,29 +1755,38 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned static void edge_break (struct usb_serial_port *port, int break_state) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); + struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial); int status; - /* flush and chase */ - edge_port->chaseResponsePending = TRUE; - - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); - if (status == 0) { - // block until chase finished - block_until_chase_response(edge_port); - } else { - edge_port->chaseResponsePending = FALSE; + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPChase))) { + /* flush and chase */ + edge_port->chaseResponsePending = TRUE; + + dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); + if (status == 0) { + // block until chase finished + block_until_chase_response(edge_port); + } else { + edge_port->chaseResponsePending = FALSE; + } } - if (break_state == -1) { - dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0); - } else { - dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0); - } - if (status) { - dbg("%s - error sending break set/clear command.", __FUNCTION__); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) { + if (break_state == -1) { + dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0); + } else { + dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0); + } + if (status) { + dbg("%s - error sending break set/clear command.", __FUNCTION__); + } } return; @@ -2288,6 +2358,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer *****************************************************************************/ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate) { + struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); unsigned char *cmdBuffer; unsigned char *currCmd; int cmdLen = 0; @@ -2295,6 +2366,14 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa int status; unsigned char number = edge_port->port->number - edge_port->port->serial->minor; + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) { + dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d", + edge_port->port->number, baudRate); + return 0; + } + dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate); status = calc_baud_rate_divisor (baudRate, &divisor); @@ -2374,6 +2453,7 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor) *****************************************************************************/ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue) { + struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); unsigned char *cmdBuffer; unsigned char *currCmd; unsigned long cmdLen = 0; @@ -2381,6 +2461,22 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) && + (regNum == MCR))) { + dbg("SendCmdWriteUartReg - Not writting to MCR Register"); + return 0; + } + + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) && + (regNum == LCR))) { + dbg ("SendCmdWriteUartReg - Not writting to LCR Register"); + return 0; + } + // Alloc memory for the string of commands. cmdBuffer = kmalloc (0x10, GFP_ATOMIC); if (cmdBuffer == NULL ) { @@ -2414,6 +2510,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r #endif static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios) { + struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); struct tty_struct *tty; int baud; unsigned cflag; @@ -2494,8 +2591,12 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi unsigned char stop_char = STOP_CHAR(tty); unsigned char start_char = START_CHAR(tty); - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char); - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) { + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XON_CHAR, start_char); + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char); + } /* if we are implementing INBOUND XON/XOFF */ if (I_IXOFF(tty)) { @@ -2515,8 +2616,14 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi } /* Set flow control to the configured value */ - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow); - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow))) + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow))) + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow); edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); @@ -2728,6 +2835,13 @@ static int edge_startup (struct usb_serial *serial) struct edgeport_port *edge_port; struct usb_device *dev; int i, j; + int response; + int interrupt_in_found; + int bulk_in_found; + int bulk_out_found; + static __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0, + EDGE_COMPATIBILITY_MASK1, + EDGE_COMPATIBILITY_MASK2 }; dev = serial->dev; @@ -2750,38 +2864,50 @@ static int edge_startup (struct usb_serial *serial) dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name); - /* get the manufacturing descriptor for this device */ - get_manufacturing_desc (edge_serial); + /* Read the epic descriptor */ + if (get_epic_descriptor(edge_serial) <= 0) { + /* memcpy descriptor to Supports structures */ + memcpy(&edge_serial->epic_descriptor.Supports, descriptor, + sizeof(struct edge_compatibility_bits)); + + /* get the manufacturing descriptor for this device */ + get_manufacturing_desc (edge_serial); - /* get the boot descriptor */ - get_boot_desc (edge_serial); + /* get the boot descriptor */ + get_boot_desc (edge_serial); - get_product_info(edge_serial); + get_product_info(edge_serial); + } /* set the number of ports from the manufacturing description */ /* serial->num_ports = serial->product_info.NumPorts; */ - if (edge_serial->product_info.NumPorts != serial->num_ports) { - warn("%s - Device Reported %d serial ports vs core " - "thinking we have %d ports, email greg@kroah.com this info.", - __FUNCTION__, edge_serial->product_info.NumPorts, - serial->num_ports); + if ((!edge_serial->is_epic) && + (edge_serial->product_info.NumPorts != serial->num_ports)) { + dev_warn(&serial->dev->dev, "Device Reported %d serial ports " + "vs. core thinking we have %d ports, email " + "greg@kroah.com this information.", + edge_serial->product_info.NumPorts, + serial->num_ports); } dbg("%s - time 1 %ld", __FUNCTION__, jiffies); - /* now load the application firmware into this device */ - load_application_firmware (edge_serial); + /* If not an EPiC device */ + if (!edge_serial->is_epic) { + /* now load the application firmware into this device */ + load_application_firmware (edge_serial); - dbg("%s - time 2 %ld", __FUNCTION__, jiffies); + dbg("%s - time 2 %ld", __FUNCTION__, jiffies); - /* Check current Edgeport EEPROM and update if necessary */ - update_edgeport_E2PROM (edge_serial); - - dbg("%s - time 3 %ld", __FUNCTION__, jiffies); + /* Check current Edgeport EEPROM and update if necessary */ + update_edgeport_E2PROM (edge_serial); - /* set the configuration to use #1 */ -// dbg("set_configuration 1"); -// usb_set_configuration (dev, 1); + dbg("%s - time 3 %ld", __FUNCTION__, jiffies); + + /* set the configuration to use #1 */ +// dbg("set_configuration 1"); +// usb_set_configuration (dev, 1); + } /* we set up the pointers to the endpoints in the edge_open function, * as the structures aren't created yet. */ @@ -2804,8 +2930,101 @@ static int edge_startup (struct usb_serial *serial) edge_port->port = serial->port[i]; usb_set_serial_port_data(serial->port[i], edge_port); } - - return 0; + + response = 0; + + if (edge_serial->is_epic) { + /* EPIC thing, set up our interrupt polling now and our read urb, so + * that the device knows it really is connected. */ + interrupt_in_found = bulk_in_found = bulk_out_found = FALSE; + for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) { + struct usb_endpoint_descriptor *endpoint; + int buffer_size; + + endpoint = &serial->interface->altsetting[0].endpoint[i].desc; + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + if ((!interrupt_in_found) && + (usb_endpoint_is_int_in(endpoint))) { + /* we found a interrupt in endpoint */ + dbg("found interrupt in"); + + /* not set up yet, so do it now */ + edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!edge_serial->interrupt_read_urb) { + err("out of memory"); + return -ENOMEM; + } + edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!edge_serial->interrupt_in_buffer) { + err("out of memory"); + usb_free_urb(edge_serial->interrupt_read_urb); + return -ENOMEM; + } + edge_serial->interrupt_in_endpoint = endpoint->bEndpointAddress; + + /* set up our interrupt urb */ + usb_fill_int_urb(edge_serial->interrupt_read_urb, + dev, + usb_rcvintpipe(dev, endpoint->bEndpointAddress), + edge_serial->interrupt_in_buffer, + buffer_size, + edge_interrupt_callback, + edge_serial, + endpoint->bInterval); + + interrupt_in_found = TRUE; + } + + if ((!bulk_in_found) && + (usb_endpoint_is_bulk_in(endpoint))) { + /* we found a bulk in endpoint */ + dbg("found bulk in"); + + /* not set up yet, so do it now */ + edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!edge_serial->read_urb) { + err("out of memory"); + return -ENOMEM; + } + edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!edge_serial->bulk_in_buffer) { + err ("out of memory"); + usb_free_urb(edge_serial->read_urb); + return -ENOMEM; + } + edge_serial->bulk_in_endpoint = endpoint->bEndpointAddress; + + /* set up our bulk in urb */ + usb_fill_bulk_urb(edge_serial->read_urb, dev, + usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), + edge_serial->bulk_in_buffer, + endpoint->wMaxPacketSize, + edge_bulk_in_callback, + edge_serial); + bulk_in_found = TRUE; + } + + if ((!bulk_out_found) && + (usb_endpoint_is_bulk_out(endpoint))) { + /* we found a bulk out endpoint */ + dbg("found bulk out"); + edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress; + bulk_out_found = TRUE; + } + } + + if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) { + err ("Error - the proper endpoints were not found!"); + return -ENODEV; + } + + /* start interrupt read for this edgeport this interrupt will + * continue as long as the edgeport is connected */ + response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL); + if (response) + err("%s - Error %d submitting control urb", __FUNCTION__, response); + } + return response; } @@ -2815,6 +3034,7 @@ static int edge_startup (struct usb_serial *serial) ****************************************************************************/ static void edge_shutdown (struct usb_serial *serial) { + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); int i; dbg("%s", __FUNCTION__); @@ -2824,7 +3044,18 @@ static void edge_shutdown (struct usb_serial *serial) kfree (usb_get_serial_port_data(serial->port[i])); usb_set_serial_port_data(serial->port[i], NULL); } - kfree (usb_get_serial_data(serial)); + /* free up our endpoint stuff */ + if (edge_serial->is_epic) { + usb_unlink_urb(edge_serial->interrupt_read_urb); + usb_free_urb(edge_serial->interrupt_read_urb); + kfree(edge_serial->interrupt_in_buffer); + + usb_unlink_urb(edge_serial->read_urb); + usb_free_urb(edge_serial->read_urb); + kfree(edge_serial->bulk_in_buffer); + } + + kfree(edge_serial); usb_set_serial_data(serial, NULL); } @@ -2846,6 +3077,9 @@ static int __init edgeport_init(void) retval = usb_serial_register(&edgeport_8port_device); if (retval) goto failed_8port_device_register; + retval = usb_serial_register(&epic_device); + if (retval) + goto failed_epic_device_register; retval = usb_register(&io_driver); if (retval) goto failed_usb_register; @@ -2853,6 +3087,8 @@ static int __init edgeport_init(void) return 0; failed_usb_register: + usb_serial_deregister(&epic_device); +failed_epic_device_register: usb_serial_deregister(&edgeport_8port_device); failed_8port_device_register: usb_serial_deregister(&edgeport_4port_device); @@ -2873,6 +3109,7 @@ static void __exit edgeport_exit (void) usb_serial_deregister (&edgeport_2port_device); usb_serial_deregister (&edgeport_4port_device); usb_serial_deregister (&edgeport_8port_device); + usb_serial_deregister (&epic_device); } module_init(edgeport_init); diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h index 123fa8a904e6..29a913a6daca 100644 --- a/drivers/usb/serial/io_edgeport.h +++ b/drivers/usb/serial/io_edgeport.h @@ -111,10 +111,12 @@ struct edgeport_product_info { __le16 FirmwareBuildNumber; /* zzzz (LE format) */ __u8 ManufactureDescDate[3]; /* MM/DD/YY when descriptor template was compiled */ - __u8 Unused1[1]; /* Available */ + __u8 HardwareType; __u8 iDownloadFile; /* What to download to EPiC device */ - __u8 Unused2[2]; /* Available */ + __u8 EpicVer; /* What version of EPiC spec this device supports */ + + struct edge_compatibility_bits Epic; }; /* diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index fad561c04c76..6d3008772540 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -47,6 +47,18 @@ static struct usb_device_id edgeport_8port_id_table [] = { { } }; +static struct usb_device_id Epic_port_id_table [] = { + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, + { } +}; + /* Devices that this driver supports */ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, @@ -70,17 +82,34 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, id_table_combined); +static struct usb_driver io_driver = { + .name = "io_edgeport", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table_combined, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver edgeport_2port_device = { .driver = { .owner = THIS_MODULE, .name = "edgeport_2", }, .description = "Edgeport 2 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_2port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -111,6 +140,7 @@ static struct usb_serial_driver edgeport_4port_device = { .name = "edgeport_4", }, .description = "Edgeport 4 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_4port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -141,6 +171,7 @@ static struct usb_serial_driver edgeport_8port_device = { .name = "edgeport_8", }, .description = "Edgeport 8 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_8port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -165,5 +196,35 @@ static struct usb_serial_driver edgeport_8port_device = { .write_bulk_callback = edge_bulk_out_data_callback, }; +static struct usb_serial_driver epic_device = { + .driver = { + .owner = THIS_MODULE, + .name = "epic", + }, + .description = "EPiC device", + .id_table = Epic_port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .shutdown = edge_shutdown, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .tiocmget = edge_tiocmget, + .tiocmset = edge_tiocmset, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, + .read_int_callback = edge_interrupt_callback, + .read_bulk_callback = edge_bulk_in_callback, + .write_bulk_callback = edge_bulk_out_data_callback, +}; + #endif diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 980285c0233a..544098d2b775 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2979,6 +2979,7 @@ static struct usb_serial_driver edgeport_1port_device = { .name = "edgeport_ti_1", }, .description = "Edgeport TI 1 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_1port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -3009,6 +3010,7 @@ static struct usb_serial_driver edgeport_2port_device = { .name = "edgeport_ti_2", }, .description = "Edgeport TI 2 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_2port_id_table, .num_interrupt_in = 1, .num_bulk_in = 2, diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h index f1804fd5a3dd..e57fa117e486 100644 --- a/drivers/usb/serial/io_usbvend.h +++ b/drivers/usb/serial/io_usbvend.h @@ -30,6 +30,7 @@ #define USB_VENDOR_ID_ION 0x1608 // Our VID #define USB_VENDOR_ID_TI 0x0451 // TI VID +#define USB_VENDOR_ID_AXIOHM 0x05D9 /* Axiohm VID */ // // Definitions of USB product IDs (PID) @@ -334,6 +335,10 @@ struct edge_compatibility_bits }; +#define EDGE_COMPATIBILITY_MASK0 0x0001 +#define EDGE_COMPATIBILITY_MASK1 0x3FFF +#define EDGE_COMPATIBILITY_MASK2 0x0001 + struct edge_compatibility_descriptor { __u8 Length; // Descriptor Length (per USB spec) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 42f757a5b876..a408184334ea 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -563,6 +563,7 @@ static struct usb_serial_driver ipaq_device = { .name = "ipaq", }, .description = "PocketPC PDA", + .usb_driver = &ipaq_driver, .id_table = ipaq_id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index d3b9a351cef8..1bc586064c77 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -442,6 +442,7 @@ static struct usb_serial_driver ipw_device = { .name = "ipw", }, .description = "IPWireless converter", + .usb_driver = &usb_ipw_driver, .id_table = usb_ipw_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 8fdf486e3465..9d847f69291c 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -138,6 +138,7 @@ static struct usb_serial_driver ir_device = { .name = "ir-usb", }, .description = "IR Dongle", + .usb_driver = &ir_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 9d2fdfd6865f..e6966f12ed5a 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -1275,11 +1275,31 @@ static int keyspan_fake_startup (struct usb_serial *serial) } /* Helper functions used by keyspan_setup_urbs */ +static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial, + int endpoint) +{ + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *ep; + int i; + + iface_desc = serial->interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + ep = &iface_desc->endpoint[i].desc; + if (ep->bEndpointAddress == endpoint) + return ep; + } + dev_warn(&serial->interface->dev, "found no endpoint descriptor for " + "endpoint %x\n", endpoint); + return NULL; +} + static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint, int dir, void *ctx, char *buf, int len, void (*callback)(struct urb *)) { struct urb *urb; + struct usb_endpoint_descriptor const *ep_desc; + char const *ep_type_name; if (endpoint == -1) return NULL; /* endpoint not needed */ @@ -1291,11 +1311,32 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint, return NULL; } - /* Fill URB using supplied data. */ - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, endpoint) | dir, - buf, len, callback, ctx); + ep_desc = find_ep(serial, endpoint); + if (!ep_desc) { + /* leak the urb, something's wrong and the callers don't care */ + return urb; + } + if (usb_endpoint_xfer_int(ep_desc)) { + ep_type_name = "INT"; + usb_fill_int_urb(urb, serial->dev, + usb_sndintpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx, + ep_desc->bInterval); + } else if (usb_endpoint_xfer_bulk(ep_desc)) { + ep_type_name = "BULK"; + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx); + } else { + dev_warn(&serial->interface->dev, + "unsupported endpoint type %x\n", + ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); + usb_free_urb(urb); + return NULL; + } + dbg("%s - using urb %p for %s endpoint %x", + __func__, urb, ep_type_name, endpoint); return urb; } diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 6413d73c139c..c6830cbdc6df 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -229,7 +229,6 @@ struct ezusb_hex_record { #define keyspan_usa28_product_id 0x010f #define keyspan_usa28x_product_id 0x0110 #define keyspan_usa28xa_product_id 0x0115 -#define keyspan_usa28xb_product_id 0x0110 #define keyspan_usa49w_product_id 0x010a #define keyspan_usa49wlc_product_id 0x012a @@ -511,7 +510,6 @@ static struct usb_device_id keyspan_ids_combined[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)}, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, { } /* Terminating entry */ @@ -559,7 +557,6 @@ static struct usb_device_id keyspan_2port_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) }, { } /* Terminating entry */ }; @@ -576,6 +573,7 @@ static struct usb_serial_driver keyspan_pre_device = { .name = "keyspan_no_firm", }, .description = "Keyspan - (without firmware)", + .usb_driver = &keyspan_driver, .id_table = keyspan_pre_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -590,6 +588,7 @@ static struct usb_serial_driver keyspan_1port_device = { .name = "keyspan_1", }, .description = "Keyspan 1 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_1port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -617,6 +616,7 @@ static struct usb_serial_driver keyspan_2port_device = { .name = "keyspan_2", }, .description = "Keyspan 2 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_2port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -644,6 +644,7 @@ static struct usb_serial_driver keyspan_4port_device = { .name = "keyspan_4", }, .description = "Keyspan 4 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_4port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 5, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 126b9703bbaf..da514cb785b3 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -793,6 +793,7 @@ static struct usb_serial_driver keyspan_pda_fake_device = { .name = "keyspan_pda_pre", }, .description = "Keyspan PDA - (prerenumeration)", + .usb_driver = &keyspan_pda_driver, .id_table = id_table_fake, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -809,6 +810,7 @@ static struct usb_serial_driver xircom_pgs_fake_device = { .name = "xircom_no_firm", }, .description = "Xircom / Entregra PGS - (prerenumeration)", + .usb_driver = &keyspan_pda_driver, .id_table = id_table_fake_xircom, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -824,6 +826,7 @@ static struct usb_serial_driver keyspan_pda_device = { .name = "keyspan_pda", }, .description = "Keyspan PDA", + .usb_driver = &keyspan_pda_driver, .id_table = id_table_std, .num_interrupt_in = 1, .num_bulk_in = 0, diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 5c4b06a99ac0..b2097c45a235 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -124,6 +124,7 @@ static struct usb_serial_driver kl5kusb105d_device = { .name = "kl5kusb105d", }, .description = "KL5KUSB105D / PalmConnect", + .usb_driver = &kl5kusb105d_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 62bea0c923bd..0683b51f0932 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -110,6 +110,7 @@ static struct usb_serial_driver kobil_device = { .name = "kobil", }, .description = "KOBIL USB smart card terminal", + .usb_driver = &kobil_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 0, diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 38b1d17e06ef..4cd839b1407f 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -137,6 +137,7 @@ static struct usb_serial_driver mct_u232_device = { .name = "mct_u232", }, .description = "MCT U232", + .usb_driver = &mct_u232_driver, .id_table = id_table_combined, .num_interrupt_in = 2, .num_bulk_in = 0, diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index e55f4ed81d7b..6109c6704a73 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1605,12 +1605,21 @@ static void mos7720_shutdown(struct usb_serial *serial) usb_set_serial_data(serial, NULL); } +static struct usb_driver usb_driver = { + .name = "moschip7720", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = moschip_port_id_table, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver moschip7720_2port_driver = { .driver = { .owner = THIS_MODULE, .name = "moschip7720", }, .description = "Moschip 2 port adapter", + .usb_driver = &usb_driver, .id_table = moschip_port_id_table, .num_interrupt_in = 1, .num_bulk_in = 2, @@ -1631,13 +1640,6 @@ static struct usb_serial_driver moschip7720_2port_driver = { .read_bulk_callback = mos7720_bulk_in_callback, }; -static struct usb_driver usb_driver = { - .name = "moschip7720", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_port_id_table, -}; - static int __init moschip7720_init(void) { int retval; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 83f661403ba1..b2264a87617b 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2834,12 +2834,21 @@ static void mos7840_shutdown(struct usb_serial *serial) } +static struct usb_driver io_driver = { + .name = "mos7840", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = moschip_id_table_combined, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver moschip7840_4port_device = { .driver = { .owner = THIS_MODULE, .name = "mos7840", }, .description = DRIVER_DESC, + .usb_driver = &io_driver, .id_table = moschip_port_id_table, .num_interrupt_in = 1, //NUM_DONT_CARE,//1, #ifdef check @@ -2869,13 +2878,6 @@ static struct usb_serial_driver moschip7840_4port_device = { .read_int_callback = mos7840_interrupt_callback, }; -static struct usb_driver io_driver = { - .name = "mos7840", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_id_table_combined, -}; - /**************************************************************************** * moschip7840_init * This is called by the module subsystem, or on startup to initialize us diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index 054abee81652..90701111d746 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -119,6 +119,7 @@ static struct usb_serial_driver navman_device = { .name = "navman", }, .id_table = id_table, + .usb_driver = &navman_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index bc91d3b726fc..0216ac12a27d 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -93,6 +93,7 @@ static struct usb_serial_driver zyxel_omninet_device = { .name = "omninet", }, .description = "ZyXEL - omni.net lcd plus usb", + .usb_driver = &omninet_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 0fed43a96871..ced9f32b29d9 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -135,6 +135,7 @@ static struct usb_serial_driver option_1port_device = { .name = "option1", }, .description = "GSM modem (1-port)", + .usb_driver = &option_driver, .id_table = option_ids1, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 5dc2ac9afa90..6c083d4e2c9b 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -1118,6 +1118,7 @@ static struct usb_serial_driver pl2303_device = { .name = "pl2303", }, .id_table = id_table, + .usb_driver = &pl2303_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, .num_bulk_out = 1, diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 30b7ebc8d45d..5a03a3fc9386 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -402,6 +402,7 @@ static struct usb_serial_driver safe_device = { .name = "safe_serial", }, .id_table = id_table, + .usb_driver = &safe_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 6d8e91e00ecf..ecedd833818d 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -13,10 +13,9 @@ Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de> Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> - History: */ -#define DRIVER_VERSION "v.1.0.5" +#define DRIVER_VERSION "v.1.0.6" #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>" #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" @@ -31,14 +30,15 @@ static struct usb_device_id id_table [] = { + { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ - { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ @@ -55,14 +55,15 @@ static struct usb_device_id id_table_1port [] = { }; static struct usb_device_id id_table_3port [] = { + { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ - { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ { } @@ -81,7 +82,7 @@ static int debug; /* per port private data */ #define N_IN_URB 4 -#define N_OUT_URB 1 +#define N_OUT_URB 4 #define IN_BUFLEN 4096 #define OUT_BUFLEN 128 @@ -396,6 +397,8 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp) struct usb_serial *serial = port->serial; int i, err; struct urb *urb; + int result; + __u16 set_mode_dzero = 0x0000; portdata = usb_get_serial_port_data(port); @@ -442,6 +445,12 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp) port->tty->low_latency = 1; + /* set mode to D0 */ + result = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 0x00, 0x40, set_mode_dzero, 0, NULL, + 0, USB_CTRL_SET_TIMEOUT); + sierra_send_setup(port); return (0); @@ -614,6 +623,7 @@ static struct usb_serial_driver sierra_1port_device = { }, .description = "Sierra USB modem (1 port)", .id_table = id_table_1port, + .usb_driver = &sierra_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, .num_bulk_out = 1, @@ -642,6 +652,7 @@ static struct usb_serial_driver sierra_3port_device = { }, .description = "Sierra USB modem (3 port)", .id_table = id_table_3port, + .usb_driver = &sierra_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 3, .num_bulk_out = 3, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 83189005c6fb..4203e2b1a761 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -262,6 +262,7 @@ static struct usb_serial_driver ti_1port_device = { .name = "ti_usb_3410_5052_1", }, .description = "TI USB 3410 1 port adapter", + .usb_driver = &ti_usb_driver, .id_table = ti_id_table_3410, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -292,6 +293,7 @@ static struct usb_serial_driver ti_2port_device = { .name = "ti_usb_3410_5052_2", }, .description = "TI USB 5052 2 port adapter", + .usb_driver = &ti_usb_driver, .id_table = ti_id_table_5052, .num_interrupt_in = 1, .num_bulk_in = 2, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 716f6806cc89..6bf22a28adb8 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -59,14 +59,19 @@ static struct usb_driver usb_serial_driver = { static int debug; static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ +static spinlock_t table_lock; static LIST_HEAD(usb_serial_driver_list); struct usb_serial *usb_serial_get_by_index(unsigned index) { - struct usb_serial *serial = serial_table[index]; + struct usb_serial *serial; + + spin_lock(&table_lock); + serial = serial_table[index]; if (serial) kref_get(&serial->kref); + spin_unlock(&table_lock); return serial; } @@ -78,6 +83,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po dbg("%s %d", __FUNCTION__, num_ports); *minor = 0; + spin_lock(&table_lock); for (i = 0; i < SERIAL_TTY_MINORS; ++i) { if (serial_table[i]) continue; @@ -96,8 +102,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po dbg("%s - minor base = %d", __FUNCTION__, *minor); for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) serial_table[i] = serial; + spin_unlock(&table_lock); return serial; } + spin_unlock(&table_lock); return NULL; } @@ -110,9 +118,11 @@ static void return_serial(struct usb_serial *serial) if (serial == NULL) return; + spin_lock(&table_lock); for (i = 0; i < serial->num_ports; ++i) { serial_table[serial->minor + i] = NULL; } + spin_unlock(&table_lock); } static void destroy_serial(struct kref *kref) @@ -271,7 +281,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) { struct usb_serial_port *port = tty->driver_data; - int retval = -EINVAL; + int retval = -ENODEV; if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) goto exit; @@ -279,6 +289,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); if (!port->open_count) { + retval = -EINVAL; dbg("%s - port not opened", __FUNCTION__); goto exit; } @@ -559,15 +570,20 @@ static void port_release(struct device *dev) port_free(port); } -static void port_free(struct usb_serial_port *port) +static void kill_traffic(struct usb_serial_port *port) { usb_kill_urb(port->read_urb); - usb_free_urb(port->read_urb); usb_kill_urb(port->write_urb); - usb_free_urb(port->write_urb); usb_kill_urb(port->interrupt_in_urb); - usb_free_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); +} + +static void port_free(struct usb_serial_port *port) +{ + kill_traffic(port); + usb_free_urb(port->read_urb); + usb_free_urb(port->write_urb); + usb_free_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_out_urb); kfree(port->bulk_in_buffer); kfree(port->bulk_out_buffer); @@ -596,6 +612,39 @@ static struct usb_serial * create_serial (struct usb_device *dev, return serial; } +static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf, + struct usb_serial_driver *drv) +{ + struct usb_dynid *dynid; + + spin_lock(&drv->dynids.lock); + list_for_each_entry(dynid, &drv->dynids.list, node) { + if (usb_match_one_id(intf, &dynid->id)) { + spin_unlock(&drv->dynids.lock); + return &dynid->id; + } + } + spin_unlock(&drv->dynids.lock); + return NULL; +} + +static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv, + struct usb_interface *intf) +{ + const struct usb_device_id *id; + + id = usb_match_id(intf, drv->id_table); + if (id) { + dbg("static descriptor matches"); + goto exit; + } + id = match_dynamic_id(intf, drv); + if (id) + dbg("dynamic descriptor matches"); +exit: + return id; +} + static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) { struct list_head *p; @@ -605,11 +654,9 @@ static struct usb_serial_driver *search_serial_device(struct usb_interface *ifac /* Check if the usb id matches a known device */ list_for_each(p, &usb_serial_driver_list) { t = list_entry(p, struct usb_serial_driver, driver_list); - id = usb_match_id(iface, t->id_table); - if (id != NULL) { - dbg("descriptor matches"); + id = get_iface_id(t, iface); + if (id) return t; - } } return NULL; @@ -639,14 +686,17 @@ int usb_serial_probe(struct usb_interface *interface, int num_ports = 0; int max_endpoints; + lock_kernel(); /* guard against unloading a serial driver module */ type = search_serial_device(interface); if (!type) { + unlock_kernel(); dbg("none matched"); return -ENODEV; } serial = create_serial (dev, interface, type); if (!serial) { + unlock_kernel(); dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } @@ -656,16 +706,18 @@ int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id; if (!try_module_get(type->driver.owner)) { + unlock_kernel(); dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; } - id = usb_match_id(interface, type->id_table); + id = get_iface_id(type, interface); retval = type->probe(serial, id); module_put(type->driver.owner); if (retval) { + unlock_kernel(); dbg ("sub driver rejected device"); kfree (serial); return retval; @@ -735,6 +787,7 @@ int usb_serial_probe(struct usb_interface *interface, * properly during a later invocation of usb_serial_probe */ if (num_bulk_in == 0 || num_bulk_out == 0) { + unlock_kernel(); dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); kfree (serial); return -ENODEV; @@ -750,6 +803,7 @@ int usb_serial_probe(struct usb_interface *interface, if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; if (num_ports == 0) { + unlock_kernel(); dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n"); kfree (serial); return -EIO; @@ -760,6 +814,7 @@ int usb_serial_probe(struct usb_interface *interface, /* if this device type has a calc_num_ports function, call it */ if (type->calc_num_ports) { if (!try_module_get(type->driver.owner)) { + unlock_kernel(); dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; @@ -771,12 +826,6 @@ int usb_serial_probe(struct usb_interface *interface, num_ports = type->num_ports; } - if (get_free_serial (serial, num_ports, &minor) == NULL) { - dev_err(&interface->dev, "No more free serial devices\n"); - kfree (serial); - return -ENOMEM; - } - serial->minor = minor; serial->num_ports = num_ports; serial->num_bulk_in = num_bulk_in; @@ -791,6 +840,8 @@ int usb_serial_probe(struct usb_interface *interface, max_endpoints = max(max_endpoints, num_interrupt_out); max_endpoints = max(max_endpoints, (int)serial->num_ports); serial->num_port_pointers = max_endpoints; + unlock_kernel(); + dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints); for (i = 0; i < max_endpoints; ++i) { port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); @@ -925,6 +976,11 @@ int usb_serial_probe(struct usb_interface *interface, } } + if (get_free_serial (serial, num_ports, &minor) == NULL) { + dev_err(&interface->dev, "No more free serial devices\n"); + goto probe_error; + } + /* register all of the individual ports with the driver core */ for (i = 0; i < num_ports; ++i) { port = serial->port[i]; @@ -1002,8 +1058,11 @@ void usb_serial_disconnect(struct usb_interface *interface) if (serial) { for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; - if (port && port->tty) - tty_hangup(port->tty); + if (port) { + if (port->tty) + tty_hangup(port->tty); + kill_traffic(port); + } } /* let the last holder of this object * cause it to be cleaned up */ @@ -1040,6 +1099,7 @@ static int __init usb_serial_init(void) return -ENOMEM; /* Initialize our global data */ + spin_lock_init(&table_lock); for (i = 0; i < SERIAL_TTY_MINORS; ++i) { serial_table[i] = NULL; } @@ -1138,7 +1198,7 @@ static void fixup_generic(struct usb_serial_driver *device) set_to_generic_if_null(device, shutdown); } -int usb_serial_register(struct usb_serial_driver *driver) +int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */ { int retval; @@ -1162,7 +1222,7 @@ int usb_serial_register(struct usb_serial_driver *driver) } -void usb_serial_deregister(struct usb_serial_driver *device) +void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */ { info("USB Serial deregistering driver %s", device->description); list_del(&device->driver_list); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index b09f06096056..2f59ff226e2c 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -90,8 +90,6 @@ static struct usb_device_id id_table [] = { .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID), @@ -151,7 +149,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, @@ -189,6 +186,7 @@ static struct usb_serial_driver handspring_device = { .name = "visor", }, .description = "Handspring Visor / Palm OS", + .usb_driver = &visor_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, @@ -219,6 +217,7 @@ static struct usb_serial_driver clie_5_device = { .name = "clie_5", }, .description = "Sony Clie 5.0", + .usb_driver = &visor_driver, .id_table = clie_id_5_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, @@ -249,6 +248,7 @@ static struct usb_serial_driver clie_3_5_device = { .name = "clie_3.5", }, .description = "Sony Clie 3.5", + .usb_driver = &visor_driver, .id_table = clie_id_3_5_table, .num_interrupt_in = 0, .num_bulk_in = 1, diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h index 765118d83fb6..4ce6f62a6f39 100644 --- a/drivers/usb/serial/visor.h +++ b/drivers/usb/serial/visor.h @@ -32,7 +32,6 @@ #define PALM_TUNGSTEN_T_ID 0x0060 #define PALM_TREO_650 0x0061 #define PALM_TUNGSTEN_Z_ID 0x0031 -#define PALM_ZIRE31_ID 0x0061 #define PALM_ZIRE_ID 0x0070 #define PALM_M100_ID 0x0080 diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 5483d8564c1b..bf16e9e1d84e 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -161,6 +161,7 @@ static struct usb_serial_driver whiteheat_fake_device = { .name = "whiteheatnofirm", }, .description = "Connect Tech - WhiteHEAT - (prerenumeration)", + .usb_driver = &whiteheat_driver, .id_table = id_table_prerenumeration, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -176,6 +177,7 @@ static struct usb_serial_driver whiteheat_device = { .name = "whiteheat", }, .description = "Connect Tech - WhiteHEAT", + .usb_driver = &whiteheat_driver, .id_table = id_table_std, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, |