aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorDaniel Drake <dsd@gentoo.org>2006-08-12 12:59:59 -0400
committerJohn W. Linville <linville@tuxdriver.com>2006-08-14 15:43:22 -0400
commitd066c2190de86d75e17dc35beba48b920cb125ee (patch)
tree7920cc3c65f77122e1aa65ed4337580c80537257 /drivers/net
parent12f393089775ca33c53541eb67112fc04d799131 (diff)
[PATCH] zd1211rw: Firmware version vs bootcode version mismatch handling
This is needed for my G220F, otherwise it fails to initialize after the existing firmware upload routine. The vendor driver actually does more than what I have done here: it downloads the firmware + boot code, modifies it, and uploads it again (really messy). I have not copied that part over, as my device can get on its feet without it. Signed-off-by: Daniel Drake <dsd@gentoo.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c50
2 files changed, 44 insertions, 7 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 9f663f66901a..4b1250859897 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -638,6 +638,7 @@ enum {
638 LOAD_CODE_SIZE = 0xe, /* words */ 638 LOAD_CODE_SIZE = 0xe, /* words */
639 LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */ 639 LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */
640 EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE, 640 EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
641 EEPROM_REGS_SIZE = 0x7e, /* words */
641 E2P_BASE_OFFSET = EEPROM_START_OFFSET + 642 E2P_BASE_OFFSET = EEPROM_START_OFFSET +
642 EEPROM_REGS_OFFSET, 643 EEPROM_REGS_OFFSET,
643}; 644};
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 2e89c2e3a053..06f72cbaf0ad 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -16,6 +16,7 @@
16 */ 16 */
17 17
18#include <asm/unaligned.h> 18#include <asm/unaligned.h>
19#include <linux/kernel.h>
19#include <linux/init.h> 20#include <linux/init.h>
20#include <linux/module.h> 21#include <linux/module.h>
21#include <linux/firmware.h> 22#include <linux/firmware.h>
@@ -267,6 +268,39 @@ static char *get_fw_name(char *buffer, size_t size, u8 device_type,
267 return buffer; 268 return buffer;
268} 269}
269 270
271static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
272 const struct firmware *ub_fw)
273{
274 const struct firmware *ur_fw = NULL;
275 int offset;
276 int r = 0;
277 char fw_name[128];
278
279 r = request_fw_file(&ur_fw,
280 get_fw_name(fw_name, sizeof(fw_name), device_type, "ur"),
281 &udev->dev);
282 if (r)
283 goto error;
284
285 r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
286 REBOOT);
287 if (r)
288 goto error;
289
290 offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
291 r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
292 E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
293
294 /* At this point, the vendor driver downloads the whole firmware
295 * image, hacks around with version IDs, and uploads it again,
296 * completely overwriting the boot code. We do not do this here as
297 * it is not required on any tested devices, and it is suspected to
298 * cause problems. */
299error:
300 release_firmware(ur_fw);
301 return r;
302}
303
270static int upload_firmware(struct usb_device *udev, u8 device_type) 304static int upload_firmware(struct usb_device *udev, u8 device_type)
271{ 305{
272 int r; 306 int r;
@@ -286,15 +320,17 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
286 320
287 fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET); 321 fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
288 322
289 /* FIXME: do we have any reason to perform the kludge that the vendor
290 * driver does when there is a version mismatch? (their driver uploads
291 * different firmwares and stuff)
292 */
293 if (fw_bcdDevice != bcdDevice) { 323 if (fw_bcdDevice != bcdDevice) {
294 dev_info(&udev->dev, 324 dev_info(&udev->dev,
295 "firmware device id %#06x and actual device id " 325 "firmware version %#06x and device bootcode version "
296 "%#06x differ, continuing anyway\n", 326 "%#06x differ\n", fw_bcdDevice, bcdDevice);
297 fw_bcdDevice, bcdDevice); 327 if (bcdDevice <= 0x4313)
328 dev_warn(&udev->dev, "device has old bootcode, please "
329 "report success or failure\n");
330
331 r = handle_version_mismatch(udev, device_type, ub_fw);
332 if (r)
333 goto error;
298 } else { 334 } else {
299 dev_dbg_f(&udev->dev, 335 dev_dbg_f(&udev->dev,
300 "firmware device id %#06x is equal to the " 336 "firmware device id %#06x is equal to the "