aboutsummaryrefslogtreecommitdiff
path: root/at76_usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'at76_usb.c')
-rw-r--r--at76_usb.c149
1 files changed, 42 insertions, 107 deletions
diff --git a/at76_usb.c b/at76_usb.c
index 649b1ce..59d9129 100644
--- a/at76_usb.c
+++ b/at76_usb.c
@@ -6028,58 +6028,43 @@ static int at76_init_new_device(struct at76_priv *dev)
}
-/**
- * at76_get_fw_info - disassembles the firmware image
- *
- * get version, str, internal and external fw part.
- * returns 0 on success, < 0 on error
- */
-static int at76_get_fw_info(u8 *fw_data, int fw_size,
- u32 *board, u32 *version, char **str,
- u8 **int_fw, int *int_fw_size,
- u8 **ext_fw, int *ext_fw_size)
-{
-/* fw structure (all numbers are little_endian)
- offset length description
- 0 4 crc 32 (seed ~0, no post, all gaps are zeros, header included)
- 4 4 board type (see at76_usb_ids.h)
- 8 4 version (major<<24|middle<<16|minor<<8|build)
- c 4 offset of printable string (id) area from begin of image
- (must be \0 terminated !)
- 10 4 offset of internal fw part area
- 14 4 length of internal fw part
- 18 4 offset of external fw part area (may be first byte _behind_
- image in case we have no external part)
- 1c 4 length of external fw part
-*/
-
- __le32 val;
+/* Parse the firmware image */
+static int at76_parse_fw(struct at76_priv *dev, u8 *fw_data, int fw_size,
+ int board_type)
+{
+ char *str;
+ struct at76_fw_header *fw = (struct at76_fw_header *)fw_data;
- if (fw_size < 0x21) {
- err("fw too short (x%x)", fw_size);
+ if (fw_size <= sizeof(*fw)) {
+ err("firmware is too short (0x%x)", fw_size);
return -EFAULT;
}
- /* crc currently not checked */
-
- memcpy(&val, fw_data + 4, 4);
- *board = le32_to_cpu(val);
-
- memcpy(&val, fw_data + 8, 4);
- *version = le32_to_cpu(val);
-
- memcpy(&val, fw_data + 0xc, 4);
- *str = fw_data + le32_to_cpu(val);
-
- memcpy(&val, fw_data + 0x10, 4);
- *int_fw = fw_data + le32_to_cpu(val);
- memcpy(&val, fw_data + 0x14, 4);
- *int_fw_size = le32_to_cpu(val);
+ /* CRC currently not checked */
+ dev->board_type = le32_to_cpu(fw->board_type);
+ dev->fw_version.major = fw->major;
+ dev->fw_version.minor = fw->minor;
+ dev->fw_version.patch = fw->patch;
+ dev->fw_version.build = fw->build;
+ str = (char *)fw_data + le32_to_cpu(fw->str_offset);
+ dev->intfw = (u8 *)fw + le32_to_cpu(fw->int_fw_offset);
+ dev->intfw_size = le32_to_cpu(fw->int_fw_len);
+ dev->extfw = (u8 *)fw + le32_to_cpu(fw->ext_fw_offset);
+ dev->extfw_size = le32_to_cpu(fw->ext_fw_len);
+
+ at76_dbg(DBG_DEVSTART, "firmware board %u version %u.%u.%u#%u "
+ "(int %x:%tx, ext %x:%tx)", dev->board_type,
+ dev->fw_version.major, dev->fw_version.minor,
+ dev->fw_version.patch, dev->fw_version.build,
+ dev->intfw_size, dev->intfw - fw_data,
+ dev->extfw_size, dev->extfw - fw_data);
+ at76_dbg(DBG_DEVSTART, "firmware id %s", str);
- memcpy(&val, fw_data + 0x18, 4);
- *ext_fw = fw_data + le32_to_cpu(val);
- memcpy(&val, fw_data + 0x1c, 4);
- *ext_fw_size = le32_to_cpu(val);
+ if (dev->board_type != board_type) {
+ err("inconsistent board types %u != %u", board_type,
+ dev->board_type);
+ return -EINVAL;
+ }
return 0;
}
@@ -6094,8 +6079,6 @@ static int at76_probe(struct usb_interface *interface,
const struct firmware *fw = firmwares[board_type].fw;
struct usb_device *udev = interface_to_usbdev(interface);
int op_mode;
- char *id_str;
- u32 version;
if (fw == NULL) {
at76_dbg(DBG_FW, "downloading firmware %s", fw_name);
@@ -6115,7 +6098,7 @@ static int at76_probe(struct usb_interface *interface,
if ((dev = at76_alloc_new_device(udev, (u8) board_type)) == NULL) {
ret = -ENOMEM;
- goto error;
+ goto error_alloc;
}
op_mode = at76_get_op_mode(udev);
@@ -6135,41 +6118,17 @@ static int at76_probe(struct usb_interface *interface,
goto error;
}
+ /* parse the firmware */
+ ret = at76_parse_fw(dev, fw->data, fw->size, board_type);
+ if (ret)
+ goto error;
+
if (op_mode != OPMODE_NORMAL_NIC_WITH_FLASH
&& op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) {
-
- at76_dbg(DBG_DEVSTART, "need to download firmware");
-
- /* parse the firmware */
- ret = at76_get_fw_info(fw->data, fw->size,
- &dev->board_type, &version, &id_str,
- &dev->intfw, &dev->intfw_size,
- &dev->extfw, &dev->extfw_size);
- if (ret)
- goto error;
-
- at76_dbg(DBG_DEVSTART,
- "firmware board %u version %u.%u.%u#%u "
- "(int %x:%tx, ext %x:%tx)", dev->board_type,
- version >> 24, (version >> 16) & 0xff,
- (version >> 8) & 0xff, version & 0xff, dev->intfw_size,
- dev->intfw - fw->data, dev->extfw_size,
- dev->extfw - fw->data);
- if (*id_str)
- at76_dbg(DBG_DEVSTART, "firmware id %s", id_str);
-
- if (dev->board_type != board_type) {
- err("inconsistent board types %u != %u", board_type,
- dev->board_type);
- at76_delete_device(dev);
- goto error;
- }
-
/* download internal firmware part */
at76_dbg(DBG_DEVSTART, "downloading internal firmware");
dev->istate = INTFW_DOWNLOAD;
schedule_work(&dev->work_internal_fw);
-
} else {
/* Internal firmware already inside the device. Get firmware
* version to test if external firmware is loaded.
@@ -6178,17 +6137,9 @@ static int at76_probe(struct usb_interface *interface,
* at76_get_op_mode() fail too :-( */
int force_fw_dwl = 0;
- /* parse the firmware */
- ret = at76_get_fw_info(fw->data, fw->size,
- &dev->board_type, &version, &id_str,
- &dev->intfw, &dev->intfw_size,
- &dev->extfw, &dev->extfw_size);
- if (ret)
- goto error;
-
/* if version >= 0.100.x.y or device with built-in flash we can
* query the device for the fw version */
- if (version >= ((0 << 24) | (100 << 16))
+ if ((dev->fw_version.major > 0 || dev->fw_version.minor >= 100)
|| (op_mode == OPMODE_NORMAL_NIC_WITH_FLASH)) {
ret = at76_get_mib(udev, MIB_FW_VERSION,
&dev->fw_version,
@@ -6210,36 +6161,20 @@ static int at76_probe(struct usb_interface *interface,
at76_dbg(DBG_DEVSTART,
"cannot get firmware (ret %d) or all zeros "
"- download external firmware", ret);
- at76_dbg(DBG_DEVSTART,
- "firmware board %u version %u.%u.%u#%u "
- "(int %x:%tx, ext %x:%tx)", dev->board_type,
- version >> 24, (version >> 16) & 0xff,
- (version >> 8) & 0xff, version & 0xff,
- dev->intfw_size, dev->intfw - fw->data,
- dev->extfw_size, dev->extfw - fw->data);
- if (*id_str)
- at76_dbg(DBG_DEVSTART, "firmware id %s",
- id_str);
-
- if (dev->board_type != board_type) {
- err("inconsistent board types %u != %u",
- board_type, dev->board_type);
- at76_delete_device(dev);
- goto error;
- }
dev->istate = EXTFW_DOWNLOAD;
schedule_work(&dev->work_external_fw);
} else {
dev->istate = INIT;
- if ((ret = at76_init_new_device(dev)) < 0) {
+ if ((ret = at76_init_new_device(dev)) < 0)
goto error;
- }
}
}
return 0;
error:
+ at76_delete_device(dev);
+ error_alloc:
usb_put_dev(udev);
return ret;
}