diff options
author | Greg Kroah-Hartman | 2015-10-22 18:25:45 -0700 |
---|---|---|
committer | Greg Kroah-Hartman | 2015-10-22 18:25:45 -0700 |
commit | f5ee0557c2058226a0d71fd0b22fe02c7de3b021 (patch) | |
tree | d0d555b8dab9b52f716504b4136d0bf4d9fdbf2e | |
parent | 9e43643b11695911bb1dd585d9a9f758a5ad4d89 (diff) | |
parent | 92944c4520edd35a060cfbdaa7431d4e3c3ebd56 (diff) |
Merge tag 'usb-serial-4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next
Johan writes:
USB-serial updates for v4.4-rc1
These updates generalise the option DTR/RTS handling so that all
usb-wwan-based drivers can use it. This is specifically needed by some
Sierra modems, which can now all be handled by qcserial again.
Included are also some clean ups of the io_ti firmware handling.
Signed-off-by: Johan Hovold <johan@kernel.org>
-rw-r--r-- | drivers/usb/serial/io_ti.c | 530 | ||||
-rw-r--r-- | drivers/usb/serial/option.c | 64 | ||||
-rw-r--r-- | drivers/usb/serial/qcserial.c | 13 | ||||
-rw-r--r-- | drivers/usb/serial/usb-wwan.h | 2 | ||||
-rw-r--r-- | drivers/usb/serial/usb_wwan.c | 42 |
5 files changed, 352 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 6956c4f62216..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 @@ -611,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) }, @@ -1113,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), @@ -1835,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, @@ -1882,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); @@ -1916,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); } @@ -1977,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..f224820f7652 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 */ @@ -175,6 +177,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 +289,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 +341,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 +386,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); |