diff options
Diffstat (limited to 'at76_usb.c')
-rw-r--r-- | at76_usb.c | 23 |
1 files changed, 18 insertions, 5 deletions
@@ -46,6 +46,9 @@ static int at76_debug = DBG_DEFAULTS; +/* Protect against concurrent firmware loading and parsing */ +static struct mutex fw_mutex; + static struct fwentry firmwares[] = { [0] = {""}, [BOARDTYPE_503_INTERSIL_3861] = {"atmel_at76c503-i3861.bin"}, @@ -5853,9 +5856,11 @@ static struct fwentry *at76_load_firmware(struct usb_device *udev, struct at76_fw_header *fwh; struct fwentry *fwe = &firmwares[board_type]; + mutex_lock(&fw_mutex); + if (fwe->loaded) { at76_dbg(DBG_FW, "re-using previously loaded fw"); - return fwe; + goto fw_out; } at76_dbg(DBG_FW, "downloading firmware %s", fwe->fwname); @@ -5864,7 +5869,7 @@ static struct fwentry *at76_load_firmware(struct usb_device *udev, err("firmware %s not found.", fwe->fwname); err("You may need to download the firmware from " "http://developer.berlios.de/projects/at76c503a/"); - return NULL; + goto fw_out; } at76_dbg(DBG_FW, "got it."); @@ -5872,7 +5877,7 @@ static struct fwentry *at76_load_firmware(struct usb_device *udev, if (fwe->fw->size <= sizeof(*fwh)) { err("firmware is too short (0x%zx)", fwe->fw->size); - return NULL; + goto fw_out; } /* CRC currently not checked */ @@ -5880,7 +5885,7 @@ static struct fwentry *at76_load_firmware(struct usb_device *udev, if (fwe->board_type != board_type) { err("board type mismatch, requested %u, got %u", board_type, fwe->board_type); - return NULL; + goto fw_out; } fwe->fw_version.major = fwh->major; @@ -5903,7 +5908,13 @@ static struct fwentry *at76_load_firmware(struct usb_device *udev, le32_to_cpu(fwh->ext_fw_offset), le32_to_cpu(fwh->ext_fw_len)); at76_dbg(DBG_DEVSTART, "firmware id %s", str); - return fwe; + fw_out: + mutex_unlock(&fw_mutex); + + if (fwe->loaded) + return fwe; + else + return NULL; } static int at76_probe(struct usb_interface *interface, @@ -6035,6 +6046,8 @@ static int __init at76_mod_init(void) printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " loading\n"); + mutex_init(&fw_mutex); + /* register this driver with the USB subsystem */ result = usb_register(&at76_driver); if (result < 0) { |