ChangeSet 1.2065.3.17, 2005/03/12 08:25:14-08:00, [EMAIL PROTECTED]
[PATCH] pcmcia: pcmcia_device_add
Re-structure the adding of PCMCIA devices and the binding of devices and
drivers by cardmgr in bind_device: pcmcia_add_device() adds a new PCMCIA
device for a socket and a device function, if it hasn't been done
before.
Signed-off-by: Dominik Brodowski <[EMAIL PROTECTED]>
Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
drivers/pcmcia/ds.c | 160 ++++++++++++++++++++++++++++++++--------------------
include/pcmcia/ds.h | 3
2 files changed, 104 insertions(+), 59 deletions(-)
diff -Nru a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
--- a/drivers/pcmcia/ds.c 2005-03-12 21:28:07 -08:00
+++ b/drivers/pcmcia/ds.c 2005-03-12 21:28:07 -08:00
@@ -358,7 +358,8 @@
static void pcmcia_put_dev(struct pcmcia_device *p_dev)
{
- put_device(&p_dev->dev);
+ if (p_dev)
+ put_device(&p_dev->dev);
}
static void pcmcia_release_dev(struct device *dev)
@@ -428,6 +429,86 @@
}
+/* device_add_lock is needed to avoid double registration by cardmgr and
kernel.
+ * Serializes pcmcia_device_add; will most likely be removed in future.
+ *
+ * While it has the caveat that adding new PCMCIA devices inside(!)
device_register()
+ * won't work, this doesn't matter much at the moment: the driver core doesn't
+ * support it either.
+ */
+static DECLARE_MUTEX(device_add_lock);
+
+static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s,
unsigned int function, struct pcmcia_driver *p_drv)
+{
+ struct pcmcia_device *p_dev, *tmp_dev;
+ unsigned long flags;
+
+ s = pcmcia_get_bus_socket(s);
+ if (!s)
+ return NULL;
+
+ down(&device_add_lock);
+
+ p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
+ if (!p_dev)
+ goto err_put;
+ memset(p_dev, 0, sizeof(struct pcmcia_device));
+
+ p_dev->socket = s->parent;
+ p_dev->device_no = (s->device_count++);
+ p_dev->func = function;
+
+ p_dev->dev.bus = &pcmcia_bus_type;
+ p_dev->dev.parent = s->parent->dev.dev;
+ p_dev->dev.release = pcmcia_release_dev;
+ sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock,
p_dev->device_no);
+
+ /* temporary workaround */
+ p_dev->dev.driver = &p_drv->drv;
+
+ /* compat */
+ p_dev->client.client_magic = CLIENT_MAGIC;
+ p_dev->client.Socket = s->parent;
+ p_dev->client.Function = function;
+ p_dev->client.state = CLIENT_UNBOUND;
+
+ /* Add to the list in pcmcia_bus_socket, but only if no device
+ * with the same func _and_ driver exists */
+ spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list) {
+ if ((tmp_dev->func == function) &&
+ (tmp_dev->dev.driver == p_dev->dev.driver)){
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ goto err_free;
+ }
+ }
+ list_add_tail(&p_dev->socket_device_list, &s->devices_list);
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+ if (device_register(&p_dev->dev)) {
+ spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ list_del(&p_dev->socket_device_list);
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+ goto err_free;
+ }
+
+ pcmcia_device_probe(&p_dev->dev);
+
+ up(&device_add_lock);
+
+ return p_dev;
+
+ err_free:
+ kfree(p_dev);
+ s->device_count--;
+ err_put:
+ up(&device_add_lock);
+ pcmcia_put_bus_socket(s);
+
+ return NULL;
+}
+
/*======================================================================
These manage a ring buffer of events pending for one user process
@@ -597,9 +678,9 @@
static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
{
struct pcmcia_driver *p_drv;
- struct pcmcia_device *p_dev, *tmp_dev;
- unsigned long flags;
+ struct pcmcia_device *p_dev;
int ret = 0;
+ unsigned long flags;
s = pcmcia_get_bus_socket(s);
if (!s)
@@ -619,78 +700,39 @@
goto err_put_driver;
}
- /* Currently, the userspace pcmcia cardmgr detects pcmcia devices.
- * Here this information is translated into a kernel
- * struct pcmcia_device.
- */
-
- p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
- if (!p_dev) {
- ret = -ENOMEM;
- goto err_put_module;
- }
- memset(p_dev, 0, sizeof(struct pcmcia_device));
-
- p_dev->socket = s->parent;
- p_dev->device_no = (s->device_count++);
- p_dev->func = bind_info->function;
-
- p_dev->dev.bus = &pcmcia_bus_type;
- p_dev->dev.parent = s->parent->dev.dev;
- p_dev->dev.release = pcmcia_release_dev;
- sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock,
p_dev->device_no);
- p_dev->dev.driver = &p_drv->drv;
-
- /* compat */
- p_dev->client.client_magic = CLIENT_MAGIC;
- p_dev->client.Socket = s->parent;
- p_dev->client.Function = bind_info->function;
- p_dev->client.state = CLIENT_UNBOUND;
-
- /* Add to the list in pcmcia_bus_socket, but only if no device
- * with the same func _and_ driver exists */
+ /* if there's already a device registered, and it was registered
+ * by userspace before, we need to return the "instance". Therefore,
+ * we need to set the cardmgr flag */
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
- list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list) {
- if ((tmp_dev->func == bind_info->function) &&
- (tmp_dev->dev.driver == p_dev->dev.driver)){
+ list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+ if ((p_dev->func == bind_info->function) &&
+ (p_dev->dev.driver == &p_drv->drv) &&
+ (p_dev->cardmgr)) {
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
- bind_info->instance = tmp_dev->instance;
+ bind_info->instance = p_dev->instance;
ret = -EBUSY;
- goto err_free;
+ goto err_put_module;
}
}
- list_add_tail(&p_dev->socket_device_list, &s->devices_list);
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
- ret = device_register(&p_dev->dev);
- if (ret)
- goto err_free;
-
- ret = pcmcia_device_probe(&p_dev->dev);
- if (ret)
- goto err_unregister;
-
- module_put(p_drv->owner);
- put_driver(&p_drv->drv);
-
- return 0;
-
- err_unregister:
- device_unregister(&p_dev->dev);
- module_put(p_drv->owner);
- put_driver(&p_drv->drv);
- return (ret);
+ p_dev = pcmcia_device_add(s, bind_info->function, p_drv);
+ if (!p_dev) {
+ ret = -EIO;
+ goto err_put_module;
+ }
+ p_dev->cardmgr++;
- err_free:
- kfree(p_dev);
err_put_module:
module_put(p_drv->owner);
err_put_driver:
put_driver(&p_drv->drv);
err_put:
pcmcia_put_bus_socket(s);
+
return (ret);
} /* bind_request */
+
int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
{
diff -Nru a/include/pcmcia/ds.h b/include/pcmcia/ds.h
--- a/include/pcmcia/ds.h 2005-03-12 21:28:07 -08:00
+++ b/include/pcmcia/ds.h 2005-03-12 21:28:07 -08:00
@@ -169,6 +169,9 @@
event_callback_args_t event_callback_args;
} client;
+ /* registration by cardmgr done? */
+ unsigned int cardmgr;
+
struct device dev;
};
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html