mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 16:54:20 +08:00
[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>
This commit is contained in:
parent
12f3930897
commit
d066c2190d
@ -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,
|
||||
};
|
||||
|
@ -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 "
|
||||
|
Loading…
Reference in New Issue
Block a user