Commit d0ec1bd1 authored by Stephen Hemminger's avatar Stephen Hemminger

[IRDA]: Dongle module owner support.

parent f660517d
...@@ -85,7 +85,7 @@ static void irda_task_timer_expired(void *data); ...@@ -85,7 +85,7 @@ static void irda_task_timer_expired(void *data);
int __init irda_device_init( void) int __init irda_device_init( void)
{ {
dongles = hashbin_new(HB_LOCK); dongles = hashbin_new(HB_NOLOCK);
if (dongles == NULL) { if (dongles == NULL) {
printk(KERN_WARNING "IrDA: Can't allocate dongles hashbin!\n"); printk(KERN_WARNING "IrDA: Can't allocate dongles hashbin!\n");
return -ENOMEM; return -ENOMEM;
...@@ -109,7 +109,9 @@ void __exit irda_device_cleanup(void) ...@@ -109,7 +109,9 @@ void __exit irda_device_cleanup(void)
IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete); hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete);
spin_lock(&dongles->hb_spinlock);
hashbin_delete(dongles, NULL); hashbin_delete(dongles, NULL);
spin_unlock(&dongles->hb_spinlock);
} }
/* /*
...@@ -424,25 +426,34 @@ int irda_device_txqueue_empty(struct net_device *dev) ...@@ -424,25 +426,34 @@ int irda_device_txqueue_empty(struct net_device *dev)
dongle_t *irda_device_dongle_init(struct net_device *dev, int type) dongle_t *irda_device_dongle_init(struct net_device *dev, int type)
{ {
struct dongle_reg *reg; struct dongle_reg *reg;
dongle_t *dongle; dongle_t *dongle = NULL;
ASSERT(dev != NULL, return NULL;); might_sleep();
spin_lock(&dongles->hb_spinlock);
reg = hashbin_find(dongles, type, NULL);
#ifdef CONFIG_KMOD #ifdef CONFIG_KMOD
ASSERT(!in_interrupt(), return NULL;);
/* Try to load the module needed */ /* Try to load the module needed */
if (!reg && capable(CAP_SYS_MODULE)) {
spin_unlock(&dongles->hb_spinlock);
request_module("irda-dongle-%d", type); request_module("irda-dongle-%d", type);
spin_lock(&dongles->hb_spinlock);
reg = hashbin_find(dongles, type, NULL);
}
#endif #endif
if (!(reg = hashbin_lock_find(dongles, type, NULL))) { if (!reg || !try_module_get(reg->owner) ) {
ERROR("IrDA: Unable to find requested dongle\n"); ERROR("IrDA: Unable to find requested dongle type %x\n", type);
return NULL; goto out;
} }
/* Allocate dongle info for this instance */ /* Allocate dongle info for this instance */
dongle = kmalloc(sizeof(dongle_t), GFP_KERNEL); dongle = kmalloc(sizeof(dongle_t), GFP_KERNEL);
if (!dongle) if (!dongle)
return NULL; goto out;
memset(dongle, 0, sizeof(dongle_t)); memset(dongle, 0, sizeof(dongle_t));
...@@ -450,6 +461,8 @@ dongle_t *irda_device_dongle_init(struct net_device *dev, int type) ...@@ -450,6 +461,8 @@ dongle_t *irda_device_dongle_init(struct net_device *dev, int type)
dongle->issue = reg; dongle->issue = reg;
dongle->dev = dev; dongle->dev = dev;
out:
spin_unlock(&dongles->hb_spinlock);
return dongle; return dongle;
} }
...@@ -461,7 +474,7 @@ int irda_device_dongle_cleanup(dongle_t *dongle) ...@@ -461,7 +474,7 @@ int irda_device_dongle_cleanup(dongle_t *dongle)
ASSERT(dongle != NULL, return -1;); ASSERT(dongle != NULL, return -1;);
dongle->issue->close(dongle); dongle->issue->close(dongle);
module_put(dongle->issue->owner);
kfree(dongle); kfree(dongle);
return 0; return 0;
...@@ -472,14 +485,16 @@ int irda_device_dongle_cleanup(dongle_t *dongle) ...@@ -472,14 +485,16 @@ int irda_device_dongle_cleanup(dongle_t *dongle)
*/ */
int irda_device_register_dongle(struct dongle_reg *new) int irda_device_register_dongle(struct dongle_reg *new)
{ {
spin_lock(&dongles->hb_spinlock);
/* Check if this dongle has been registered before */ /* Check if this dongle has been registered before */
if (hashbin_lock_find(dongles, new->type, NULL)) { if (hashbin_find(dongles, new->type, NULL)) {
MESSAGE("%s: Dongle already registered\n", __FUNCTION__); MESSAGE("%s: Dongle type %x already registered\n",
return 0; __FUNCTION__, new->type);
} } else {
/* Insert IrDA dongle into hashbin */ /* Insert IrDA dongle into hashbin */
hashbin_insert(dongles, (irda_queue_t *) new, new->type, NULL); hashbin_insert(dongles, (irda_queue_t *) new, new->type, NULL);
}
spin_unlock(&dongles->hb_spinlock);
return 0; return 0;
} }
...@@ -494,11 +509,11 @@ void irda_device_unregister_dongle(struct dongle_reg *dongle) ...@@ -494,11 +509,11 @@ void irda_device_unregister_dongle(struct dongle_reg *dongle)
{ {
struct dongle *node; struct dongle *node;
spin_lock(&dongles->hb_spinlock);
node = hashbin_remove(dongles, dongle->type, NULL); node = hashbin_remove(dongles, dongle->type, NULL);
if (!node) { if (!node)
ERROR("%s: dongle not found!\n", __FUNCTION__); ERROR("%s: dongle not found!\n", __FUNCTION__);
return; spin_unlock(&dongles->hb_spinlock);
}
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment