aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
authorRene Buergel <rene.buergel@sohard.de>2012-09-18 03:02:01 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-09-18 12:26:30 -0400
commit8d733e26c076f47e7774c0e5baa74c9b1c01199a (patch)
tree9c7d8885361c63325f0fb7e1ca3f0da00ed89fce /drivers/usb/serial
parentcc183e2a5ebfdddc8d3498149cae6b4c40551a68 (diff)
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>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/ezusb.c79
-rw-r--r--drivers/usb/serial/keyspan.c39
-rw-r--r--drivers/usb/serial/keyspan_pda.c29
-rw-r--r--drivers/usb/serial/whiteheat.c85
4 files changed, 99 insertions, 133 deletions
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
index bc3076f2c066..4223d761223d 100644
--- a/drivers/usb/serial/ezusb.c
+++ b/drivers/usb/serial/ezusb.c
@@ -13,6 +13,8 @@
13#include <linux/slab.h> 13#include <linux/slab.h>
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/usb.h> 15#include <linux/usb.h>
16#include <linux/firmware.h>
17#include <linux/ihex.h>
16 18
17struct ezusb_fx_type { 19struct ezusb_fx_type {
18 /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ 20 /* 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)
79 return ezusb_set_reset(dev, ezusb_fx2.cpucs_reg, reset_bit); 81 return ezusb_set_reset(dev, ezusb_fx2.cpucs_reg, reset_bit);
80} 82}
81EXPORT_SYMBOL_GPL(ezusb_fx2_set_reset); 83EXPORT_SYMBOL_GPL(ezusb_fx2_set_reset);
84
85static int ezusb_ihex_firmware_download(struct usb_device *dev,
86 struct ezusb_fx_type fx,
87 const char *firmware_path)
88{
89 int ret = -ENOENT;
90 const struct firmware *firmware = NULL;
91 const struct ihex_binrec *record;
92
93 if (request_ihex_firmware(&firmware, firmware_path,
94 &dev->dev)) {
95 dev_err(&dev->dev,
96 "%s - request \"%s\" failed\n",
97 __func__, firmware_path);
98 goto out;
99 }
100
101 ret = ezusb_set_reset(dev, fx.cpucs_reg, 0);
102 if (ret < 0)
103 goto out;
104
105 record = (const struct ihex_binrec *)firmware->data;
106 for (; record; record = ihex_next_binrec(record)) {
107 if (be32_to_cpu(record->addr) > fx.max_internal_adress) {
108 ret = ezusb_writememory(dev, be32_to_cpu(record->addr),
109 (unsigned char *)record->data,
110 be16_to_cpu(record->len), WRITE_EXT_RAM);
111 if (ret < 0) {
112 dev_err(&dev->dev, "%s - ezusb_writememory "
113 "failed writing internal memory "
114 "(%d %04X %p %d)\n", __func__, ret,
115 be32_to_cpu(record->addr), record->data,
116 be16_to_cpu(record->len));
117 goto out;
118 }
119 }
120 }
121
122 ret = ezusb_set_reset(dev, fx.cpucs_reg, 1);
123 if (ret < 0)
124 goto out;
125 record = (const struct ihex_binrec *)firmware->data;
126 for (; record; record = ihex_next_binrec(record)) {
127 if (be32_to_cpu(record->addr) <= fx.max_internal_adress) {
128 ret = ezusb_writememory(dev, be32_to_cpu(record->addr),
129 (unsigned char *)record->data,
130 be16_to_cpu(record->len), WRITE_INT_RAM);
131 if (ret < 0) {
132 dev_err(&dev->dev, "%s - ezusb_writememory "
133 "failed writing external memory "
134 "(%d %04X %p %d)\n", __func__, ret,
135 be32_to_cpu(record->addr), record->data,
136 be16_to_cpu(record->len));
137 goto out;
138 }
139 }
140 }
141 ret = ezusb_set_reset(dev, fx.cpucs_reg, 0);
142out:
143 release_firmware(firmware);
144 return ret;
145}
146
147int ezusb_fx1_ihex_firmware_download(struct usb_device *dev,
148 const char *firmware_path)
149{
150 return ezusb_ihex_firmware_download(dev, ezusb_fx1, firmware_path);
151}
152EXPORT_SYMBOL_GPL(ezusb_fx1_ihex_firmware_download);
153
154int ezusb_fx2_ihex_firmware_download(struct usb_device *dev,
155 const char *firmware_path)
156{
157 return ezusb_ihex_firmware_download(dev, ezusb_fx2, firmware_path);
158}
159EXPORT_SYMBOL_GPL(ezusb_fx2_ihex_firmware_download);
160
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 4f25849d343e..0acb07131f6e 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -38,8 +38,6 @@
38#include <linux/tty_flip.h> 38#include <linux/tty_flip.h>
39#include <linux/module.h> 39#include <linux/module.h>
40#include <linux/spinlock.h> 40#include <linux/spinlock.h>
41#include <linux/firmware.h>
42#include <linux/ihex.h>
43#include <linux/uaccess.h> 41#include <linux/uaccess.h>
44#include <linux/usb.h> 42#include <linux/usb.h>
45#include <linux/usb/serial.h> 43#include <linux/usb/serial.h>
@@ -1167,10 +1165,7 @@ static void keyspan_close(struct usb_serial_port *port)
1167/* download the firmware to a pre-renumeration device */ 1165/* download the firmware to a pre-renumeration device */
1168static int keyspan_fake_startup(struct usb_serial *serial) 1166static int keyspan_fake_startup(struct usb_serial *serial)
1169{ 1167{
1170 int response; 1168 char *fw_name;
1171 const struct ihex_binrec *record;
1172 char *fw_name;
1173 const struct firmware *fw;
1174 1169
1175 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n", 1170 dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
1176 le16_to_cpu(serial->dev->descriptor.bcdDevice), 1171 le16_to_cpu(serial->dev->descriptor.bcdDevice),
@@ -1238,34 +1233,16 @@ static int keyspan_fake_startup(struct usb_serial *serial)
1238 return 1; 1233 return 1;
1239 } 1234 }
1240 1235
1241 if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) {
1242 dev_err(&serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name);
1243 return 1;
1244 }
1245
1246 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name); 1236 dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
1247 1237
1248 /* download the firmware image */ 1238 if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
1249 response = ezusb_fx1_set_reset(serial->dev, 1); 1239 dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
1250 1240 fw_name);
1251 record = (const struct ihex_binrec *)fw->data; 1241 return -ENOENT;
1252
1253 while (record) {
1254 response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
1255 (unsigned char *)record->data,
1256 be16_to_cpu(record->len), 0xa0);
1257 if (response < 0) {
1258 dev_err(&serial->dev->dev, "ezusb_writememory failed for Keyspan firmware (%d %04X %p %d)\n",
1259 response, be32_to_cpu(record->addr),
1260 record->data, be16_to_cpu(record->len));
1261 break;
1262 }
1263 record = ihex_next_binrec(record);
1264 } 1242 }
1265 release_firmware(fw); 1243
1266 /* bring device out of reset. Renumeration will occur in a 1244 /* after downloading firmware Renumeration will occur in a
1267 moment and the new device will bind to the real driver */ 1245 moment and the new device will bind to the real driver */
1268 response = ezusb_fx1_set_reset(serial->dev, 0);
1269 1246
1270 /* we don't want this device to have a driver assigned to it. */ 1247 /* we don't want this device to have a driver assigned to it. */
1271 return 1; 1248 return 1;
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 39ab6687ce23..e1cada31356e 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -25,8 +25,6 @@
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/spinlock.h> 26#include <linux/spinlock.h>
27#include <linux/workqueue.h> 27#include <linux/workqueue.h>
28#include <linux/firmware.h>
29#include <linux/ihex.h>
30#include <linux/uaccess.h> 28#include <linux/uaccess.h>
31#include <linux/usb.h> 29#include <linux/usb.h>
32#include <linux/usb/serial.h> 30#include <linux/usb/serial.h>
@@ -675,8 +673,6 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial)
675{ 673{
676 int response; 674 int response;
677 const char *fw_name; 675 const char *fw_name;
678 const struct ihex_binrec *record;
679 const struct firmware *fw;
680 676
681 /* download the firmware here ... */ 677 /* download the firmware here ... */
682 response = ezusb_fx1_set_reset(serial->dev, 1); 678 response = ezusb_fx1_set_reset(serial->dev, 1);
@@ -696,30 +692,15 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial)
696 __func__); 692 __func__);
697 return -ENODEV; 693 return -ENODEV;
698 } 694 }
699 if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) { 695
696 if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
700 dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n", 697 dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
701 fw_name); 698 fw_name);
702 return -ENOENT; 699 return -ENOENT;
703 } 700 }
704 record = (const struct ihex_binrec *)fw->data; 701
705 702 /* after downloading firmware Renumeration will occur in a
706 while (record) { 703 moment and the new device will bind to the real driver */
707 response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
708 (unsigned char *)record->data,
709 be16_to_cpu(record->len), 0xa0);
710 if (response < 0) {
711 dev_err(&serial->dev->dev, "ezusb_writememory failed "
712 "for Keyspan PDA firmware (%d %04X %p %d)\n",
713 response, be32_to_cpu(record->addr),
714 record->data, be16_to_cpu(record->len));
715 break;
716 }
717 record = ihex_next_binrec(record);
718 }
719 release_firmware(fw);
720 /* bring device out of reset. Renumeration will occur in a moment
721 and the new device will bind to the real driver */
722 response = ezusb_fx1_set_reset(serial->dev, 0);
723 704
724 /* we want this device to fail to have a driver assigned to it. */ 705 /* we want this device to fail to have a driver assigned to it. */
725 return 1; 706 return 1;
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 8172ea3aead0..efa32bf5f758 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -33,8 +33,6 @@
33#include <linux/serial.h> 33#include <linux/serial.h>
34#include <linux/usb/serial.h> 34#include <linux/usb/serial.h>
35#include <linux/usb/ezusb.h> 35#include <linux/usb/ezusb.h>
36#include <linux/firmware.h>
37#include <linux/ihex.h>
38#include "whiteheat.h" /* WhiteHEAT specific commands */ 36#include "whiteheat.h" /* WhiteHEAT specific commands */
39 37
40#ifndef CMSPAR 38#ifndef CMSPAR
@@ -194,84 +192,15 @@ static int firm_report_tx_done(struct usb_serial_port *port);
194static int whiteheat_firmware_download(struct usb_serial *serial, 192static int whiteheat_firmware_download(struct usb_serial *serial,
195 const struct usb_device_id *id) 193 const struct usb_device_id *id)
196{ 194{
197 int response, ret = -ENOENT; 195 int response;
198 const struct firmware *loader_fw = NULL, *firmware_fw = NULL;
199 const struct ihex_binrec *record;
200 196
201 if (request_ihex_firmware(&firmware_fw, "whiteheat.fw", 197 response = ezusb_fx1_ihex_firmware_download(serial->dev, "whiteheat_loader.fw");
202 &serial->dev->dev)) { 198 if (response >= 0) {
203 dev_err(&serial->dev->dev, 199 response = ezusb_fx1_ihex_firmware_download(serial->dev, "whiteheat.fw");
204 "%s - request \"whiteheat.fw\" failed\n", __func__); 200 if (response >= 0)
205 goto out; 201 return 0;
206 }
207 if (request_ihex_firmware(&loader_fw, "whiteheat_loader.fw",
208 &serial->dev->dev)) {
209 dev_err(&serial->dev->dev,
210 "%s - request \"whiteheat_loader.fw\" failed\n",
211 __func__);
212 goto out;
213 }
214 ret = 0;
215 response = ezusb_fx1_set_reset(serial->dev, 1);
216
217 record = (const struct ihex_binrec *)loader_fw->data;
218 while (record) {
219 response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
220 (unsigned char *)record->data,
221 be16_to_cpu(record->len), 0xa0);
222 if (response < 0) {
223 dev_err(&serial->dev->dev, "%s - ezusb_writememory "
224 "failed for loader (%d %04X %p %d)\n",
225 __func__, response, be32_to_cpu(record->addr),
226 record->data, be16_to_cpu(record->len));
227 break;
228 }
229 record = ihex_next_binrec(record);
230 }
231
232 response = ezusb_fx1_set_reset(serial->dev, 0);
233
234 record = (const struct ihex_binrec *)firmware_fw->data;
235 while (record && be32_to_cpu(record->addr) < 0x1b40)
236 record = ihex_next_binrec(record);
237 while (record) {
238 response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
239 (unsigned char *)record->data,
240 be16_to_cpu(record->len), 0xa3);
241 if (response < 0) {
242 dev_err(&serial->dev->dev, "%s - ezusb_writememory "
243 "failed for first firmware step "
244 "(%d %04X %p %d)\n", __func__, response,
245 be32_to_cpu(record->addr), record->data,
246 be16_to_cpu(record->len));
247 break;
248 }
249 ++record;
250 }
251
252 response = ezusb_fx1_set_reset(serial->dev, 1);
253
254 record = (const struct ihex_binrec *)firmware_fw->data;
255 while (record && be32_to_cpu(record->addr) < 0x1b40) {
256 response = ezusb_writememory(serial->dev, be32_to_cpu(record->addr),
257 (unsigned char *)record->data,
258 be16_to_cpu(record->len), 0xa0);
259 if (response < 0) {
260 dev_err(&serial->dev->dev, "%s - ezusb_writememory "
261 "failed for second firmware step "
262 "(%d %04X %p %d)\n", __func__, response,
263 be32_to_cpu(record->addr), record->data,
264 be16_to_cpu(record->len));
265 break;
266 }
267 ++record;
268 } 202 }
269 ret = 0; 203 return -ENOENT;
270 response = ezusb_fx1_set_reset(serial->dev, 0);
271 out:
272 release_firmware(loader_fw);
273 release_firmware(firmware_fw);
274 return ret;
275} 204}
276 205
277 206