aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Roskin <proski@gnu.org>2007-07-11 03:56:02 -0400
committerGuido Guenther <agx@bogon.sigxcpu.org>2007-07-15 12:19:05 -0400
commit250fd5d94bfd382b1b1e8864feff1e6e318c7626 (patch)
tree5d31f9af054488b00c7cd453006536983d340533
parent7d879c70801f86dfb662f347b180e1c7ac41ec8f (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.c23
1 files 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) {