Commit 5509076d authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman

USB: io_ti: fix firmware download on big-endian machines

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: default avatarLudovic Drolez <ldrolez@debian.org>
Tested-by: default avatarLudovic Drolez <ldrolez@debian.org>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarJohan Hovold <jhovold@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 01bb59eb
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/swab.h>
#include <linux/kfifo.h> #include <linux/kfifo.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/firmware.h> #include <linux/firmware.h>
...@@ -280,7 +281,7 @@ static int read_download_mem(struct usb_device *dev, int start_address, ...@@ -280,7 +281,7 @@ static int read_download_mem(struct usb_device *dev, int start_address,
{ {
int status = 0; int status = 0;
__u8 read_length; __u8 read_length;
__be16 be_start_address; u16 be_start_address;
dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length); dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length);
...@@ -296,10 +297,14 @@ static int read_download_mem(struct usb_device *dev, int start_address, ...@@ -296,10 +297,14 @@ static int read_download_mem(struct usb_device *dev, int start_address,
if (read_length > 1) { if (read_length > 1) {
dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length); 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, status = ti_vread_sync(dev, UMPC_MEMORY_READ,
(__u16)address_type, (__u16)address_type,
(__force __u16)be_start_address, be_start_address,
buffer, read_length); buffer, read_length);
if (status) { if (status) {
...@@ -394,7 +399,7 @@ static int write_i2c_mem(struct edgeport_serial *serial, ...@@ -394,7 +399,7 @@ static int write_i2c_mem(struct edgeport_serial *serial,
struct device *dev = &serial->serial->dev->dev; struct device *dev = &serial->serial->dev->dev;
int status = 0; int status = 0;
int write_length; 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 */
...@@ -409,11 +414,16 @@ static int write_i2c_mem(struct edgeport_serial *serial, ...@@ -409,11 +414,16 @@ static int write_i2c_mem(struct edgeport_serial *serial,
__func__, start_address, write_length); __func__, start_address, write_length);
usb_serial_debug_data(dev, __func__, write_length, buffer); usb_serial_debug_data(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, status = ti_vsend_sync(serial->serial->dev,
UMPC_MEMORY_WRITE, (__u16)address_type, UMPC_MEMORY_WRITE, (__u16)address_type,
(__force __u16)be_start_address, be_start_address,
buffer, write_length); buffer, write_length);
if (status) { if (status) {
dev_dbg(dev, "%s - ERROR %d\n", __func__, status); dev_dbg(dev, "%s - ERROR %d\n", __func__, status);
...@@ -436,11 +446,16 @@ static int write_i2c_mem(struct edgeport_serial *serial, ...@@ -436,11 +446,16 @@ static int write_i2c_mem(struct edgeport_serial *serial,
__func__, start_address, write_length); __func__, start_address, write_length);
usb_serial_debug_data(dev, __func__, write_length, buffer); 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, status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE,
(__u16)address_type, (__u16)address_type,
(__force __u16)be_start_address, be_start_address,
buffer, write_length); buffer, write_length);
if (status) { if (status) {
dev_err(dev, "%s - ERROR %d\n", __func__, status); dev_err(dev, "%s - ERROR %d\n", __func__, status);
...@@ -585,8 +600,8 @@ static int get_descriptor_addr(struct edgeport_serial *serial, ...@@ -585,8 +600,8 @@ static int get_descriptor_addr(struct edgeport_serial *serial,
if (rom_desc->Type == desc_type) if (rom_desc->Type == desc_type)
return start_address; return start_address;
start_address = start_address + sizeof(struct ti_i2c_desc) start_address = start_address + sizeof(struct ti_i2c_desc) +
+ rom_desc->Size; 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);
...@@ -599,7 +614,7 @@ static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer) ...@@ -599,7 +614,7 @@ static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer)
__u16 i; __u16 i;
__u8 cs = 0; __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]); cs = (__u8)(cs + buffer[i]);
if (cs != rom_desc->CheckSum) { if (cs != rom_desc->CheckSum) {
...@@ -650,7 +665,7 @@ static int check_i2c_image(struct edgeport_serial *serial) ...@@ -650,7 +665,7 @@ static int check_i2c_image(struct edgeport_serial *serial)
break; break;
if ((start_address + sizeof(struct ti_i2c_desc) + 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; status = -ENODEV;
dev_dbg(dev, "%s - structure too big, erroring out.\n", __func__); dev_dbg(dev, "%s - structure too big, erroring out.\n", __func__);
break; break;
...@@ -665,7 +680,8 @@ static int check_i2c_image(struct edgeport_serial *serial) ...@@ -665,7 +680,8 @@ static int check_i2c_image(struct edgeport_serial *serial)
/* Read the descriptor data */ /* Read the descriptor data */
status = read_rom(serial, start_address + status = read_rom(serial, start_address +
sizeof(struct ti_i2c_desc), sizeof(struct ti_i2c_desc),
rom_desc->Size, buffer); le16_to_cpu(rom_desc->Size),
buffer);
if (status) if (status)
break; break;
...@@ -674,7 +690,7 @@ static int check_i2c_image(struct edgeport_serial *serial) ...@@ -674,7 +690,7 @@ static int check_i2c_image(struct edgeport_serial *serial)
break; break;
} }
start_address = start_address + sizeof(struct ti_i2c_desc) + 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) && } while ((rom_desc->Type != I2C_DESC_TYPE_ION) &&
(start_address < TI_MAX_I2C_SIZE)); (start_address < TI_MAX_I2C_SIZE));
...@@ -712,7 +728,7 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer) ...@@ -712,7 +728,7 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer)
/* Read the descriptor data */ /* Read the descriptor data */
status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc), status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc),
rom_desc->Size, buffer); le16_to_cpu(rom_desc->Size), buffer);
if (status) if (status)
goto exit; goto exit;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment