Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+33 −17
Original line number Diff line number Diff line
@@ -28,6 +28,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>
@@ -280,7 +281,7 @@ static int read_download_mem(struct usb_device *dev, int start_address,
{
	int status = 0;
	__u8 read_length;
	__be16 be_start_address;
	u16 be_start_address;

	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) {
			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,
					be_start_address,
					buffer, read_length);

		if (status) {
@@ -394,7 +399,7 @@ static int write_i2c_mem(struct edgeport_serial *serial,
	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 */

@@ -409,11 +414,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);
	/*
	 * 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,
				(__force __u16)be_start_address,
				be_start_address,
				buffer,	write_length);
	if (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);
		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,
				be_start_address,
				buffer, write_length);
		if (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)
			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);

@@ -599,7 +614,7 @@ static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer)
	__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) {
@@ -650,7 +665,7 @@ static int check_i2c_image(struct edgeport_serial *serial)
			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;
@@ -665,7 +680,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;

@@ -674,7 +690,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));
@@ -712,7 +728,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;