diff options
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/io_ti.c | 530 | ||||
-rw-r--r-- | drivers/usb/serial/option.c | 88 | ||||
-rw-r--r-- | drivers/usb/serial/qcserial.c | 15 | ||||
-rw-r--r-- | drivers/usb/serial/usb-wwan.h | 2 | ||||
-rw-r--r-- | drivers/usb/serial/usb_wwan.c | 42 | ||||
-rw-r--r-- | drivers/usb/serial/whiteheat.c | 31 |
6 files changed, 409 insertions, 299 deletions
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 0ac1b10be1f7..fce82fd79f77 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -54,8 +54,10 @@ #define TI_MODE_CONFIGURING 0 /* Device has not entered start device */ #define TI_MODE_BOOT 1 /* Staying in boot mode */ #define TI_MODE_DOWNLOAD 2 /* Made it to download mode */ -#define TI_MODE_TRANSITIONING 3 /* Currently in boot mode but - transitioning to download mode */ +#define TI_MODE_TRANSITIONING 3 /* + * Currently in boot mode but + * transitioning to download mode + */ /* read urb state */ #define EDGE_READ_URB_RUNNING 0 @@ -97,9 +99,11 @@ struct edgeport_port { __u8 shadow_mcr; __u8 shadow_lsr; __u8 lsr_mask; - __u32 ump_read_timeout; /* Number of milliseconds the UMP will - wait without data before completing - a read short */ + __u32 ump_read_timeout; /* + * Number of milliseconds the UMP will + * wait without data before completing + * a read short + */ int baud_rate; int close_pending; int lsr_event; @@ -115,8 +119,10 @@ struct edgeport_port { struct edgeport_serial { struct product_info product_info; u8 TI_I2C_Type; /* Type of I2C in UMP */ - u8 TiReadI2C; /* Set to TRUE if we have read the - I2c in Boot Mode */ + u8 TiReadI2C; /* + * Set to TRUE if we have read the + * I2c in Boot Mode + */ struct mutex es_lock; int num_ports_open; struct usb_serial *serial; @@ -223,6 +229,11 @@ static void edge_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); static void edge_send(struct usb_serial_port *port, struct tty_struct *tty); +static int do_download_mode(struct edgeport_serial *serial, + const struct firmware *fw); +static int do_boot_mode(struct edgeport_serial *serial, + const struct firmware *fw); + /* sysfs attributes */ static int edge_create_sysfs_attrs(struct usb_serial_port *port); static int edge_remove_sysfs_attrs(struct usb_serial_port *port); @@ -324,7 +335,8 @@ static int read_download_mem(struct usb_device *dev, int start_address, dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length); - /* Read in blocks of 64 bytes + /* + * Read in blocks of 64 bytes * (TI firmware can't handle more than 64 byte reads) */ while (length) { @@ -430,7 +442,6 @@ static int write_boot_mem(struct edgeport_serial *serial, return status; } - /* Write edgeport I2C memory to TI chip */ static int write_i2c_mem(struct edgeport_serial *serial, int start_address, int length, __u8 address_type, __u8 *buffer) @@ -472,8 +483,10 @@ static int write_i2c_mem(struct edgeport_serial *serial, start_address += write_length; buffer += write_length; - /* We should be aligned now -- can write - max page size bytes at a time */ + /* + * We should be aligned now -- can write max page size bytes at a + * time. + */ while (length) { if (length > EPROM_PAGE_SIZE) write_length = EPROM_PAGE_SIZE; @@ -506,7 +519,8 @@ static int write_i2c_mem(struct edgeport_serial *serial, return status; } -/* Examine the UMP DMA registers and LSR +/* + * Examine the UMP DMA registers and LSR * * Check the MSBit of the X and Y DMA byte count registers. * A zero in this bit indicates that the TX DMA buffers are empty @@ -523,9 +537,11 @@ static int tx_active(struct edgeport_port *port) if (!oedb) return -ENOMEM; - lsr = kmalloc(1, GFP_KERNEL); /* Sigh, that's right, just one byte, - as not all platforms can do DMA - from stack */ + /* + * Sigh, that's right, just one byte, as not all platforms can + * do DMA from stack + */ + lsr = kmalloc(1, GFP_KERNEL); if (!lsr) { kfree(oedb); return -ENOMEM; @@ -615,8 +631,6 @@ static int write_rom(struct edgeport_serial *serial, int start_address, return -EINVAL; } - - /* Read a descriptor header from I2C based on type */ static int get_descriptor_addr(struct edgeport_serial *serial, int desc_type, struct ti_i2c_desc *rom_desc) @@ -785,8 +799,7 @@ exit: } /* Build firmware header used for firmware update */ -static int build_i2c_fw_hdr(u8 *header, struct device *dev, - const struct firmware *fw) +static int build_i2c_fw_hdr(u8 *header, const struct firmware *fw) { __u8 *buffer; int buffer_size; @@ -797,7 +810,8 @@ static int build_i2c_fw_hdr(u8 *header, struct device *dev, struct ti_i2c_firmware_rec *firmware_rec; struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; - /* In order to update the I2C firmware we must change the type 2 record + /* + * In order to update the I2C firmware we must change the type 2 record * to type 0xF2. This will force the UMP to come up in Boot Mode. * Then while in boot mode, the driver will download the latest * firmware (padded to 15.5k) into the UMP ram. And finally when the @@ -806,8 +820,10 @@ static int build_i2c_fw_hdr(u8 *header, struct device *dev, * update the record type from 0xf2 to 0x02. */ - /* Allocate a 15.5k buffer + 2 bytes for version number - * (Firmware Record) */ + /* + * Allocate a 15.5k buffer + 2 bytes for version number (Firmware + * Record) + */ buffer_size = (((1024 * 16) - 512 ) + sizeof(struct ti_i2c_firmware_rec)); @@ -815,7 +831,7 @@ static int build_i2c_fw_hdr(u8 *header, struct device *dev, if (!buffer) return -ENOMEM; - // Set entire image of 0xffs + /* Set entire image of 0xffs */ memset(buffer, 0xff, buffer_size); /* Copy version number into firmware record */ @@ -981,32 +997,41 @@ static int check_fw_sanity(struct edgeport_serial *serial, return 0; } -/** +/* * DownloadTIFirmware - Download run-time operating firmware to the TI5052 * * This routine downloads the main operating code into the TI5052, using the * boot code already burned into E2PROM or ROM. */ -static int download_fw(struct edgeport_serial *serial, - const struct firmware *fw) +static int download_fw(struct edgeport_serial *serial) { - struct device *dev = &serial->serial->dev->dev; + struct device *dev = &serial->serial->interface->dev; int status = 0; - int start_address; - struct edge_ti_manuf_descriptor *ti_manuf_desc; struct usb_interface_descriptor *interface; - int download_cur_ver; - int download_new_ver; - struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; + const struct firmware *fw; + const char *fw_name = "edgeport/down3.bin"; + struct edgeport_fw_hdr *fw_hdr; - if (check_fw_sanity(serial, fw)) - return -EINVAL; + status = request_firmware(&fw, fw_name, dev); + if (status) { + dev_err(dev, "Failed to load image \"%s\" err %d\n", + fw_name, status); + return status; + } + + if (check_fw_sanity(serial, fw)) { + status = -EINVAL; + goto out; + } - /* If on-board version is newer, "fw_version" will be updated below. */ + fw_hdr = (struct edgeport_fw_hdr *)fw->data; + + /* If on-board version is newer, "fw_version" will be updated later. */ serial->fw_version = (fw_hdr->major_version << 8) + fw_hdr->minor_version; - /* This routine is entered by both the BOOT mode and the Download mode + /* + * This routine is entered by both the BOOT mode and the Download mode * We can determine which code is running by the reading the config * descriptor and if we have only one bulk pipe it is in boot mode */ @@ -1017,12 +1042,13 @@ static int download_fw(struct edgeport_serial *serial, status = choose_config(serial->serial->dev); if (status) - return status; + goto out; interface = &serial->serial->interface->cur_altsetting->desc; if (!interface) { dev_err(dev, "%s - no interface set, error!\n", __func__); - return -ENODEV; + status = -ENODEV; + goto out; } /* @@ -1030,190 +1056,219 @@ static int download_fw(struct edgeport_serial *serial, * if we have more than one endpoint we are definitely in download * mode */ - if (interface->bNumEndpoints > 1) + if (interface->bNumEndpoints > 1) { serial->product_info.TiMode = TI_MODE_DOWNLOAD; - else + status = do_download_mode(serial, fw); + } else { /* Otherwise we will remain in configuring mode */ serial->product_info.TiMode = TI_MODE_CONFIGURING; + status = do_boot_mode(serial, fw); + } - /********************************************************************/ - /* Download Mode */ - /********************************************************************/ - if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) { - struct ti_i2c_desc *rom_desc; +out: + release_firmware(fw); + return status; +} - dev_dbg(dev, "%s - RUNNING IN DOWNLOAD MODE\n", __func__); +static int do_download_mode(struct edgeport_serial *serial, + const struct firmware *fw) +{ + struct device *dev = &serial->serial->interface->dev; + int status = 0; + int start_address; + struct edge_ti_manuf_descriptor *ti_manuf_desc; + int download_cur_ver; + int download_new_ver; + struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; + struct ti_i2c_desc *rom_desc; - status = check_i2c_image(serial); - if (status) { - dev_dbg(dev, "%s - DOWNLOAD MODE -- BAD I2C\n", __func__); - return status; - } + dev_dbg(dev, "%s - RUNNING IN DOWNLOAD MODE\n", __func__); - /* Validate Hardware version number - * Read Manufacturing Descriptor from TI Based Edgeport - */ - ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL); - if (!ti_manuf_desc) + status = check_i2c_image(serial); + if (status) { + dev_dbg(dev, "%s - DOWNLOAD MODE -- BAD I2C\n", __func__); + return status; + } + + /* + * Validate Hardware version number + * Read Manufacturing Descriptor from TI Based Edgeport + */ + ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL); + if (!ti_manuf_desc) + return -ENOMEM; + + status = get_manuf_info(serial, (__u8 *)ti_manuf_desc); + if (status) { + kfree(ti_manuf_desc); + return status; + } + + /* Check version number of ION descriptor */ + if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) { + dev_dbg(dev, "%s - Wrong CPU Rev %d (Must be 2)\n", + __func__, ti_cpu_rev(ti_manuf_desc)); + kfree(ti_manuf_desc); + return -EINVAL; + } + + rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); + if (!rom_desc) { + kfree(ti_manuf_desc); + return -ENOMEM; + } + + /* Search for type 2 record (firmware record) */ + start_address = get_descriptor_addr(serial, + I2C_DESC_TYPE_FIRMWARE_BASIC, rom_desc); + if (start_address != 0) { + struct ti_i2c_firmware_rec *firmware_version; + u8 *record; + + dev_dbg(dev, "%s - Found Type FIRMWARE (Type 2) record\n", + __func__); + + firmware_version = kmalloc(sizeof(*firmware_version), + GFP_KERNEL); + if (!firmware_version) { + kfree(rom_desc); + kfree(ti_manuf_desc); return -ENOMEM; + } - status = get_manuf_info(serial, (__u8 *)ti_manuf_desc); + /* + * Validate version number + * Read the descriptor data + */ + status = read_rom(serial, start_address + + sizeof(struct ti_i2c_desc), + sizeof(struct ti_i2c_firmware_rec), + (__u8 *)firmware_version); if (status) { + kfree(firmware_version); + kfree(rom_desc); kfree(ti_manuf_desc); return status; } - /* Check version number of ION descriptor */ - if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) { - dev_dbg(dev, "%s - Wrong CPU Rev %d (Must be 2)\n", - __func__, ti_cpu_rev(ti_manuf_desc)); - kfree(ti_manuf_desc); - return -EINVAL; - } + /* + * Check version number of download with current + * version in I2c + */ + download_cur_ver = (firmware_version->Ver_Major << 8) + + (firmware_version->Ver_Minor); + download_new_ver = (fw_hdr->major_version << 8) + + (fw_hdr->minor_version); - rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); - if (!rom_desc) { - kfree(ti_manuf_desc); - return -ENOMEM; - } + dev_dbg(dev, "%s - >> FW Versions Device %d.%d Driver %d.%d\n", + __func__, firmware_version->Ver_Major, + firmware_version->Ver_Minor, + fw_hdr->major_version, fw_hdr->minor_version); - /* Search for type 2 record (firmware record) */ - start_address = get_descriptor_addr(serial, - I2C_DESC_TYPE_FIRMWARE_BASIC, rom_desc); - if (start_address != 0) { - struct ti_i2c_firmware_rec *firmware_version; - u8 *record; - - dev_dbg(dev, "%s - Found Type FIRMWARE (Type 2) record\n", __func__); + /* + * Check if we have an old version in the I2C and + * update if necessary + */ + if (download_cur_ver < download_new_ver) { + dev_dbg(dev, "%s - Update I2C dld from %d.%d to %d.%d\n", + __func__, + firmware_version->Ver_Major, + firmware_version->Ver_Minor, + fw_hdr->major_version, + fw_hdr->minor_version); - firmware_version = kmalloc(sizeof(*firmware_version), - GFP_KERNEL); - if (!firmware_version) { + record = kmalloc(1, GFP_KERNEL); + if (!record) { + kfree(firmware_version); kfree(rom_desc); kfree(ti_manuf_desc); return -ENOMEM; } + /* + * In order to update the I2C firmware we must + * change the type 2 record to type 0xF2. This + * will force the UMP to come up in Boot Mode. + * Then while in boot mode, the driver will + * download the latest firmware (padded to + * 15.5k) into the UMP ram. Finally when the + * device comes back up in download mode the + * driver will cause the new firmware to be + * copied from the UMP Ram to I2C and the + * firmware will update the record type from + * 0xf2 to 0x02. + */ + *record = I2C_DESC_TYPE_FIRMWARE_BLANK; - /* Validate version number - * Read the descriptor data + /* + * Change the I2C Firmware record type to + * 0xf2 to trigger an update */ - status = read_rom(serial, start_address + - sizeof(struct ti_i2c_desc), - sizeof(struct ti_i2c_firmware_rec), - (__u8 *)firmware_version); + status = write_rom(serial, start_address, + sizeof(*record), record); if (status) { + kfree(record); kfree(firmware_version); kfree(rom_desc); kfree(ti_manuf_desc); return status; } - /* Check version number of download with current - version in I2c */ - download_cur_ver = (firmware_version->Ver_Major << 8) + - (firmware_version->Ver_Minor); - download_new_ver = (fw_hdr->major_version << 8) + - (fw_hdr->minor_version); - - dev_dbg(dev, "%s - >> FW Versions Device %d.%d Driver %d.%d\n", - __func__, firmware_version->Ver_Major, - firmware_version->Ver_Minor, - fw_hdr->major_version, fw_hdr->minor_version); + /* + * verify the write -- must do this in order + * for write to complete before we do the + * hardware reset + */ + status = read_rom(serial, + start_address, + sizeof(*record), + record); + if (status) { + kfree(record); + kfree(firmware_version); + kfree(rom_desc); + kfree(ti_manuf_desc); + return status; + } - /* Check if we have an old version in the I2C and - update if necessary */ - if (download_cur_ver < download_new_ver) { - dev_dbg(dev, "%s - Update I2C dld from %d.%d to %d.%d\n", - __func__, - firmware_version->Ver_Major, - firmware_version->Ver_Minor, - fw_hdr->major_version, - fw_hdr->minor_version); - - record = kmalloc(1, GFP_KERNEL); - if (!record) { - kfree(firmware_version); - kfree(rom_desc); - kfree(ti_manuf_desc); - return -ENOMEM; - } - /* In order to update the I2C firmware we must - * change the type 2 record to type 0xF2. This - * will force the UMP to come up in Boot Mode. - * Then while in boot mode, the driver will - * download the latest firmware (padded to - * 15.5k) into the UMP ram. Finally when the - * device comes back up in download mode the - * driver will cause the new firmware to be - * copied from the UMP Ram to I2C and the - * firmware will update the record type from - * 0xf2 to 0x02. - */ - *record = I2C_DESC_TYPE_FIRMWARE_BLANK; - - /* Change the I2C Firmware record type to - 0xf2 to trigger an update */ - status = write_rom(serial, start_address, - sizeof(*record), record); - if (status) { - kfree(record); - kfree(firmware_version); - kfree(rom_desc); - kfree(ti_manuf_desc); - return status; - } - - /* verify the write -- must do this in order - * for write to complete before we do the - * hardware reset - */ - status = read_rom(serial, - start_address, - sizeof(*record), - record); - if (status) { - kfree(record); - kfree(firmware_version); - kfree(rom_desc); - kfree(ti_manuf_desc); - return status; - } - - if (*record != I2C_DESC_TYPE_FIRMWARE_BLANK) { - dev_err(dev, "%s - error resetting device\n", __func__); - kfree(record); - kfree(firmware_version); - kfree(rom_desc); - kfree(ti_manuf_desc); - return -ENODEV; - } - - dev_dbg(dev, "%s - HARDWARE RESET\n", __func__); - - /* Reset UMP -- Back to BOOT MODE */ - status = ti_vsend_sync(serial->serial->dev, - UMPC_HARDWARE_RESET, - 0, 0, NULL, 0, - TI_VSEND_TIMEOUT_DEFAULT); - - dev_dbg(dev, "%s - HARDWARE RESET return %d\n", __func__, status); - - /* return an error on purpose. */ + if (*record != I2C_DESC_TYPE_FIRMWARE_BLANK) { + dev_err(dev, "%s - error resetting device\n", + __func__); kfree(record); kfree(firmware_version); kfree(rom_desc); kfree(ti_manuf_desc); return -ENODEV; - } else { - /* Same or newer fw version is already loaded */ - serial->fw_version = download_cur_ver; } + + dev_dbg(dev, "%s - HARDWARE RESET\n", __func__); + + /* Reset UMP -- Back to BOOT MODE */ + status = ti_vsend_sync(serial->serial->dev, + UMPC_HARDWARE_RESET, + 0, 0, NULL, 0, + TI_VSEND_TIMEOUT_DEFAULT); + + dev_dbg(dev, "%s - HARDWARE RESET return %d\n", + __func__, status); + + /* return an error on purpose. */ + kfree(record); kfree(firmware_version); + kfree(rom_desc); + kfree(ti_manuf_desc); + return -ENODEV; } - /* Search for type 0xF2 record (firmware blank record) */ - else if ((start_address = get_descriptor_addr(serial, I2C_DESC_TYPE_FIRMWARE_BLANK, rom_desc)) != 0) { + /* Same or newer fw version is already loaded */ + serial->fw_version = download_cur_ver; + kfree(firmware_version); + } + /* Search for type 0xF2 record (firmware blank record) */ + else { + start_address = get_descriptor_addr(serial, + I2C_DESC_TYPE_FIRMWARE_BLANK, rom_desc); + if (start_address != 0) { #define HEADER_SIZE (sizeof(struct ti_i2c_desc) + \ - sizeof(struct ti_i2c_firmware_rec)) + sizeof(struct ti_i2c_firmware_rec)) __u8 *header; __u8 *vheader; @@ -1232,7 +1287,8 @@ static int download_fw(struct edgeport_serial *serial, return -ENOMEM; } - dev_dbg(dev, "%s - Found Type BLANK FIRMWARE (Type F2) record\n", __func__); + dev_dbg(dev, "%s - Found Type BLANK FIRMWARE (Type F2) record\n", + __func__); /* * In order to update the I2C firmware we must change @@ -1245,7 +1301,7 @@ static int download_fw(struct edgeport_serial *serial, * UMP Ram to I2C and the firmware will update the * record type from 0xf2 to 0x02. */ - status = build_i2c_fw_hdr(header, dev, fw); + status = build_i2c_fw_hdr(header, fw); if (status) { kfree(vheader); kfree(header); @@ -1254,8 +1310,10 @@ static int download_fw(struct edgeport_serial *serial, return -EINVAL; } - /* Update I2C with type 0xf2 record with correct - size and checksum */ + /* + * Update I2C with type 0xf2 record with correct + * size and checksum + */ status = write_rom(serial, start_address, HEADER_SIZE, @@ -1268,13 +1326,16 @@ static int download_fw(struct edgeport_serial *serial, return -EINVAL; } - /* verify the write -- must do this in order for - write to complete before we do the hardware reset */ + /* + * verify the write -- must do this in order for + * write to complete before we do the hardware reset + */ status = read_rom(serial, start_address, HEADER_SIZE, vheader); if (status) { - dev_dbg(dev, "%s - can't read header back\n", __func__); + dev_dbg(dev, "%s - can't read header back\n", + __func__); kfree(vheader); kfree(header); kfree(rom_desc); @@ -1282,7 +1343,8 @@ static int download_fw(struct edgeport_serial *serial, return status; } if (memcmp(vheader, header, HEADER_SIZE)) { - dev_dbg(dev, "%s - write download record failed\n", __func__); + dev_dbg(dev, "%s - write download record failed\n", + __func__); kfree(vheader); kfree(header); kfree(rom_desc); @@ -1301,26 +1363,33 @@ static int download_fw(struct edgeport_serial *serial, 0, 0, NULL, 0, TI_VSEND_TIMEOUT_FW_DOWNLOAD); - dev_dbg(dev, "%s - Update complete 0x%x\n", __func__, status); + dev_dbg(dev, "%s - Update complete 0x%x\n", __func__, + status); if (status) { dev_err(dev, "%s - UMPC_COPY_DNLD_TO_I2C failed\n", - __func__); + __func__); kfree(rom_desc); kfree(ti_manuf_desc); return status; } } - - // The device is running the download code - kfree(rom_desc); - kfree(ti_manuf_desc); - return 0; } - /********************************************************************/ - /* Boot Mode */ - /********************************************************************/ + /* The device is running the download code */ + kfree(rom_desc); + kfree(ti_manuf_desc); + return 0; +} + +static int do_boot_mode(struct edgeport_serial *serial, + const struct firmware *fw) +{ + struct device *dev = &serial->serial->interface->dev; + int status = 0; + struct edge_ti_manuf_descriptor *ti_manuf_desc; + struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; + dev_dbg(dev, "%s - RUNNING IN BOOT MODE\n", __func__); /* Configure the TI device so we can use the BULK pipes for download */ @@ -1336,8 +1405,10 @@ static int download_fw(struct edgeport_serial *serial, goto stayinbootmode; } - /* We have an ION device (I2c Must be programmed) - Determine I2C image type */ + /* + * We have an ION device (I2c Must be programmed) + * Determine I2C image type + */ if (i2c_type_bootmode(serial)) goto stayinbootmode; @@ -1349,7 +1420,8 @@ static int download_fw(struct edgeport_serial *serial, __u8 *buffer; int buffer_size; - /* Validate Hardware version number + /* + * Validate Hardware version number * Read Manufacturing Descriptor from TI Based Edgeport */ ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL); @@ -1439,7 +1511,6 @@ stayinbootmode: return 0; } - static int ti_do_config(struct edgeport_port *port, int feature, int on) { int port_number = port->port->port_number; @@ -1450,7 +1521,6 @@ static int ti_do_config(struct edgeport_port *port, int feature, int on) on, NULL, 0); } - static int restore_mcr(struct edgeport_port *port, __u8 mcr) { int status = 0; @@ -1556,7 +1626,6 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, icount->frame++; } - static void edge_interrupt_callback(struct urb *urb) { struct edgeport_serial *edge_serial = urb->context; @@ -1616,8 +1685,9 @@ static void edge_interrupt_callback(struct urb *urb) case TIUMP_INTERRUPT_CODE_LSR: lsr = map_line_status(data[1]); if (lsr & UMP_UART_LSR_DATA_MASK) { - /* Save the LSR event for bulk read - completion routine */ + /* + * Save the LSR event for bulk read completion routine + */ dev_dbg(dev, "%s - LSR Event Port %u LSR Status = %02x\n", __func__, port_number, lsr); edge_port->lsr_event = 1; @@ -1925,8 +1995,10 @@ static void edge_close(struct usb_serial_port *port) if (edge_serial == NULL || edge_port == NULL) return; - /* The bulkreadcompletion routine will check - * this flag and dump add read data */ + /* + * The bulkreadcompletion routine will check + * this flag and dump add read data + */ edge_port->close_pending = 1; usb_kill_urb(port->read_urb); @@ -2016,8 +2088,10 @@ static void edge_send(struct usb_serial_port *port, struct tty_struct *tty) } else edge_port->port->icount.tx += count; - /* wakeup any process waiting for writes to complete */ - /* there is now more room in the buffer for new writes */ + /* + * wakeup any process waiting for writes to complete + * there is now more room in the buffer for new writes + */ if (tty) tty_wakeup(tty); } @@ -2089,8 +2163,10 @@ static void edge_throttle(struct tty_struct *tty) } } - /* if we are implementing RTS/CTS, stop reads */ - /* and the Edgeport will clear the RTS line */ + /* + * if we are implementing RTS/CTS, stop reads + * and the Edgeport will clear the RTS line + */ if (C_CRTSCTS(tty)) stop_read(edge_port); @@ -2113,8 +2189,10 @@ static void edge_unthrottle(struct tty_struct *tty) dev_err(&port->dev, "%s - failed to write start character, %d\n", __func__, status); } } - /* if we are implementing RTS/CTS, restart reads */ - /* are the Edgeport will assert the RTS line */ + /* + * if we are implementing RTS/CTS, restart reads + * are the Edgeport will assert the RTS line + */ if (C_CRTSCTS(tty)) { status = restart_read(edge_port); if (status) @@ -2236,8 +2314,10 @@ static void change_port_settings(struct tty_struct *tty, restart_read(edge_port); } - /* if we are implementing XON/XOFF, set the start and stop - character in the device */ + /* + * if we are implementing XON/XOFF, set the start and stop + * character in the device + */ config->cXon = START_CHAR(tty); config->cXoff = STOP_CHAR(tty); @@ -2467,9 +2547,6 @@ static int edge_startup(struct usb_serial *serial) { struct edgeport_serial *edge_serial; int status; - const struct firmware *fw; - const char *fw_name = "edgeport/down3.bin"; - struct device *dev = &serial->interface->dev; u16 product_id; /* create our private serial structure */ @@ -2481,16 +2558,7 @@ static int edge_startup(struct usb_serial *serial) edge_serial->serial = serial; usb_set_serial_data(serial, edge_serial); - status = request_firmware(&fw, fw_name, dev); - if (status) { - dev_err(dev, "Failed to load image \"%s\" err %d\n", - fw_name, status); - kfree(edge_serial); - return status; - } - - status = download_fw(edge_serial, fw); - release_firmware(fw); + status = download_fw(edge_serial); if (status) { kfree(edge_serial); return status; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 6d1941a2396a..685fef71d3d1 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -48,7 +48,6 @@ static int option_probe(struct usb_serial *serial, const struct usb_device_id *id); static int option_attach(struct usb_serial *serial); static void option_release(struct usb_serial *serial); -static int option_send_setup(struct usb_serial_port *port); static void option_instat_callback(struct urb *urb); /* Vendor and product IDs */ @@ -234,8 +233,6 @@ static void option_instat_callback(struct urb *urb); #define QUALCOMM_VENDOR_ID 0x05C6 -#define SIERRA_VENDOR_ID 0x1199 - #define CMOTECH_VENDOR_ID 0x16d8 #define CMOTECH_PRODUCT_6001 0x6001 #define CMOTECH_PRODUCT_CMU_300 0x6002 @@ -278,6 +275,10 @@ static void option_instat_callback(struct urb *urb); #define ZTE_PRODUCT_MF622 0x0001 #define ZTE_PRODUCT_MF628 0x0015 #define ZTE_PRODUCT_MF626 0x0031 +#define ZTE_PRODUCT_ZM8620_X 0x0396 +#define ZTE_PRODUCT_ME3620_MBIM 0x0426 +#define ZTE_PRODUCT_ME3620_X 0x1432 +#define ZTE_PRODUCT_ME3620_L 0x1433 #define ZTE_PRODUCT_AC2726 0xfff1 #define ZTE_PRODUCT_MG880 0xfffd #define ZTE_PRODUCT_CDMA_TECH 0xfffe @@ -544,6 +545,18 @@ static const struct option_blacklist_info zte_mc2716_z_blacklist = { .sendsetup = BIT(1) | BIT(2) | BIT(3), }; +static const struct option_blacklist_info zte_me3620_mbim_blacklist = { + .reserved = BIT(2) | BIT(3) | BIT(4), +}; + +static const struct option_blacklist_info zte_me3620_xl_blacklist = { + .reserved = BIT(3) | BIT(4) | BIT(5), +}; + +static const struct option_blacklist_info zte_zm8620_x_blacklist = { + .reserved = BIT(3) | BIT(4) | BIT(5), +}; + static const struct option_blacklist_info huawei_cdc12_blacklist = { .reserved = BIT(1) | BIT(2), }; @@ -595,11 +608,6 @@ static const struct option_blacklist_info telit_le920_blacklist = { .reserved = BIT(1) | BIT(5), }; -static const struct option_blacklist_info sierra_mc73xx_blacklist = { - .sendsetup = BIT(0) | BIT(2), - .reserved = BIT(8) | BIT(10) | BIT(11), -}; - static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -1097,10 +1105,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ - { USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x68c0, 0xff), - .driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC73xx */ - { USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x9041, 0xff), - .driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC7305/MC7355 */ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), @@ -1591,6 +1595,14 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist }, + { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_L), + .driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist }, + { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_MBIM), + .driver_info = (kernel_ulong_t)&zte_me3620_mbim_blacklist }, + { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_X), + .driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist }, + { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ZM8620_X), + .driver_info = (kernel_ulong_t)&zte_zm8620_x_blacklist }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) }, @@ -1811,10 +1823,6 @@ static struct usb_serial_driver * const serial_drivers[] = { &option_1port_device, NULL }; -struct option_private { - u8 bInterfaceNumber; -}; - module_usb_serial_driver(serial_drivers, option_ids); static int option_probe(struct usb_serial *serial, @@ -1858,29 +1866,19 @@ static int option_attach(struct usb_serial *serial) struct usb_interface_descriptor *iface_desc; const struct option_blacklist_info *blacklist; struct usb_wwan_intf_private *data; - struct option_private *priv; data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); if (!data) return -ENOMEM; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - kfree(data); - return -ENOMEM; - } - /* Retrieve blacklist info stored at probe. */ blacklist = usb_get_serial_data(serial); iface_desc = &serial->interface->cur_altsetting->desc; - priv->bInterfaceNumber = iface_desc->bInterfaceNumber; - data->private = priv; - if (!blacklist || !test_bit(iface_desc->bInterfaceNumber, &blacklist->sendsetup)) { - data->send_setup = option_send_setup; + data->use_send_setup = 1; } spin_lock_init(&data->susp_lock); @@ -1892,9 +1890,7 @@ static int option_attach(struct usb_serial *serial) static void option_release(struct usb_serial *serial) { struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); - struct option_private *priv = intfdata->private; - kfree(priv); kfree(intfdata); } @@ -1953,40 +1949,6 @@ static void option_instat_callback(struct urb *urb) } } -/** send RTS/DTR state to the port. - * - * This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN - * CDC. -*/ -static int option_send_setup(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); - struct option_private *priv = intfdata->private; - struct usb_wwan_port_private *portdata; - int val = 0; - int res; - - portdata = usb_get_serial_port_data(port); - - if (portdata->dtr_state) - val |= 0x01; - if (portdata->rts_state) - val |= 0x02; - - res = usb_autopm_get_interface(serial->interface); - if (res) - return res; - - res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - 0x22, 0x21, val, priv->bInterfaceNumber, NULL, - 0, USB_CTRL_SET_TIMEOUT); - - usb_autopm_put_interface(serial->interface); - - return res; -} - MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index ebcec8cda858..5022fcfa0260 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -143,9 +143,11 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x0f3d, 0x68a2)}, /* Sierra Wireless MC7700 */ {DEVICE_SWI(0x114f, 0x68a2)}, /* Sierra Wireless MC7750 */ {DEVICE_SWI(0x1199, 0x68a2)}, /* Sierra Wireless MC7710 */ + {DEVICE_SWI(0x1199, 0x68c0)}, /* Sierra Wireless MC7304/MC7354 */ {DEVICE_SWI(0x1199, 0x901c)}, /* Sierra Wireless EM7700 */ {DEVICE_SWI(0x1199, 0x901f)}, /* Sierra Wireless EM7355 */ {DEVICE_SWI(0x1199, 0x9040)}, /* Sierra Wireless Modem */ + {DEVICE_SWI(0x1199, 0x9041)}, /* Sierra Wireless MC7305/MC7355 */ {DEVICE_SWI(0x1199, 0x9051)}, /* Netgear AirCard 340U */ {DEVICE_SWI(0x1199, 0x9053)}, /* Sierra Wireless Modem */ {DEVICE_SWI(0x1199, 0x9054)}, /* Sierra Wireless Modem */ @@ -153,6 +155,8 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x1199, 0x9056)}, /* Sierra Wireless Modem */ {DEVICE_SWI(0x1199, 0x9060)}, /* Sierra Wireless Modem */ {DEVICE_SWI(0x1199, 0x9061)}, /* Sierra Wireless Modem */ + {DEVICE_SWI(0x1199, 0x9070)}, /* Sierra Wireless MC74xx/EM74xx */ + {DEVICE_SWI(0x1199, 0x9071)}, /* Sierra Wireless MC74xx/EM74xx */ {DEVICE_SWI(0x413c, 0x81a2)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a3)}, /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a4)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ @@ -175,6 +179,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) __u8 nintf; __u8 ifnum; int altsetting = -1; + bool sendsetup = false; nintf = serial->dev->actconfig->desc.bNumInterfaces; dev_dbg(dev, "Num Interfaces = %d\n", nintf); @@ -286,6 +291,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) break; case 3: dev_dbg(dev, "Modem port found\n"); + sendsetup = true; break; default: /* don't claim any unsupported interface */ @@ -337,17 +343,25 @@ done: } } + if (!retval) + usb_set_serial_data(serial, (void *)(unsigned long)sendsetup); + return retval; } static int qc_attach(struct usb_serial *serial) { struct usb_wwan_intf_private *data; + bool sendsetup; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + sendsetup = !!(unsigned long)(usb_get_serial_data(serial)); + if (sendsetup) + data->use_send_setup = 1; + spin_lock_init(&data->susp_lock); usb_set_serial_data(serial, data); @@ -374,6 +388,7 @@ static struct usb_serial_driver qcdevice = { .probe = qcprobe, .open = usb_wwan_open, .close = usb_wwan_close, + .dtr_rts = usb_wwan_dtr_rts, .write = usb_wwan_write, .write_room = usb_wwan_write_room, .chars_in_buffer = usb_wwan_chars_in_buffer, diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h index f22dff58b587..44b25c08c68a 100644 --- a/drivers/usb/serial/usb-wwan.h +++ b/drivers/usb/serial/usb-wwan.h @@ -34,9 +34,9 @@ extern int usb_wwan_resume(struct usb_serial *serial); struct usb_wwan_intf_private { spinlock_t susp_lock; unsigned int suspended:1; + unsigned int use_send_setup:1; int in_flight; unsigned int open_ports; - int (*send_setup) (struct usb_serial_port *port); void *private; }; diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 825305cb71d9..be9cb61b4d19 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -36,6 +36,40 @@ #include <linux/serial.h> #include "usb-wwan.h" +/* + * Generate DTR/RTS signals on the port using the SET_CONTROL_LINE_STATE request + * in CDC ACM. + */ +static int usb_wwan_send_setup(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct usb_wwan_port_private *portdata; + int val = 0; + int ifnum; + int res; + + portdata = usb_get_serial_port_data(port); + + if (portdata->dtr_state) + val |= 0x01; + if (portdata->rts_state) + val |= 0x02; + + ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; + + res = usb_autopm_get_interface(serial->interface); + if (res) + return res; + + res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + 0x22, 0x21, val, ifnum, NULL, 0, + USB_CTRL_SET_TIMEOUT); + + usb_autopm_put_interface(port->serial->interface); + + return res; +} + void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) { struct usb_wwan_port_private *portdata; @@ -43,7 +77,7 @@ void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) intfdata = usb_get_serial_data(port->serial); - if (!intfdata->send_setup) + if (!intfdata->use_send_setup) return; portdata = usb_get_serial_port_data(port); @@ -51,7 +85,7 @@ void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) portdata->rts_state = on; portdata->dtr_state = on; - intfdata->send_setup(port); + usb_wwan_send_setup(port); } EXPORT_SYMBOL(usb_wwan_dtr_rts); @@ -84,7 +118,7 @@ int usb_wwan_tiocmset(struct tty_struct *tty, portdata = usb_get_serial_port_data(port); intfdata = usb_get_serial_data(port->serial); - if (!intfdata->send_setup) + if (!intfdata->use_send_setup) return -EINVAL; /* FIXME: what locks portdata fields ? */ @@ -97,7 +131,7 @@ int usb_wwan_tiocmset(struct tty_struct *tty, portdata->rts_state = 0; if (clear & TIOCM_DTR) portdata->dtr_state = 0; - return intfdata->send_setup(port); + return usb_wwan_send_setup(port); } EXPORT_SYMBOL(usb_wwan_tiocmset); diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 6c3734d2b45a..d3ea90bef84d 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -80,6 +80,8 @@ static int whiteheat_firmware_download(struct usb_serial *serial, static int whiteheat_firmware_attach(struct usb_serial *serial); /* function prototypes for the Connect Tech WhiteHEAT serial converter */ +static int whiteheat_probe(struct usb_serial *serial, + const struct usb_device_id *id); static int whiteheat_attach(struct usb_serial *serial); static void whiteheat_release(struct usb_serial *serial); static int whiteheat_port_probe(struct usb_serial_port *port); @@ -116,6 +118,7 @@ static struct usb_serial_driver whiteheat_device = { .description = "Connect Tech - WhiteHEAT", .id_table = id_table_std, .num_ports = 4, + .probe = whiteheat_probe, .attach = whiteheat_attach, .release = whiteheat_release, .port_probe = whiteheat_port_probe, @@ -217,6 +220,34 @@ static int whiteheat_firmware_attach(struct usb_serial *serial) /***************************************************************************** * Connect Tech's White Heat serial driver functions *****************************************************************************/ + +static int whiteheat_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + size_t num_bulk_in = 0; + size_t num_bulk_out = 0; + size_t min_num_bulk; + unsigned int i; + + iface_desc = serial->interface->cur_altsetting; + + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { + endpoint = &iface_desc->endpoint[i].desc; + if (usb_endpoint_is_bulk_in(endpoint)) + ++num_bulk_in; + if (usb_endpoint_is_bulk_out(endpoint)) + ++num_bulk_out; + } + + min_num_bulk = COMMAND_PORT + 1; + if (num_bulk_in < min_num_bulk || num_bulk_out < min_num_bulk) + return -ENODEV; + + return 0; +} + static int whiteheat_attach(struct usb_serial *serial) { struct usb_serial_port *command_port; |