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: Ludovic Drolez <ldrolez@debian.org> Tested-by: Ludovic Drolez <ldrolez@debian.org> Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
01bb59ebff
commit
5509076d1b
@@ -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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
__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,
|
|||||||
__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,
|
|||||||
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)
|
|||||||
__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)
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
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)
|
|||||||
|
|
||||||
/* 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;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user