diff options
author | Pavel Roskin <proski@gnu.org> | 2007-07-11 03:56:02 -0400 |
---|---|---|
committer | Guido Guenther <agx@bogon.sigxcpu.org> | 2007-07-15 12:19:05 -0400 |
commit | 250fd5d94bfd382b1b1e8864feff1e6e318c7626 (patch) | |
tree | 5d31f9af054488b00c7cd453006536983d340533 | |
parent | 7d879c70801f86dfb662f347b180e1c7ac41ec8f (diff) |
[PATCH] Protect firmware loading with a mutex
Otherwise, two devices could try to load and parse the same firmware at
the same time.
Signed-off-by: Pavel Roskin <proski@gnu.org>
-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) { |