summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/zd1211rw
diff options
context:
space:
mode:
authorDaniel Drake <dsd@gentoo.org>2006-08-12 17:59:59 +0100
committerJohn W. Linville <linville@tuxdriver.com>2006-08-14 15:43:22 -0400
commitd066c2190de86d75e17dc35beba48b920cb125ee (patch)
tree7920cc3c65f77122e1aa65ed4337580c80537257 /drivers/net/wireless/zd1211rw
parent12f393089775ca33c53541eb67112fc04d799131 (diff)
downloadlinux-3.10-d066c2190de86d75e17dc35beba48b920cb125ee.tar.gz
linux-3.10-d066c2190de86d75e17dc35beba48b920cb125ee.tar.bz2
linux-3.10-d066c2190de86d75e17dc35beba48b920cb125ee.zip
[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/wireless/zd1211rw')
-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 9f663f66901..4b125085989 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -638,6 +638,7 @@ enum {
LOAD_CODE_SIZE = 0xe, /* words */
LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */
EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
+ EEPROM_REGS_SIZE = 0x7e, /* words */
E2P_BASE_OFFSET = EEPROM_START_OFFSET +
EEPROM_REGS_OFFSET,
};
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 2e89c2e3a05..06f72cbaf0a 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -16,6 +16,7 @@
*/
#include <asm/unaligned.h>
+#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/firmware.h>
@@ -267,6 +268,39 @@ static char *get_fw_name(char *buffer, size_t size, u8 device_type,
return buffer;
}
+static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
+ const struct firmware *ub_fw)
+{
+ const struct firmware *ur_fw = NULL;
+ int offset;
+ int r = 0;
+ char fw_name[128];
+
+ r = request_fw_file(&ur_fw,
+ get_fw_name(fw_name, sizeof(fw_name), device_type, "ur"),
+ &udev->dev);
+ if (r)
+ goto error;
+
+ r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
+ REBOOT);
+ if (r)
+ goto error;
+
+ offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
+ r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
+ E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
+
+ /* At this point, the vendor driver downloads the whole firmware
+ * image, hacks around with version IDs, and uploads it again,
+ * completely overwriting the boot code. We do not do this here as
+ * it is not required on any tested devices, and it is suspected to
+ * cause problems. */
+error:
+ release_firmware(ur_fw);
+ return r;
+}
+
static int upload_firmware(struct usb_device *udev, u8 device_type)
{
int r;
@@ -286,15 +320,17 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
- /* FIXME: do we have any reason to perform the kludge that the vendor
- * driver does when there is a version mismatch? (their driver uploads
- * different firmwares and stuff)
- */
if (fw_bcdDevice != bcdDevice) {
dev_info(&udev->dev,
- "firmware device id %#06x and actual device id "
- "%#06x differ, continuing anyway\n",
- fw_bcdDevice, bcdDevice);
+ "firmware version %#06x and device bootcode version "
+ "%#06x differ\n", fw_bcdDevice, bcdDevice);
+ if (bcdDevice <= 0x4313)
+ dev_warn(&udev->dev, "device has old bootcode, please "
+ "report success or failure\n");
+
+ r = handle_version_mismatch(udev, device_type, ub_fw);
+ if (r)
+ goto error;
} else {
dev_dbg_f(&udev->dev,
"firmware device id %#06x is equal to the "