USB: io_ti: fix firmware download on big-endian machines
authorJohan Hovold <jhovold@gmail.com>
Fri, 25 Apr 2014 13:23:03 +0000 (15:23 +0200)
committerBen Hutchings <ben@decadent.org.uk>
Sun, 18 May 2014 13:58:08 +0000 (14:58 +0100)
commit 5509076d1b4485ce9fb07705fcbcd2695907ab5b upstream.

During firmware download the device expects memory addresses in
big-endian byte order. As the wIndex parameter which hold the address is
sent in little-endian byte order regardless of host byte order, we need
to use swab16 rather than cpu_to_be16.

Also make sure to handle the struct ti_i2c_desc size parameter which is
returned in little-endian byte order.

Reported-by: Ludovic Drolez <ldrolez@debian.org>
Tested-by: Ludovic Drolez <ldrolez@debian.org>
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/usb/serial/io_ti.c

index f42119d..c575e0a 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
 #include <linux/serial.h>
 #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>
 #include <linux/kfifo.h>
 #include <linux/ioctl.h>
 #include <linux/firmware.h>
@@ -306,7 +307,7 @@ static int read_download_mem(struct usb_device *dev, int start_address,
 {
        int status = 0;
        __u8 read_length;
 {
        int status = 0;
        __u8 read_length;
-       __be16 be_start_address;
+       u16 be_start_address;
 
        dbg("%s - @ %x for %d", __func__, start_address, length);
 
 
        dbg("%s - @ %x for %d", __func__, start_address, length);
 
@@ -323,10 +324,14 @@ static int read_download_mem(struct usb_device *dev, int start_address,
                        dbg("%s - @ %x for %d", __func__,
                             start_address, read_length);
                }
                        dbg("%s - @ %x for %d", __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,
                status = ti_vread_sync(dev, UMPC_MEMORY_READ,
                                        (__u16)address_type,
-                                       (__force __u16)be_start_address,
+                                       be_start_address,
                                        buffer, read_length);
 
                if (status) {
                                        buffer, read_length);
 
                if (status) {
@@ -426,7 +431,7 @@ static int write_i2c_mem(struct edgeport_serial *serial,
 {
        int status = 0;
        int write_length;
 {
        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 */
 
 
        /* We can only send a maximum of 1 aligned byte page at a time */
 
@@ -442,11 +447,16 @@ static int write_i2c_mem(struct edgeport_serial *serial,
        usb_serial_debug_data(debug, &serial->serial->dev->dev,
                                                __func__, write_length, buffer);
 
        usb_serial_debug_data(debug, &serial->serial->dev->dev,
                                                __func__, write_length, buffer);
 
-       /* Write first page */
-       be_start_address = cpu_to_be16(start_address);
+       /*
+        * 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,
        status = ti_vsend_sync(serial->serial->dev,
                                UMPC_MEMORY_WRITE, (__u16)address_type,
-                               (__force __u16)be_start_address,
+                               be_start_address,
                                buffer, write_length);
        if (status) {
                dbg("%s - ERROR %d", __func__, status);
                                buffer, write_length);
        if (status) {
                dbg("%s - ERROR %d", __func__, status);
@@ -470,11 +480,16 @@ static int write_i2c_mem(struct edgeport_serial *serial,
                usb_serial_debug_data(debug, &serial->serial->dev->dev,
                                        __func__, write_length, buffer);
 
                usb_serial_debug_data(debug, &serial->serial->dev->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,
                status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE,
                                (__u16)address_type,
-                               (__force __u16)be_start_address,
+                               be_start_address,
                                buffer, write_length);
                if (status) {
                        dev_err(&serial->serial->dev->dev, "%s - ERROR %d\n",
                                buffer, write_length);
                if (status) {
                        dev_err(&serial->serial->dev->dev, "%s - ERROR %d\n",
@@ -681,8 +696,8 @@ static int get_descriptor_addr(struct edgeport_serial *serial,
                if (rom_desc->Type == desc_type)
                        return start_address;
 
                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);
 
 
        } while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type);
 
@@ -695,7 +710,7 @@ 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++)
+       for (i = 0; i < le16_to_cpu(rom_desc->Size); i++)
                cs = (__u8)(cs + buffer[i]);
 
        if (cs != rom_desc->CheckSum) {
                cs = (__u8)(cs + buffer[i]);
 
        if (cs != rom_desc->CheckSum) {
@@ -749,7 +764,7 @@ static int check_i2c_image(struct edgeport_serial *serial)
                        break;
 
                if ((start_address + sizeof(struct ti_i2c_desc) +
                        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;
                        dbg("%s - structure too big, erroring out.", __func__);
                        break;
                        status = -ENODEV;
                        dbg("%s - structure too big, erroring out.", __func__);
                        break;
@@ -764,7 +779,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),
                        /* 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;
 
                        if (status)
                                break;
 
@@ -773,7 +789,7 @@ static int check_i2c_image(struct edgeport_serial *serial)
                                break;
                }
                start_address = start_address + sizeof(struct ti_i2c_desc) +
                                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));
 
        } while ((rom_desc->Type != I2C_DESC_TYPE_ION) &&
                                (start_address < TI_MAX_I2C_SIZE));
@@ -812,7 +828,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),
 
        /* 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;
 
        if (status)
                goto exit;