USB: ezusb: add functions for firmware download
This patch adds new functions to upload firmware to the controller. The drivers currently using ezusb are adapted to use these new functions. This also fixes a bug occuring during firmware loading in the whiteheat-driver: The driver iterates over an ihex-formatted firmware using ++ on a "const struct ihex_binrec*" which leads to faulty results, because ihex data is read as length. The function "ihex_next_binrec(record)" has so be used to work correctly Signed-off-by: René Bürgel <rene.buergel@sohard.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
cc183e2a5e
Коммит
8d733e26c0
|
@ -13,6 +13,8 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/ihex.h>
|
||||
|
||||
struct ezusb_fx_type {
|
||||
/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */
|
||||
|
@ -79,3 +81,80 @@ int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit)
|
|||
return ezusb_set_reset(dev, ezusb_fx2.cpucs_reg, reset_bit);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ezusb_fx2_set_reset);
|
||||
|
||||
static int ezusb_ihex_firmware_download(struct usb_device *dev,
|
||||
struct ezusb_fx_type fx,
|
||||
const char *firmware_path)
|
||||
{
|
||||
int ret = -ENOENT;
|
||||
const struct firmware *firmware = NULL;
|
||||
const struct ihex_binrec *record;
|
||||
|
||||
if (request_ihex_firmware(&firmware, firmware_path,
|
||||
&dev->dev)) {
|
||||
dev_err(&dev->dev,
|
||||
"%s - request \"%s\" failed\n",
|
||||
__func__, firmware_path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ezusb_set_reset(dev, fx.cpucs_reg, 0);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
record = (const struct ihex_binrec *)firmware->data;
|
||||
for (; record; record = ihex_next_binrec(record)) {
|
||||
if (be32_to_cpu(record->addr) > fx.max_internal_adress) {
|
||||
ret = ezusb_writememory(dev, be32_to_cpu(record->addr),
|
||||
(unsigned char *)record->data,
|
||||
be16_to_cpu(record->len), WRITE_EXT_RAM);
|
||||
if (ret < 0) {
|
||||
dev_err(&dev->dev, "%s - ezusb_writememory "
|
||||
"failed writing internal memory "
|
||||
"(%d %04X %p %d)\n", __func__, ret,
|
||||
be32_to_cpu(record->addr), record->data,
|
||||
be16_to_cpu(record->len));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = ezusb_set_reset(dev, fx.cpucs_reg, 1);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
record = (const struct ihex_binrec *)firmware->data;
|
||||
for (; record; record = ihex_next_binrec(record)) {
|
||||
if (be32_to_cpu(record->addr) <= fx.max_internal_adress) {
|
||||
ret = ezusb_writememory(dev, be32_to_cpu(record->addr),
|
||||
(unsigned char *)record->data,
|
||||
be16_to_cpu(record->len), WRITE_INT_RAM);
|
||||
if (ret < 0) {
|
||||
dev_err(&dev->dev, "%s - ezusb_writememory "
|
||||
"failed writing external memory "
|
||||
"(%d %04X %p %d)\n", __func__, ret,
|
||||
be32_to_cpu(record->addr), record->data,
|
||||
be16_to_cpu(record->len));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = ezusb_set_reset(dev, fx.cpucs_reg, 0);
|
||||
out:
|
||||
release_firmware(firmware);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ezusb_fx1_ihex_firmware_download(struct usb_device *dev,
|
||||
const char *firmware_path)
|
||||
{
|
||||
return ezusb_ihex_firmware_download(dev, ezusb_fx1, firmware_path);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ezusb_fx1_ihex_firmware_download);
|
||||
|
||||
int ezusb_fx2_ihex_firmware_download(struct usb_device *dev,
|
||||
const char *firmware_path)
|
||||
{
|
||||
return ezusb_ihex_firmware_download(dev, ezusb_fx2, firmware_path);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ezusb_fx2_ihex_firmware_download);
|
||||
|
||||
|
|
|
@ -38,8 +38,6 @@
|
|||
#include <linux/tty_flip.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/ihex.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/serial.h>
|
||||
|
@ -1167,10 +1165,7 @@ static void keyspan_close(struct usb_serial_port *port)
|
|||
/* download the firmware to a pre-renumeration device */
|
||||
static int keyspan_fake_startup(struct usb_serial *serial)
|
||||
{
|
||||
int response;
|
||||
const struct ihex_binrec *record;
|
||||
char *fw_name;
|
||||
const struct firmware *fw;
|
||||
char *fw_name;
|
||||
|
||||
dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
|
||||
le16_to_cpu(serial->dev->descriptor.bcdDevice),
|
||||
|
@ -1238,34 +1233,16 @@ static int keyspan_fake_startup(struct usb_serial *serial)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) {
|
||||
dev_err(&serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
|
||||
|
||||
/* download the firmware image */
|
||||
response = ezusb_fx1_set_reset(serial->dev, 1);
|
||||
|
||||
record = (const struct ihex_binrec *)fw->data;
|
||||
|
||||
while (record) {
|
||||
response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
|
||||
(unsigned char *)record->data,
|
||||
be16_to_cpu(record->len), 0xa0);
|
||||
if (response < 0) {
|
||||
dev_err(&serial->dev->dev, "ezusb_writememory failed for Keyspan firmware (%d %04X %p %d)\n",
|
||||
response, be32_to_cpu(record->addr),
|
||||
record->data, be16_to_cpu(record->len));
|
||||
break;
|
||||
}
|
||||
record = ihex_next_binrec(record);
|
||||
if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
|
||||
dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
|
||||
fw_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
release_firmware(fw);
|
||||
/* bring device out of reset. Renumeration will occur in a
|
||||
moment and the new device will bind to the real driver */
|
||||
response = ezusb_fx1_set_reset(serial->dev, 0);
|
||||
|
||||
/* after downloading firmware Renumeration will occur in a
|
||||
moment and the new device will bind to the real driver */
|
||||
|
||||
/* we don't want this device to have a driver assigned to it. */
|
||||
return 1;
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/ihex.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/serial.h>
|
||||
|
@ -675,8 +673,6 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial)
|
|||
{
|
||||
int response;
|
||||
const char *fw_name;
|
||||
const struct ihex_binrec *record;
|
||||
const struct firmware *fw;
|
||||
|
||||
/* download the firmware here ... */
|
||||
response = ezusb_fx1_set_reset(serial->dev, 1);
|
||||
|
@ -696,30 +692,15 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial)
|
|||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) {
|
||||
|
||||
if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
|
||||
dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
|
||||
fw_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
record = (const struct ihex_binrec *)fw->data;
|
||||
|
||||
while (record) {
|
||||
response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
|
||||
(unsigned char *)record->data,
|
||||
be16_to_cpu(record->len), 0xa0);
|
||||
if (response < 0) {
|
||||
dev_err(&serial->dev->dev, "ezusb_writememory failed "
|
||||
"for Keyspan PDA firmware (%d %04X %p %d)\n",
|
||||
response, be32_to_cpu(record->addr),
|
||||
record->data, be16_to_cpu(record->len));
|
||||
break;
|
||||
}
|
||||
record = ihex_next_binrec(record);
|
||||
}
|
||||
release_firmware(fw);
|
||||
/* bring device out of reset. Renumeration will occur in a moment
|
||||
and the new device will bind to the real driver */
|
||||
response = ezusb_fx1_set_reset(serial->dev, 0);
|
||||
/* after downloading firmware Renumeration will occur in a
|
||||
moment and the new device will bind to the real driver */
|
||||
|
||||
/* we want this device to fail to have a driver assigned to it. */
|
||||
return 1;
|
||||
|
|
|
@ -33,8 +33,6 @@
|
|||
#include <linux/serial.h>
|
||||
#include <linux/usb/serial.h>
|
||||
#include <linux/usb/ezusb.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/ihex.h>
|
||||
#include "whiteheat.h" /* WhiteHEAT specific commands */
|
||||
|
||||
#ifndef CMSPAR
|
||||
|
@ -194,84 +192,15 @@ static int firm_report_tx_done(struct usb_serial_port *port);
|
|||
static int whiteheat_firmware_download(struct usb_serial *serial,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
int response, ret = -ENOENT;
|
||||
const struct firmware *loader_fw = NULL, *firmware_fw = NULL;
|
||||
const struct ihex_binrec *record;
|
||||
int response;
|
||||
|
||||
if (request_ihex_firmware(&firmware_fw, "whiteheat.fw",
|
||||
&serial->dev->dev)) {
|
||||
dev_err(&serial->dev->dev,
|
||||
"%s - request \"whiteheat.fw\" failed\n", __func__);
|
||||
goto out;
|
||||
response = ezusb_fx1_ihex_firmware_download(serial->dev, "whiteheat_loader.fw");
|
||||
if (response >= 0) {
|
||||
response = ezusb_fx1_ihex_firmware_download(serial->dev, "whiteheat.fw");
|
||||
if (response >= 0)
|
||||
return 0;
|
||||
}
|
||||
if (request_ihex_firmware(&loader_fw, "whiteheat_loader.fw",
|
||||
&serial->dev->dev)) {
|
||||
dev_err(&serial->dev->dev,
|
||||
"%s - request \"whiteheat_loader.fw\" failed\n",
|
||||
__func__);
|
||||
goto out;
|
||||
}
|
||||
ret = 0;
|
||||
response = ezusb_fx1_set_reset(serial->dev, 1);
|
||||
|
||||
record = (const struct ihex_binrec *)loader_fw->data;
|
||||
while (record) {
|
||||
response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
|
||||
(unsigned char *)record->data,
|
||||
be16_to_cpu(record->len), 0xa0);
|
||||
if (response < 0) {
|
||||
dev_err(&serial->dev->dev, "%s - ezusb_writememory "
|
||||
"failed for loader (%d %04X %p %d)\n",
|
||||
__func__, response, be32_to_cpu(record->addr),
|
||||
record->data, be16_to_cpu(record->len));
|
||||
break;
|
||||
}
|
||||
record = ihex_next_binrec(record);
|
||||
}
|
||||
|
||||
response = ezusb_fx1_set_reset(serial->dev, 0);
|
||||
|
||||
record = (const struct ihex_binrec *)firmware_fw->data;
|
||||
while (record && be32_to_cpu(record->addr) < 0x1b40)
|
||||
record = ihex_next_binrec(record);
|
||||
while (record) {
|
||||
response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
|
||||
(unsigned char *)record->data,
|
||||
be16_to_cpu(record->len), 0xa3);
|
||||
if (response < 0) {
|
||||
dev_err(&serial->dev->dev, "%s - ezusb_writememory "
|
||||
"failed for first firmware step "
|
||||
"(%d %04X %p %d)\n", __func__, response,
|
||||
be32_to_cpu(record->addr), record->data,
|
||||
be16_to_cpu(record->len));
|
||||
break;
|
||||
}
|
||||
++record;
|
||||
}
|
||||
|
||||
response = ezusb_fx1_set_reset(serial->dev, 1);
|
||||
|
||||
record = (const struct ihex_binrec *)firmware_fw->data;
|
||||
while (record && be32_to_cpu(record->addr) < 0x1b40) {
|
||||
response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
|
||||
(unsigned char *)record->data,
|
||||
be16_to_cpu(record->len), 0xa0);
|
||||
if (response < 0) {
|
||||
dev_err(&serial->dev->dev, "%s - ezusb_writememory "
|
||||
"failed for second firmware step "
|
||||
"(%d %04X %p %d)\n", __func__, response,
|
||||
be32_to_cpu(record->addr), record->data,
|
||||
be16_to_cpu(record->len));
|
||||
break;
|
||||
}
|
||||
++record;
|
||||
}
|
||||
ret = 0;
|
||||
response = ezusb_fx1_set_reset(serial->dev, 0);
|
||||
out:
|
||||
release_firmware(loader_fw);
|
||||
release_firmware(firmware_fw);
|
||||
return ret;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче