From 250fd5d94bfd382b1b1e8864feff1e6e318c7626 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Wed, 11 Jul 2007 03:56:02 -0400 Subject: [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 --- at76_usb.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/at76_usb.c b/at76_usb.c index 2a3a784..0ec97e1 100644 --- a/at76_usb.c +++ b/at76_usb.c @@ -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) { -- cgit v1.2.3