diff options
Diffstat (limited to 'drivers/usb/serial/io_ti.c')
| -rw-r--r-- | drivers/usb/serial/io_ti.c | 1271 |
1 files changed, 706 insertions, 565 deletions
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 60054e72b75b..7d0584b2a234 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Edgeport USB Serial Converter driver * * Copyright (C) 2000-2002 Inside Out Networks, All rights reserved. * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * * Supports the following devices: * EP/1 EP/2 EP/4 EP/21 EP/22 EP/221 EP/42 EP/421 WATCHPORT * @@ -20,7 +16,6 @@ #include <linux/kernel.h> #include <linux/jiffies.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -29,6 +24,7 @@ #include <linux/spinlock.h> #include <linux/mutex.h> #include <linux/serial.h> +#include <linux/swab.h> #include <linux/kfifo.h> #include <linux/ioctl.h> #include <linux/firmware.h> @@ -54,56 +50,79 @@ #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 #define EDGE_READ_URB_STOPPING 1 #define EDGE_READ_URB_STOPPED 2 -#define EDGE_CLOSING_WAIT 4000 /* in .01 sec */ - -#define EDGE_OUT_BUF_SIZE 1024 - /* Product information read from the Edgeport */ struct product_info { int TiMode; /* Current TI Mode */ - __u8 hardware_type; /* Type of hardware */ -} __attribute__((packed)); + u8 hardware_type; /* Type of hardware */ +} __packed; + +/* + * Edgeport firmware header + * + * "build_number" has been set to 0 in all three of the images I have + * seen, and Digi Tech Support suggests that it is safe to ignore it. + * + * "length" is the number of bytes of actual data following the header. + * + * "checksum" is the low order byte resulting from adding the values of + * all the data bytes. + */ +struct edgeport_fw_hdr { + u8 major_version; + u8 minor_version; + __le16 build_number; + __le16 length; + u8 checksum; +} __packed; struct edgeport_port { - __u16 uart_base; - __u16 dma_address; - __u8 shadow_msr; - __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 */ + u16 uart_base; + u16 dma_address; + u8 shadow_msr; + 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 + */ int baud_rate; int close_pending; int lsr_event; struct edgeport_serial *edge_serial; struct usb_serial_port *port; - __u8 bUartMode; /* Port type, 0: RS232, etc. */ + u8 bUartMode; /* Port type, 0: RS232, etc. */ spinlock_t ep_lock; int ep_read_urb_state; int ep_write_urb_in_use; - struct kfifo write_fifo; }; 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; + struct delayed_work heartbeat_work; + int fw_version; + bool use_heartbeat; }; @@ -147,6 +166,7 @@ static const struct usb_device_id edgeport_2port_id_table[] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8S) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416B) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_E5805A) }, { } }; @@ -185,16 +205,12 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8S) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416B) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_E5805A) }, { } }; MODULE_DEVICE_TABLE(usb, id_table_combined); -static unsigned char OperationalMajorVersion; -static unsigned char OperationalMinorVersion; -static unsigned short OperationalBuildNumber; - -static int closing_wait = EDGE_CLOSING_WAIT; static bool ignore_cpu_rev; static int default_uart_mode; /* RS232 */ @@ -205,16 +221,42 @@ static void stop_read(struct edgeport_port *edge_port); static int restart_read(struct edgeport_port *edge_port); static void edge_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios); + struct usb_serial_port *port, + const 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); +/* + * Some release of Edgeport firmware "down3.bin" after version 4.80 + * introduced code to automatically disconnect idle devices on some + * Edgeport models after periods of inactivity, typically ~60 seconds. + * This occurs without regard to whether ports on the device are open + * or not. Digi International Tech Support suggested: + * + * 1. Adding driver "heartbeat" code to reset the firmware timer by + * requesting a descriptor record every 15 seconds, which should be + * effective with newer firmware versions that require it, and benign + * with older versions that do not. In practice 40 seconds seems often + * enough. + * 2. The heartbeat code is currently required only on Edgeport/416 models. + */ +#define FW_HEARTBEAT_VERSION_CUTOFF ((4 << 8) + 80) +#define FW_HEARTBEAT_SECS 40 + +/* Timeouts in msecs: firmware downloads take longer */ +#define TI_VSEND_TIMEOUT_DEFAULT 1000 +#define TI_VSEND_TIMEOUT_FW_DOWNLOAD 10000 -static int ti_vread_sync(struct usb_device *dev, __u8 request, - __u16 value, __u16 index, u8 *data, int size) +static int ti_vread_sync(struct usb_device *dev, u8 request, u16 value, + u16 index, void *data, int size) { int status; @@ -224,51 +266,51 @@ static int ti_vread_sync(struct usb_device *dev, __u8 request, if (status < 0) return status; if (status != size) { - dev_dbg(&dev->dev, "%s - wanted to write %d, but only wrote %d\n", + dev_dbg(&dev->dev, "%s - wanted to read %d, but only read %d\n", __func__, size, status); return -ECOMM; } return 0; } -static int ti_vsend_sync(struct usb_device *dev, __u8 request, - __u16 value, __u16 index, u8 *data, int size) +static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value, + u16 index, void *data, int size, int timeout) { int status; status = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT), - value, index, data, size, 1000); + value, index, data, size, timeout); if (status < 0) return status; - if (status != size) { - dev_dbg(&dev->dev, "%s - wanted to write %d, but only wrote %d\n", - __func__, size, status); - return -ECOMM; - } + return 0; } -static int send_cmd(struct usb_device *dev, __u8 command, - __u8 moduleid, __u16 value, u8 *data, - int size) +static int read_port_cmd(struct usb_serial_port *port, u8 command, u16 value, + void *data, int size) +{ + return ti_vread_sync(port->serial->dev, command, value, + UMPM_UART1_PORT + port->port_number, + data, size); +} + +static int send_port_cmd(struct usb_serial_port *port, u8 command, u16 value, + void *data, int size) { - return ti_vsend_sync(dev, command, value, moduleid, data, size); + return ti_vsend_sync(port->serial->dev, command, value, + UMPM_UART1_PORT + port->port_number, + data, size, TI_VSEND_TIMEOUT_DEFAULT); } /* clear tx/rx buffers and fifo in TI UMP */ -static int purge_port(struct usb_serial_port *port, __u16 mask) +static int purge_port(struct usb_serial_port *port, u16 mask) { int port_number = port->port_number; dev_dbg(&port->dev, "%s - port %d, mask %x\n", __func__, port_number, mask); - return send_cmd(port->serial->dev, - UMPC_PURGE_PORT, - (__u8)(UMPM_UART1_PORT + port_number), - mask, - NULL, - 0); + return send_port_cmd(port, UMPC_PURGE_PORT, mask, NULL, 0); } /** @@ -280,30 +322,35 @@ static int purge_port(struct usb_serial_port *port, __u16 mask) * @buffer: pointer to input data buffer */ static int read_download_mem(struct usb_device *dev, int start_address, - int length, __u8 address_type, __u8 *buffer) + int length, u8 address_type, u8 *buffer) { int status = 0; - __u8 read_length; - __be16 be_start_address; + u8 read_length; + u16 be_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) { if (length > 64) read_length = 64; else - read_length = (__u8)length; + read_length = (u8)length; if (read_length > 1) { dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length); } - be_start_address = cpu_to_be16(start_address); + /* + * NOTE: Must use swab as wIndex is sent in little-endian + * byte order regardless of host byte order. + */ + be_start_address = swab16((u16)start_address); status = ti_vread_sync(dev, UMPC_MEMORY_READ, - (__u16)address_type, - (__force __u16)be_start_address, + (u16)address_type, + be_start_address, buffer, read_length); if (status) { @@ -324,7 +371,7 @@ static int read_download_mem(struct usb_device *dev, int start_address, } static int read_ram(struct usb_device *dev, int start_address, - int length, __u8 *buffer) + int length, u8 *buffer) { return read_download_mem(dev, start_address, length, DTK_ADDR_SPACE_XDATA, buffer); @@ -332,7 +379,7 @@ static int read_ram(struct usb_device *dev, int start_address, /* Read edgeport memory to a given block */ static int read_boot_mem(struct edgeport_serial *serial, - int start_address, int length, __u8 *buffer) + int start_address, int length, u8 *buffer) { int status = 0; int i; @@ -340,7 +387,7 @@ static int read_boot_mem(struct edgeport_serial *serial, for (i = 0; i < length; i++) { status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ, serial->TI_I2C_Type, - (__u16)(start_address+i), &buffer[i], 0x01); + (u16)(start_address+i), &buffer[i], 0x01); if (status) { dev_dbg(&serial->serial->dev->dev, "%s - ERROR %x\n", __func__, status); return status; @@ -358,7 +405,7 @@ static int read_boot_mem(struct edgeport_serial *serial, /* Write given block to TI EPROM memory */ static int write_boot_mem(struct edgeport_serial *serial, - int start_address, int length, __u8 *buffer) + int start_address, int length, u8 *buffer) { int status = 0; int i; @@ -367,11 +414,9 @@ static int write_boot_mem(struct edgeport_serial *serial, /* Must do a read before write */ if (!serial->TiReadI2C) { temp = kmalloc(1, GFP_KERNEL); - if (!temp) { - dev_err(&serial->serial->dev->dev, - "%s - out of memory\n", __func__); + if (!temp) return -ENOMEM; - } + status = read_boot_mem(serial, 0, 1, temp); kfree(temp); if (status) @@ -379,9 +424,9 @@ static int write_boot_mem(struct edgeport_serial *serial, } for (i = 0; i < length; ++i) { - status = ti_vsend_sync(serial->serial->dev, - UMPC_MEMORY_WRITE, buffer[i], - (__u16)(i + start_address), NULL, 0); + status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, + buffer[i], (u16)(i + start_address), NULL, + 0, TI_VSEND_TIMEOUT_DEFAULT); if (status) return status; } @@ -392,15 +437,14 @@ 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) + int start_address, int length, u8 address_type, u8 *buffer) { struct device *dev = &serial->serial->dev->dev; int status = 0; int write_length; - __be16 be_start_address; + u16 be_start_address; /* We can only send a maximum of 1 aligned byte page at a time */ @@ -415,12 +459,16 @@ static int write_i2c_mem(struct edgeport_serial *serial, __func__, start_address, write_length); usb_serial_debug_data(dev, __func__, write_length, buffer); - /* Write first page */ - be_start_address = cpu_to_be16(start_address); - status = ti_vsend_sync(serial->serial->dev, - UMPC_MEMORY_WRITE, (__u16)address_type, - (__force __u16)be_start_address, - buffer, write_length); + /* + * Write first page. + * + * NOTE: Must use swab as wIndex is sent in little-endian byte order + * regardless of host byte order. + */ + be_start_address = swab16((u16)start_address); + status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, + (u16)address_type, be_start_address, + buffer, write_length, TI_VSEND_TIMEOUT_DEFAULT); if (status) { dev_dbg(dev, "%s - ERROR %d\n", __func__, status); return status; @@ -430,8 +478,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; @@ -442,12 +492,16 @@ static int write_i2c_mem(struct edgeport_serial *serial, __func__, start_address, write_length); usb_serial_debug_data(dev, __func__, write_length, buffer); - /* Write next page */ - be_start_address = cpu_to_be16(start_address); + /* + * Write next page. + * + * NOTE: Must use swab as wIndex is sent in little-endian byte + * order regardless of host byte order. + */ + be_start_address = swab16((u16)start_address); status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, - (__u16)address_type, - (__force __u16)be_start_address, - buffer, write_length); + (u16)address_type, be_start_address, buffer, + write_length, TI_VSEND_TIMEOUT_DEFAULT); if (status) { dev_err(dev, "%s - ERROR %d\n", __func__, status); return status; @@ -460,7 +514,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 @@ -470,18 +525,18 @@ static int tx_active(struct edgeport_port *port) { int status; struct out_endpoint_desc_block *oedb; - __u8 *lsr; + u8 *lsr; int bytes_left = 0; oedb = kmalloc(sizeof(*oedb), GFP_KERNEL); - if (!oedb) { - dev_err(&port->port->dev, "%s - out of memory\n", __func__); + 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; @@ -541,7 +596,7 @@ static int choose_config(struct usb_device *dev) } static int read_rom(struct edgeport_serial *serial, - int start_address, int length, __u8 *buffer) + int start_address, int length, u8 *buffer) { int status; @@ -559,7 +614,7 @@ static int read_rom(struct edgeport_serial *serial, } static int write_rom(struct edgeport_serial *serial, int start_address, - int length, __u8 *buffer) + int length, u8 *buffer) { if (serial->product_info.TiMode == TI_MODE_BOOT) return write_boot_mem(serial, start_address, length, @@ -571,8 +626,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) @@ -586,15 +639,15 @@ static int get_descriptor_addr(struct edgeport_serial *serial, status = read_rom(serial, start_address, sizeof(struct ti_i2c_desc), - (__u8 *)rom_desc); + (u8 *)rom_desc); if (status) return 0; if (rom_desc->Type == desc_type) return start_address; - start_address = start_address + sizeof(struct ti_i2c_desc) - + rom_desc->Size; + start_address = start_address + sizeof(struct ti_i2c_desc) + + le16_to_cpu(rom_desc->Size); } while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type); @@ -602,13 +655,13 @@ static int get_descriptor_addr(struct edgeport_serial *serial, } /* Validate descriptor checksum */ -static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer) +static int valid_csum(struct ti_i2c_desc *rom_desc, u8 *buffer) { - __u16 i; - __u8 cs = 0; + u16 i; + u8 cs = 0; - for (i = 0; i < rom_desc->Size; i++) - cs = (__u8)(cs + buffer[i]); + for (i = 0; i < le16_to_cpu(rom_desc->Size); i++) + cs = (u8)(cs + buffer[i]); if (cs != rom_desc->CheckSum) { pr_debug("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs); @@ -624,18 +677,15 @@ static int check_i2c_image(struct edgeport_serial *serial) int status = 0; struct ti_i2c_desc *rom_desc; int start_address = 2; - __u8 *buffer; - __u16 ttype; + u8 *buffer; + u16 ttype; rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); - if (!rom_desc) { - dev_err(dev, "%s - out of memory\n", __func__); + if (!rom_desc) return -ENOMEM; - } + buffer = kmalloc(TI_MAX_I2C_SIZE, GFP_KERNEL); if (!buffer) { - dev_err(dev, "%s - out of memory when allocating buffer\n", - __func__); kfree(rom_desc); return -ENOMEM; } @@ -656,12 +706,12 @@ static int check_i2c_image(struct edgeport_serial *serial) status = read_rom(serial, start_address, sizeof(struct ti_i2c_desc), - (__u8 *)rom_desc); + (u8 *)rom_desc); if (status) break; if ((start_address + sizeof(struct ti_i2c_desc) + - rom_desc->Size) > TI_MAX_I2C_SIZE) { + le16_to_cpu(rom_desc->Size)) > TI_MAX_I2C_SIZE) { status = -ENODEV; dev_dbg(dev, "%s - structure too big, erroring out.\n", __func__); break; @@ -676,7 +726,8 @@ static int check_i2c_image(struct edgeport_serial *serial) /* Read the descriptor data */ status = read_rom(serial, start_address + sizeof(struct ti_i2c_desc), - rom_desc->Size, buffer); + le16_to_cpu(rom_desc->Size), + buffer); if (status) break; @@ -685,7 +736,7 @@ static int check_i2c_image(struct edgeport_serial *serial) break; } start_address = start_address + sizeof(struct ti_i2c_desc) + - rom_desc->Size; + le16_to_cpu(rom_desc->Size); } while ((rom_desc->Type != I2C_DESC_TYPE_ION) && (start_address < TI_MAX_I2C_SIZE)); @@ -700,7 +751,7 @@ out: return status; } -static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer) +static int get_manuf_info(struct edgeport_serial *serial, u8 *buffer) { int status; int start_address; @@ -709,10 +760,9 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer) struct device *dev = &serial->serial->dev->dev; rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); - if (!rom_desc) { - dev_err(dev, "%s - out of memory\n", __func__); + if (!rom_desc) return -ENOMEM; - } + start_address = get_descriptor_addr(serial, I2C_DESC_TYPE_ION, rom_desc); @@ -724,7 +774,7 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer) /* Read the descriptor data */ status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc), - rom_desc->Size, buffer); + le16_to_cpu(rom_desc->Size), buffer); if (status) goto exit; @@ -744,20 +794,19 @@ exit: } /* Build firmware header used for firmware update */ -static int build_i2c_fw_hdr(__u8 *header, struct device *dev) +static int build_i2c_fw_hdr(u8 *header, const struct firmware *fw) { - __u8 *buffer; + u8 *buffer; int buffer_size; int i; - int err; - __u8 cs = 0; + u8 cs = 0; struct ti_i2c_desc *i2c_header; struct ti_i2c_image_header *img_header; struct ti_i2c_firmware_rec *firmware_rec; - const struct firmware *fw; - const char *fw_name = "edgeport/down3.bin"; + 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 @@ -766,38 +815,25 @@ 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)); buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!buffer) { - dev_err(dev, "%s - out of memory\n", __func__); + if (!buffer) return -ENOMEM; - } - // Set entire image of 0xffs + /* Set entire image of 0xffs */ memset(buffer, 0xff, buffer_size); - err = request_firmware(&fw, fw_name, dev); - if (err) { - dev_err(dev, "Failed to load image \"%s\" err %d\n", - fw_name, err); - kfree(buffer); - return err; - } - - /* Save Download Version Number */ - OperationalMajorVersion = fw->data[0]; - OperationalMinorVersion = fw->data[1]; - OperationalBuildNumber = fw->data[2] | (fw->data[3] << 8); - /* Copy version number into firmware record */ firmware_rec = (struct ti_i2c_firmware_rec *)buffer; - firmware_rec->Ver_Major = OperationalMajorVersion; - firmware_rec->Ver_Minor = OperationalMinorVersion; + firmware_rec->Ver_Major = fw_hdr->major_version; + firmware_rec->Ver_Minor = fw_hdr->minor_version; /* Pointer to fw_down memory image */ img_header = (struct ti_i2c_image_header *)&fw->data[4]; @@ -806,10 +842,8 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) &fw->data[4 + sizeof(struct ti_i2c_image_header)], le16_to_cpu(img_header->Length)); - release_firmware(fw); - for (i=0; i < buffer_size; i++) { - cs = (__u8)(cs + buffer[i]); + cs = (u8)(cs + buffer[i]); } kfree(buffer); @@ -819,10 +853,10 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) firmware_rec = (struct ti_i2c_firmware_rec*)i2c_header->Data; i2c_header->Type = I2C_DESC_TYPE_FIRMWARE_BLANK; - i2c_header->Size = (__u16)buffer_size; + i2c_header->Size = cpu_to_le16(buffer_size); i2c_header->CheckSum = cs; - firmware_rec->Ver_Major = OperationalMajorVersion; - firmware_rec->Ver_Minor = OperationalMinorVersion; + firmware_rec->Ver_Major = fw_hdr->major_version; + firmware_rec->Ver_Minor = fw_hdr->minor_version; return 0; } @@ -835,10 +869,8 @@ static int i2c_type_bootmode(struct edgeport_serial *serial) u8 *data; data = kmalloc(1, GFP_KERNEL); - if (!data) { - dev_err(dev, "%s - out of memory\n", __func__); + if (!data) return -ENOMEM; - } /* Try to read type 2 */ status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ, @@ -887,7 +919,7 @@ static int bulk_xfer(struct usb_serial *serial, void *buffer, } /* Download given firmware image to the device (IN BOOT MODE) */ -static int download_code(struct edgeport_serial *serial, __u8 *image, +static int download_code(struct edgeport_serial *serial, u8 *image, int image_length) { int status = 0; @@ -925,7 +957,42 @@ static int ti_cpu_rev(struct edge_ti_manuf_descriptor *desc) return TI_GET_CPU_REVISION(desc->CpuRev_BoardRev); } -/** +static int check_fw_sanity(struct edgeport_serial *serial, + const struct firmware *fw) +{ + u16 length_total; + u8 checksum = 0; + int pos; + struct device *dev = &serial->serial->interface->dev; + struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; + + if (fw->size < sizeof(struct edgeport_fw_hdr)) { + dev_err(dev, "incomplete fw header\n"); + return -EINVAL; + } + + length_total = le16_to_cpu(fw_hdr->length) + + sizeof(struct edgeport_fw_hdr); + + if (fw->size != length_total) { + dev_err(dev, "bad fw size (expected: %u, got: %zu)\n", + length_total, fw->size); + return -EINVAL; + } + + for (pos = sizeof(struct edgeport_fw_hdr); pos < fw->size; ++pos) + checksum += fw->data[pos]; + + if (checksum != fw_hdr->checksum) { + dev_err(dev, "bad fw checksum (expected: 0x%x, got: 0x%x)\n", + fw_hdr->checksum, checksum); + return -EINVAL; + } + + return 0; +} + +/* * DownloadTIFirmware - Download run-time operating firmware to the TI5052 * * This routine downloads the main operating code into the TI5052, using the @@ -933,15 +1000,33 @@ static int ti_cpu_rev(struct edge_ti_manuf_descriptor *desc) */ 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; + const struct firmware *fw; + const char *fw_name = "edgeport/down3.bin"; + struct edgeport_fw_hdr *fw_hdr; - /* This routine is entered by both the BOOT mode and the Download mode + 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; + } + + 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 * 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 */ @@ -952,12 +1037,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; } /* @@ -965,198 +1051,224 @@ 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) { - dev_err(dev, "%s - out of memory.\n", __func__); + 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; - } - - rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); - if (!rom_desc) { - dev_err(dev, "%s - out of memory.\n", __func__); - kfree(ti_manuf_desc); - return -ENOMEM; - } + /* + * 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); - /* 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 - >> 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); - 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) { - dev_err(dev, "%s - out of memory.\n", __func__); + 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 = (OperationalMajorVersion << 8) + - (OperationalMinorVersion); + /* + * 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; + } - dev_dbg(dev, "%s - >> FW Versions Device %d.%d Driver %d.%d\n", - __func__, firmware_version->Ver_Major, - firmware_version->Ver_Minor, - OperationalMajorVersion, - OperationalMinorVersion); - - /* 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, - OperationalMajorVersion, - OperationalMinorVersion); - - record = kmalloc(1, GFP_KERNEL); - if (!record) { - dev_err(dev, "%s - out of memory.\n", - __func__); - 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); - - 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; } + + 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)) - __u8 *header; - __u8 *vheader; + sizeof(struct ti_i2c_firmware_rec)) + u8 *header; + u8 *vheader; header = kmalloc(HEADER_SIZE, GFP_KERNEL); if (!header) { - dev_err(dev, "%s - out of memory.\n", __func__); kfree(rom_desc); kfree(ti_manuf_desc); return -ENOMEM; @@ -1164,14 +1276,14 @@ static int download_fw(struct edgeport_serial *serial) vheader = kmalloc(HEADER_SIZE, GFP_KERNEL); if (!vheader) { - dev_err(dev, "%s - out of memory.\n", __func__); kfree(header); kfree(rom_desc); kfree(ti_manuf_desc); 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 @@ -1184,7 +1296,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); + status = build_i2c_fw_hdr(header, fw); if (status) { kfree(vheader); kfree(header); @@ -1193,8 +1305,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, @@ -1207,13 +1321,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); @@ -1221,7 +1338,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); @@ -1236,28 +1354,37 @@ static int download_fw(struct edgeport_serial *serial) /* Tell firmware to copy download image into I2C */ status = ti_vsend_sync(serial->serial->dev, - UMPC_COPY_DNLD_TO_I2C, 0, 0, NULL, 0); + UMPC_COPY_DNLD_TO_I2C, + 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 */ @@ -1273,8 +1400,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; @@ -1282,22 +1411,19 @@ static int download_fw(struct edgeport_serial *serial) if (!check_i2c_image(serial)) { struct ti_i2c_image_header *header; int i; - __u8 cs = 0; - __u8 *buffer; + u8 cs = 0; + u8 *buffer; int buffer_size; - int err; - const struct firmware *fw; - const char *fw_name = "edgeport/down3.bin"; - /* 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); - if (!ti_manuf_desc) { - dev_err(dev, "%s - out of memory.\n", __func__); + if (!ti_manuf_desc) return -ENOMEM; - } - status = get_manuf_info(serial, (__u8 *)ti_manuf_desc); + + status = get_manuf_info(serial, (u8 *)ti_manuf_desc); if (status) { kfree(ti_manuf_desc); goto stayinbootmode; @@ -1331,38 +1457,29 @@ static int download_fw(struct edgeport_serial *serial) buffer_size = (((1024 * 16) - 512) + sizeof(struct ti_i2c_image_header)); buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!buffer) { - dev_err(dev, "%s - out of memory\n", __func__); + if (!buffer) return -ENOMEM; - } /* Initialize the buffer to 0xff (pad the buffer) */ memset(buffer, 0xff, buffer_size); - - err = request_firmware(&fw, fw_name, dev); - if (err) { - dev_err(dev, "Failed to load image \"%s\" err %d\n", - fw_name, err); - kfree(buffer); - return err; - } memcpy(buffer, &fw->data[4], fw->size - 4); - release_firmware(fw); for (i = sizeof(struct ti_i2c_image_header); i < buffer_size; i++) { - cs = (__u8)(cs + buffer[i]); + cs = (u8)(cs + buffer[i]); } header = (struct ti_i2c_image_header *)buffer; /* update length and checksum after padding */ - header->Length = cpu_to_le16((__u16)(buffer_size - + header->Length = cpu_to_le16((u16)(buffer_size - sizeof(struct ti_i2c_image_header))); header->CheckSum = cs; /* Download the operational code */ - dev_dbg(dev, "%s - Downloading operational code image (TI UMP)\n", __func__); + dev_dbg(dev, "%s - Downloading operational code image version %d.%d (TI UMP)\n", + __func__, + fw_hdr->major_version, fw_hdr->minor_version); status = download_code(serial, buffer, buffer_size); kfree(buffer); @@ -1377,8 +1494,7 @@ static int download_fw(struct edgeport_serial *serial) dev_dbg(dev, "%s - Download successful -- Device rebooting...\n", __func__); - /* return an error on purpose */ - return -ENODEV; + return 1; } stayinbootmode: @@ -1386,22 +1502,17 @@ stayinbootmode: dev_dbg(dev, "%s - STAYING IN BOOT MODE\n", __func__); serial->product_info.TiMode = TI_MODE_BOOT; - return 0; + return 1; } - static int ti_do_config(struct edgeport_port *port, int feature, int on) { - int port_number = port->port->port_number; - on = !!on; /* 1 or 0 not bitmask */ - return send_cmd(port->port->serial->dev, - feature, (__u8)(UMPM_UART1_PORT + port_number), - on, NULL, 0); -} + return send_port_cmd(port->port, feature, on, NULL, 0); +} -static int restore_mcr(struct edgeport_port *port, __u8 mcr) +static int restore_mcr(struct edgeport_port *port, u8 mcr) { int status = 0; @@ -1417,9 +1528,9 @@ static int restore_mcr(struct edgeport_port *port, __u8 mcr) } /* Convert TI LSR to standard UART flags */ -static __u8 map_line_status(__u8 ti_lsr) +static u8 map_line_status(u8 ti_lsr) { - __u8 lsr = 0; + u8 lsr = 0; #define MAP_FLAG(flagUmp, flagUart) \ if (ti_lsr & flagUmp) \ @@ -1437,7 +1548,7 @@ static __u8 map_line_status(__u8 ti_lsr) return lsr; } -static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) +static void handle_new_msr(struct edgeport_port *edge_port, u8 msr) { struct async_icount *icount; struct tty_struct *tty; @@ -1466,21 +1577,17 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) tty = tty_port_tty_get(&edge_port->port->port); /* handle CTS flow control */ if (tty && C_CRTSCTS(tty)) { - if (msr & EDGEPORT_MSR_CTS) { - tty->hw_stopped = 0; + if (msr & EDGEPORT_MSR_CTS) tty_wakeup(tty); - } else { - tty->hw_stopped = 1; - } } tty_kref_put(tty); } static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, - __u8 lsr, __u8 data) + u8 lsr, u8 data) { struct async_icount *icount; - __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | + u8 new_lsr = (u8)(lsr & (u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK)); dev_dbg(&edge_port->port->dev, "%s - %02x\n", __func__, new_lsr); @@ -1492,7 +1599,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, * Parity and Framing errors only count if they * occur exclusive of a break being received. */ - new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK); + new_lsr &= (u8)(LSR_OVER_ERR | LSR_BREAK); /* Place LSR data byte into Rx buffer */ if (lsr_data) @@ -1510,7 +1617,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; @@ -1522,8 +1628,8 @@ static void edge_interrupt_callback(struct urb *urb) int port_number; int function; int retval; - __u8 lsr; - __u8 msr; + u8 lsr; + u8 msr; int status = urb->status; switch (status) { @@ -1560,6 +1666,12 @@ static void edge_interrupt_callback(struct urb *urb) function = TIUMP_GET_FUNC_FROM_CODE(data[0]); dev_dbg(dev, "%s - port_number %d, function %d, info 0x%x\n", __func__, port_number, function, data[1]); + + if (port_number >= edge_serial->serial->num_ports) { + dev_err(dev, "bad port number %d\n", port_number); + goto exit; + } + port = edge_serial->serial->port[port_number]; edge_port = usb_get_serial_port_data(port); if (!edge_port) { @@ -1570,8 +1682,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; @@ -1612,6 +1725,7 @@ static void edge_bulk_in_callback(struct urb *urb) struct edgeport_port *edge_port = urb->context; struct device *dev = &edge_port->port->dev; unsigned char *data = urb->transfer_buffer; + unsigned long flags; int retval = 0; int port_number; int status = urb->status; @@ -1640,7 +1754,7 @@ static void edge_bulk_in_callback(struct urb *urb) port_number = edge_port->port->port_number; - if (edge_port->lsr_event) { + if (urb->actual_length > 0 && edge_port->lsr_event) { edge_port->lsr_event = 0; dev_dbg(dev, "%s ===== Port %u LSR Status = %02x, Data = %02x ======\n", __func__, port_number, edge_port->lsr_mask, *data); @@ -1663,13 +1777,13 @@ static void edge_bulk_in_callback(struct urb *urb) exit: /* continue read unless stopped */ - spin_lock(&edge_port->ep_lock); + spin_lock_irqsave(&edge_port->ep_lock, flags); if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) retval = usb_submit_urb(urb, GFP_ATOMIC); else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING) edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED; - spin_unlock(&edge_port->ep_lock); + spin_unlock_irqrestore(&edge_port->ep_lock, flags); if (retval) dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval); } @@ -1723,7 +1837,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) struct edgeport_serial *edge_serial; struct usb_device *dev; struct urb *urb; - int port_number; int status; u16 open_settings; u8 transaction_timeout; @@ -1731,24 +1844,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) if (edge_port == NULL) return -ENODEV; - port_number = port->port_number; - switch (port_number) { - case 0: - edge_port->uart_base = UMPMEM_BASE_UART1; - edge_port->dma_address = UMPD_OEDB1_ADDRESS; - break; - case 1: - edge_port->uart_base = UMPMEM_BASE_UART2; - edge_port->dma_address = UMPD_OEDB2_ADDRESS; - break; - default: - dev_err(&port->dev, "Unknown port number!!!\n"); - return -ENODEV; - } - - dev_dbg(&port->dev, "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n", - __func__, port_number, edge_port->uart_base, edge_port->dma_address); - dev = port->serial->dev; /* turn off loopback */ @@ -1780,8 +1875,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) dev_dbg(&port->dev, "%s - Sending UMPC_OPEN_PORT\n", __func__); /* Tell TI to open and start the port */ - status = send_cmd(dev, UMPC_OPEN_PORT, - (u8)(UMPM_UART1_PORT + port_number), open_settings, NULL, 0); + status = send_port_cmd(port, UMPC_OPEN_PORT, open_settings, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send open command, %d\n", __func__, status); @@ -1789,8 +1883,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) } /* Start the DMA? */ - status = send_cmd(dev, UMPC_START_PORT, - (u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0); + status = send_port_cmd(port, UMPC_START_PORT, 0, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send start DMA command, %d\n", __func__, status); @@ -1807,9 +1900,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) } /* Read Initial MSR */ - status = ti_vread_sync(dev, UMPC_READ_MSR, 0, - (__u16)(UMPM_UART1_PORT + port_number), - &edge_port->shadow_msr, 1); + status = read_port_cmd(port, UMPC_READ_MSR, 0, &edge_port->shadow_msr, 1); if (status) { dev_err(&port->dev, "%s - cannot send read MSR command, %d\n", __func__, status); @@ -1828,13 +1919,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) if (edge_serial->num_ports_open == 0) { /* we are the first port to open, post the interrupt urb */ urb = edge_serial->serial->port[0]->interrupt_in_urb; - if (!urb) { - dev_err(&port->dev, - "%s - no interrupt urb present, exiting\n", - __func__); - status = -EINVAL; - goto release_es_lock; - } urb->context = edge_serial; status = usb_submit_urb(urb, GFP_KERNEL); if (status) { @@ -1854,12 +1938,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) /* start up our bulk read urb */ urb = port->read_urb; - if (!urb) { - dev_err(&port->dev, "%s - no read urb present, exiting\n", - __func__); - status = -EINVAL; - goto unlink_int_urb; - } edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING; urb->context = edge_port; status = usb_submit_urb(urb, GFP_KERNEL); @@ -1872,8 +1950,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) ++edge_serial->num_ports_open; - port->port.drain_delay = 1; - goto release_es_lock; unlink_int_urb: @@ -1888,30 +1964,28 @@ static void edge_close(struct usb_serial_port *port) { struct edgeport_serial *edge_serial; struct edgeport_port *edge_port; - struct usb_serial *serial = port->serial; unsigned long flags; - int port_number; edge_serial = usb_get_serial_data(port->serial); edge_port = usb_get_serial_port_data(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); usb_kill_urb(port->write_urb); edge_port->ep_write_urb_in_use = 0; spin_lock_irqsave(&edge_port->ep_lock, flags); - kfifo_reset_out(&edge_port->write_fifo); + kfifo_reset_out(&port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__); - port_number = port->port_number; - send_cmd(serial->dev, UMPC_CLOSE_PORT, - (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0); + send_port_cmd(port, UMPC_CLOSE_PORT, 0, NULL, 0); mutex_lock(&edge_serial->es_lock); --edge_port->edge_serial->num_ports_open; @@ -1939,7 +2013,7 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, if (edge_port->close_pending == 1) return -ENODEV; - count = kfifo_in_locked(&edge_port->write_fifo, data, count, + count = kfifo_in_locked(&port->write_fifo, data, count, &edge_port->ep_lock); edge_send(port, tty); @@ -1959,7 +2033,7 @@ static void edge_send(struct usb_serial_port *port, struct tty_struct *tty) return; } - count = kfifo_out(&edge_port->write_fifo, + count = kfifo_out(&port->write_fifo, port->write_urb->transfer_buffer, port->bulk_out_size); @@ -1988,17 +2062,19 @@ 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); } -static int edge_write_room(struct tty_struct *tty) +static unsigned int edge_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int room = 0; + unsigned int room; unsigned long flags; if (edge_port == NULL) @@ -2007,27 +2083,27 @@ static int edge_write_room(struct tty_struct *tty) return 0; spin_lock_irqsave(&edge_port->ep_lock, flags); - room = kfifo_avail(&edge_port->write_fifo); + room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); - dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); + dev_dbg(&port->dev, "%s - returns %u\n", __func__, room); return room; } -static int edge_chars_in_buffer(struct tty_struct *tty) +static unsigned int edge_chars_in_buffer(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int chars = 0; + unsigned int chars; unsigned long flags; if (edge_port == NULL) return 0; spin_lock_irqsave(&edge_port->ep_lock, flags); - chars = kfifo_len(&edge_port->write_fifo); + chars = kfifo_len(&port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); - dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); + dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars); return chars; } @@ -2061,8 +2137,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); @@ -2085,8 +2163,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) @@ -2131,19 +2211,17 @@ static int restart_read(struct edgeport_port *edge_port) } static void change_port_settings(struct tty_struct *tty, - struct edgeport_port *edge_port, struct ktermios *old_termios) + struct edgeport_port *edge_port, const struct ktermios *old_termios) { struct device *dev = &edge_port->port->dev; struct ump_uart_config *config; int baud; unsigned cflag; int status; - int port_number = edge_port->port->port_number; config = kmalloc (sizeof (*config), GFP_KERNEL); if (!config) { tty->termios = *old_termios; - dev_err(dev, "%s - out of memory\n", __func__); return; } @@ -2154,7 +2232,7 @@ static void change_port_settings(struct tty_struct *tty, /* These flags must be set */ config->wFlags |= UMP_MASK_UART_FLAGS_RECEIVE_MS_INT; config->wFlags |= UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR; - config->bUartMode = (__u8)(edge_port->bUartMode); + config->bUartMode = (u8)(edge_port->bUartMode); switch (cflag & CSIZE) { case CS5: @@ -2206,12 +2284,13 @@ static void change_port_settings(struct tty_struct *tty, dev_dbg(dev, "%s - RTS/CTS is enabled\n", __func__); } else { dev_dbg(dev, "%s - RTS/CTS is disabled\n", __func__); - tty->hw_stopped = 0; 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); @@ -2238,11 +2317,14 @@ static void change_port_settings(struct tty_struct *tty, if (!baud) { /* pick a default, any default... */ baud = 9600; - } else + } else { + /* Avoid a zero divisor. */ + baud = min(baud, 461550); tty_encode_baud_rate(tty, baud, baud); + } edge_port->baud_rate = baud; - config->wBaudRate = (__u16)((461550L + baud/2) / baud); + config->wBaudRate = (u16)((461550L + baud/2) / baud); /* FIXME: Recompute actual baud from divisor here */ @@ -2261,9 +2343,8 @@ static void change_port_settings(struct tty_struct *tty, cpu_to_be16s(&config->wFlags); cpu_to_be16s(&config->wBaudRate); - status = send_cmd(edge_port->port->serial->dev, UMPC_SET_CONFIG, - (__u8)(UMPM_UART1_PORT + port_number), - 0, (__u8 *)config, sizeof(*config)); + status = send_port_cmd(edge_port->port, UMPC_SET_CONFIG, 0, config, + sizeof(*config)); if (status) dev_dbg(dev, "%s - error %d when trying to write config to device\n", __func__, status); @@ -2271,17 +2352,10 @@ static void change_port_settings(struct tty_struct *tty, } static void edge_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned int cflag; - - cflag = tty->termios.c_cflag; - - dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, - tty->termios.c_cflag, tty->termios.c_iflag); - dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__, - old_termios->c_cflag, old_termios->c_iflag); if (edge_port == NULL) return; @@ -2347,99 +2421,129 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static int get_serial_info(struct edgeport_port *edge_port, - struct serial_struct __user *retinfo) +static int edge_break(struct tty_struct *tty, int break_state) { - struct serial_struct tmp; - unsigned cwait; + struct usb_serial_port *port = tty->driver_data; + struct edgeport_port *edge_port = usb_get_serial_port_data(port); + int status; + int bv = 0; /* Off */ - if (!retinfo) - return -EFAULT; + if (break_state == -1) + bv = 1; /* On */ - cwait = edge_port->port->port.closing_wait; - if (cwait != ASYNC_CLOSING_WAIT_NONE) - cwait = jiffies_to_msecs(cwait) / 10; + status = ti_do_config(edge_port, UMPC_SET_CLR_BREAK, bv); + if (status) { + dev_dbg(&port->dev, "%s - error %d sending break set/clear command.\n", + __func__, status); + return status; + } - memset(&tmp, 0, sizeof(tmp)); + return 0; +} - tmp.type = PORT_16550A; - tmp.line = edge_port->port->minor; - tmp.port = edge_port->port->port_number; - tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; - tmp.xmit_fifo_size = edge_port->port->bulk_out_size; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = cwait; +static void edge_heartbeat_schedule(struct edgeport_serial *edge_serial) +{ + if (!edge_serial->use_heartbeat) + return; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; + schedule_delayed_work(&edge_serial->heartbeat_work, + FW_HEARTBEAT_SECS * HZ); } -static int edge_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static void edge_heartbeat_work(struct work_struct *work) { - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); + struct edgeport_serial *serial; + struct ti_i2c_desc *rom_desc; - dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd); + serial = container_of(work, struct edgeport_serial, + heartbeat_work.work); - switch (cmd) { - case TIOCGSERIAL: - dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__); - return get_serial_info(edge_port, - (struct serial_struct __user *) arg); + rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); + + /* Descriptor address request is enough to reset the firmware timer */ + if (!rom_desc || !get_descriptor_addr(serial, I2C_DESC_TYPE_ION, + rom_desc)) { + dev_err(&serial->serial->interface->dev, + "%s - Incomplete heartbeat\n", __func__); } - return -ENOIOCTLCMD; + kfree(rom_desc); + + edge_heartbeat_schedule(serial); } -static void edge_break(struct tty_struct *tty, int break_state) +static int edge_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int status; - int bv = 0; /* Off */ + struct device *dev = &serial->interface->dev; + unsigned char num_ports = serial->type->num_ports; + + /* Make sure we have the required endpoints when in download mode. */ + if (serial->interface->cur_altsetting->desc.bNumEndpoints > 1) { + if (epds->num_bulk_in < num_ports || + epds->num_bulk_out < num_ports || + epds->num_interrupt_in < 1) { + dev_err(dev, "required endpoints missing\n"); + return -ENODEV; + } + } - if (break_state == -1) - bv = 1; /* On */ - status = ti_do_config(edge_port, UMPC_SET_CLR_BREAK, bv); - if (status) - dev_dbg(&port->dev, "%s - error %d sending break set/clear command.\n", - __func__, status); + return num_ports; } static int edge_startup(struct usb_serial *serial) { struct edgeport_serial *edge_serial; int status; + u16 product_id; /* create our private serial structure */ edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); - if (edge_serial == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); + if (!edge_serial) return -ENOMEM; - } + mutex_init(&edge_serial->es_lock); edge_serial->serial = serial; + INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work); usb_set_serial_data(serial, edge_serial); status = download_fw(edge_serial); - if (status) { + if (status < 0) { kfree(edge_serial); return status; } + if (status > 0) + return 1; /* bind but do not register any ports */ + + product_id = le16_to_cpu( + edge_serial->serial->dev->descriptor.idProduct); + + /* Currently only the EP/416 models require heartbeat support */ + if (edge_serial->fw_version > FW_HEARTBEAT_VERSION_CUTOFF) { + if (product_id == ION_DEVICE_ID_TI_EDGEPORT_416 || + product_id == ION_DEVICE_ID_TI_EDGEPORT_416B) { + edge_serial->use_heartbeat = true; + } + } + + edge_heartbeat_schedule(edge_serial); + return 0; } static void edge_disconnect(struct usb_serial *serial) { + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + + cancel_delayed_work_sync(&edge_serial->heartbeat_work); } static void edge_release(struct usb_serial *serial) { - kfree(usb_get_serial_data(serial)); + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + + cancel_delayed_work_sync(&edge_serial->heartbeat_work); + kfree(edge_serial); } static int edge_port_probe(struct usb_serial_port *port) @@ -2451,47 +2555,62 @@ static int edge_port_probe(struct usb_serial_port *port) if (!edge_port) return -ENOMEM; - ret = kfifo_alloc(&edge_port->write_fifo, EDGE_OUT_BUF_SIZE, - GFP_KERNEL); - if (ret) { - kfree(edge_port); - return -ENOMEM; - } - spin_lock_init(&edge_port->ep_lock); edge_port->port = port; edge_port->edge_serial = usb_get_serial_data(port->serial); edge_port->bUartMode = default_uart_mode; + switch (port->port_number) { + case 0: + edge_port->uart_base = UMPMEM_BASE_UART1; + edge_port->dma_address = UMPD_OEDB1_ADDRESS; + break; + case 1: + edge_port->uart_base = UMPMEM_BASE_UART2; + edge_port->dma_address = UMPD_OEDB2_ADDRESS; + break; + default: + dev_err(&port->dev, "unknown port number\n"); + ret = -ENODEV; + goto err; + } + + dev_dbg(&port->dev, + "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n", + __func__, port->port_number, edge_port->uart_base, + edge_port->dma_address); + usb_set_serial_port_data(port, edge_port); ret = edge_create_sysfs_attrs(port); - if (ret) { - kfifo_free(&edge_port->write_fifo); - kfree(edge_port); - return ret; - } + if (ret) + goto err; - port->port.closing_wait = msecs_to_jiffies(closing_wait * 10); + /* + * The LSR does not tell when the transmitter shift register has + * emptied so add a one-character drain delay. + */ + port->port.drain_delay = 1; return 0; +err: + kfree(edge_port); + + return ret; } -static int edge_port_remove(struct usb_serial_port *port) +static void edge_port_remove(struct usb_serial_port *port) { struct edgeport_port *edge_port; edge_port = usb_get_serial_port_data(port); edge_remove_sysfs_attrs(port); - kfifo_free(&edge_port->write_fifo); kfree(edge_port); - - return 0; } /* Sysfs Attributes */ -static ssize_t show_uart_mode(struct device *dev, +static ssize_t uart_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_serial_port *port = to_usb_serial_port(dev); @@ -2500,7 +2619,7 @@ static ssize_t show_uart_mode(struct device *dev, return sprintf(buf, "%d\n", edge_port->bUartMode); } -static ssize_t store_uart_mode(struct device *dev, +static ssize_t uart_mode_store(struct device *dev, struct device_attribute *attr, const char *valbuf, size_t count) { struct usb_serial_port *port = to_usb_serial_port(dev); @@ -2516,9 +2635,7 @@ static ssize_t store_uart_mode(struct device *dev, return count; } - -static DEVICE_ATTR(uart_mode, S_IWUSR | S_IRUGO, show_uart_mode, - store_uart_mode); +static DEVICE_ATTR_RW(uart_mode); static int edge_create_sysfs_attrs(struct usb_serial_port *port) { @@ -2531,25 +2648,44 @@ static int edge_remove_sysfs_attrs(struct usb_serial_port *port) return 0; } +#ifdef CONFIG_PM +static int edge_suspend(struct usb_serial *serial, pm_message_t message) +{ + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + + cancel_delayed_work_sync(&edge_serial->heartbeat_work); + + return 0; +} + +static int edge_resume(struct usb_serial *serial) +{ + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + + edge_heartbeat_schedule(edge_serial); + + return 0; +} +#endif static struct usb_serial_driver edgeport_1port_device = { .driver = { - .owner = THIS_MODULE, .name = "edgeport_ti_1", }, .description = "Edgeport TI 1 port adapter", .id_table = edgeport_1port_id_table, .num_ports = 1, + .num_bulk_out = 1, .open = edge_open, .close = edge_close, .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, + .calc_num_ports = edge_calc_num_ports, .disconnect = edge_disconnect, .release = edge_release, .port_probe = edge_port_probe, .port_remove = edge_port_remove, - .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, @@ -2563,26 +2699,30 @@ static struct usb_serial_driver edgeport_1port_device = { .read_int_callback = edge_interrupt_callback, .read_bulk_callback = edge_bulk_in_callback, .write_bulk_callback = edge_bulk_out_callback, +#ifdef CONFIG_PM + .suspend = edge_suspend, + .resume = edge_resume, +#endif }; static struct usb_serial_driver edgeport_2port_device = { .driver = { - .owner = THIS_MODULE, .name = "edgeport_ti_2", }, .description = "Edgeport TI 2 port adapter", .id_table = edgeport_2port_id_table, .num_ports = 2, + .num_bulk_out = 1, .open = edge_open, .close = edge_close, .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, + .calc_num_ports = edge_calc_num_ports, .disconnect = edge_disconnect, .release = edge_release, .port_probe = edge_port_probe, .port_remove = edge_port_remove, - .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, @@ -2596,6 +2736,10 @@ static struct usb_serial_driver edgeport_2port_device = { .read_int_callback = edge_interrupt_callback, .read_bulk_callback = edge_bulk_in_callback, .write_bulk_callback = edge_bulk_out_callback, +#ifdef CONFIG_PM + .suspend = edge_suspend, + .resume = edge_resume, +#endif }; static struct usb_serial_driver * const serial_drivers[] = { @@ -2609,12 +2753,9 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("edgeport/down3.bin"); -module_param(closing_wait, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain, in .01 secs"); - -module_param(ignore_cpu_rev, bool, S_IRUGO | S_IWUSR); +module_param(ignore_cpu_rev, bool, 0644); MODULE_PARM_DESC(ignore_cpu_rev, "Ignore the cpu revision when connecting to a device"); -module_param(default_uart_mode, int, S_IRUGO | S_IWUSR); +module_param(default_uart_mode, int, 0644); MODULE_PARM_DESC(default_uart_mode, "Default uart_mode, 0=RS232, ..."); |
