diff options
author | Johan Hovold <jhovold@gmail.com> | 2014-04-25 09:23:03 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-31 00:52:13 -0400 |
commit | 9e036f060793ddb0a9f3f70d4753877b85e894b4 (patch) | |
tree | 9518f3e87b63eae33e07c8bb624908d50218a726 | |
parent | 2eb1a584d440a3aed1b4793f39d091c1fff3f6d7 (diff) |
USB: io_ti: fix firmware download on big-endian machines
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>
-rw-r--r-- | drivers/usb/serial/io_ti.c | 50 |
1 files changed, 33 insertions, 17 deletions
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 1be6ba7bee27..c5c9cbf107d1 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
30 | #include <linux/mutex.h> | 30 | #include <linux/mutex.h> |
31 | #include <linux/serial.h> | 31 | #include <linux/serial.h> |
32 | #include <linux/swab.h> | ||
32 | #include <linux/kfifo.h> | 33 | #include <linux/kfifo.h> |
33 | #include <linux/ioctl.h> | 34 | #include <linux/ioctl.h> |
34 | #include <linux/firmware.h> | 35 | #include <linux/firmware.h> |
@@ -284,7 +285,7 @@ static int read_download_mem(struct usb_device *dev, int start_address, | |||
284 | { | 285 | { |
285 | int status = 0; | 286 | int status = 0; |
286 | __u8 read_length; | 287 | __u8 read_length; |
287 | __be16 be_start_address; | 288 | u16 be_start_address; |
288 | 289 | ||
289 | dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length); | 290 | dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length); |
290 | 291 | ||
@@ -300,10 +301,14 @@ static int read_download_mem(struct usb_device *dev, int start_address, | |||
300 | if (read_length > 1) { | 301 | if (read_length > 1) { |
301 | dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length); | 302 | dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length); |
302 | } | 303 | } |
303 | be_start_address = cpu_to_be16(start_address); | 304 | /* |
305 | * NOTE: Must use swab as wIndex is sent in little-endian | ||
306 | * byte order regardless of host byte order. | ||
307 | */ | ||
308 | be_start_address = swab16((u16)start_address); | ||
304 | status = ti_vread_sync(dev, UMPC_MEMORY_READ, | 309 | status = ti_vread_sync(dev, UMPC_MEMORY_READ, |
305 | (__u16)address_type, | 310 | (__u16)address_type, |
306 | (__force __u16)be_start_address, | 311 | be_start_address, |
307 | buffer, read_length); | 312 | buffer, read_length); |
308 | 313 | ||
309 | if (status) { | 314 | if (status) { |
@@ -400,7 +405,7 @@ static int write_i2c_mem(struct edgeport_serial *serial, | |||
400 | struct device *dev = &serial->serial->dev->dev; | 405 | struct device *dev = &serial->serial->dev->dev; |
401 | int status = 0; | 406 | int status = 0; |
402 | int write_length; | 407 | int write_length; |
403 | __be16 be_start_address; | 408 | u16 be_start_address; |
404 | 409 | ||
405 | /* We can only send a maximum of 1 aligned byte page at a time */ | 410 | /* We can only send a maximum of 1 aligned byte page at a time */ |
406 | 411 | ||
@@ -415,11 +420,16 @@ static int write_i2c_mem(struct edgeport_serial *serial, | |||
415 | __func__, start_address, write_length); | 420 | __func__, start_address, write_length); |
416 | usb_serial_debug_data(dev, __func__, write_length, buffer); | 421 | usb_serial_debug_data(dev, __func__, write_length, buffer); |
417 | 422 | ||
418 | /* Write first page */ | 423 | /* |
419 | be_start_address = cpu_to_be16(start_address); | 424 | * Write first page. |
425 | * | ||
426 | * NOTE: Must use swab as wIndex is sent in little-endian byte order | ||
427 | * regardless of host byte order. | ||
428 | */ | ||
429 | be_start_address = swab16((u16)start_address); | ||
420 | status = ti_vsend_sync(serial->serial->dev, | 430 | status = ti_vsend_sync(serial->serial->dev, |
421 | UMPC_MEMORY_WRITE, (__u16)address_type, | 431 | UMPC_MEMORY_WRITE, (__u16)address_type, |
422 | (__force __u16)be_start_address, | 432 | be_start_address, |
423 | buffer, write_length); | 433 | buffer, write_length); |
424 | if (status) { | 434 | if (status) { |
425 | dev_dbg(dev, "%s - ERROR %d\n", __func__, status); | 435 | dev_dbg(dev, "%s - ERROR %d\n", __func__, status); |
@@ -442,11 +452,16 @@ static int write_i2c_mem(struct edgeport_serial *serial, | |||
442 | __func__, start_address, write_length); | 452 | __func__, start_address, write_length); |
443 | usb_serial_debug_data(dev, __func__, write_length, buffer); | 453 | usb_serial_debug_data(dev, __func__, write_length, buffer); |
444 | 454 | ||
445 | /* Write next page */ | 455 | /* |
446 | be_start_address = cpu_to_be16(start_address); | 456 | * Write next page. |
457 | * | ||
458 | * NOTE: Must use swab as wIndex is sent in little-endian byte | ||
459 | * order regardless of host byte order. | ||
460 | */ | ||
461 | be_start_address = swab16((u16)start_address); | ||
447 | status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, | 462 | status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, |
448 | (__u16)address_type, | 463 | (__u16)address_type, |
449 | (__force __u16)be_start_address, | 464 | be_start_address, |
450 | buffer, write_length); | 465 | buffer, write_length); |
451 | if (status) { | 466 | if (status) { |
452 | dev_err(dev, "%s - ERROR %d\n", __func__, status); | 467 | dev_err(dev, "%s - ERROR %d\n", __func__, status); |
@@ -593,8 +608,8 @@ static int get_descriptor_addr(struct edgeport_serial *serial, | |||
593 | if (rom_desc->Type == desc_type) | 608 | if (rom_desc->Type == desc_type) |
594 | return start_address; | 609 | return start_address; |
595 | 610 | ||
596 | start_address = start_address + sizeof(struct ti_i2c_desc) | 611 | start_address = start_address + sizeof(struct ti_i2c_desc) + |
597 | + rom_desc->Size; | 612 | le16_to_cpu(rom_desc->Size); |
598 | 613 | ||
599 | } while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type); | 614 | } while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type); |
600 | 615 | ||
@@ -607,7 +622,7 @@ static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer) | |||
607 | __u16 i; | 622 | __u16 i; |
608 | __u8 cs = 0; | 623 | __u8 cs = 0; |
609 | 624 | ||
610 | for (i = 0; i < rom_desc->Size; i++) | 625 | for (i = 0; i < le16_to_cpu(rom_desc->Size); i++) |
611 | cs = (__u8)(cs + buffer[i]); | 626 | cs = (__u8)(cs + buffer[i]); |
612 | 627 | ||
613 | if (cs != rom_desc->CheckSum) { | 628 | if (cs != rom_desc->CheckSum) { |
@@ -661,7 +676,7 @@ static int check_i2c_image(struct edgeport_serial *serial) | |||
661 | break; | 676 | break; |
662 | 677 | ||
663 | if ((start_address + sizeof(struct ti_i2c_desc) + | 678 | if ((start_address + sizeof(struct ti_i2c_desc) + |
664 | rom_desc->Size) > TI_MAX_I2C_SIZE) { | 679 | le16_to_cpu(rom_desc->Size)) > TI_MAX_I2C_SIZE) { |
665 | status = -ENODEV; | 680 | status = -ENODEV; |
666 | dev_dbg(dev, "%s - structure too big, erroring out.\n", __func__); | 681 | dev_dbg(dev, "%s - structure too big, erroring out.\n", __func__); |
667 | break; | 682 | break; |
@@ -676,7 +691,8 @@ static int check_i2c_image(struct edgeport_serial *serial) | |||
676 | /* Read the descriptor data */ | 691 | /* Read the descriptor data */ |
677 | status = read_rom(serial, start_address + | 692 | status = read_rom(serial, start_address + |
678 | sizeof(struct ti_i2c_desc), | 693 | sizeof(struct ti_i2c_desc), |
679 | rom_desc->Size, buffer); | 694 | le16_to_cpu(rom_desc->Size), |
695 | buffer); | ||
680 | if (status) | 696 | if (status) |
681 | break; | 697 | break; |
682 | 698 | ||
@@ -685,7 +701,7 @@ static int check_i2c_image(struct edgeport_serial *serial) | |||
685 | break; | 701 | break; |
686 | } | 702 | } |
687 | start_address = start_address + sizeof(struct ti_i2c_desc) + | 703 | start_address = start_address + sizeof(struct ti_i2c_desc) + |
688 | rom_desc->Size; | 704 | le16_to_cpu(rom_desc->Size); |
689 | 705 | ||
690 | } while ((rom_desc->Type != I2C_DESC_TYPE_ION) && | 706 | } while ((rom_desc->Type != I2C_DESC_TYPE_ION) && |
691 | (start_address < TI_MAX_I2C_SIZE)); | 707 | (start_address < TI_MAX_I2C_SIZE)); |
@@ -724,7 +740,7 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer) | |||
724 | 740 | ||
725 | /* Read the descriptor data */ | 741 | /* Read the descriptor data */ |
726 | status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc), | 742 | status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc), |
727 | rom_desc->Size, buffer); | 743 | le16_to_cpu(rom_desc->Size), buffer); |
728 | if (status) | 744 | if (status) |
729 | goto exit; | 745 | goto exit; |
730 | 746 | ||