]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] pcmcia: new ds - cs interface
authorDominik Brodowski <linux@dominikbrodowski.de>
Tue, 11 Jan 2005 11:19:00 +0000 (03:19 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Tue, 11 Jan 2005 11:19:00 +0000 (03:19 -0800)
Add a new registration function to register the PCMCIA 16-bit subsystem
(ds a.k.a. pcmcia) with the PCMICA core (cs a.k.a. pcmcia_core).

As send_event is only called with skt->sem held, we can use that to safeguard
skt->callback(), too. Note that the class_device_register() call by pccardd()
is done _before_ skt->sem() is held, and the pcmcia_socket_register() doesn't
hold skt->sem() as well, so there is no chance for a deadlock.

Signed-off-by: Dominik Brodowski <linux@brodo.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/pcmcia/cs.c
drivers/pcmcia/cs_internal.h
drivers/pcmcia/ds.c
include/pcmcia/ss.h

index 4e4c964f7e01bfa595ab948efb159c14787ac78c..7a522f0eed8853f38e9a95c6057d1e60298f23ca 100644 (file)
@@ -349,8 +349,6 @@ static void free_regions(memory_handle_t *list)
     }
 }
 
-static int send_event(struct pcmcia_socket *s, event_t event, int priority);
-
 static void shutdown_socket(struct pcmcia_socket *s)
 {
     client_t **c;
@@ -402,6 +400,26 @@ static void shutdown_socket(struct pcmcia_socket *s)
     
 ======================================================================*/
 
+
+static int pcmcia_send_event(struct pcmcia_socket *s, event_t event, int priority)
+{
+       int ret;
+
+       if (!s->callback)
+               return 0;
+       if (!try_module_get(s->callback->owner))
+               return 0;
+
+       ret = s->callback->event(s, event, priority);
+
+       module_put(s->callback->owner);
+
+       return ret;
+}
+
+
+/* NOTE: send_event needs to be called with skt->sem held. */
+
 static int send_event(struct pcmcia_socket *s, event_t event, int priority)
 {
     client_t *client = s->clients;
@@ -411,6 +429,11 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority)
     ret = 0;
     if (s->state & SOCKET_CARDBUS)
            return 0;
+
+    ret = pcmcia_send_event(s, event, priority);
+    if (ret)
+           return (ret);
+
     for (; client; client = client->next) { 
        if (client->state & (CLIENT_UNBOUND|CLIENT_STALE))
            continue;
@@ -1363,6 +1386,34 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
     return CS_OUT_OF_RESOURCE;
 } /* register_client */
 
+/* register pcmcia_callback */
+int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
+{
+        int ret = 0;
+
+       /* s->skt_sem also protects s->callback */
+       down(&s->skt_sem);
+
+       if (c) {
+               /* registration */
+               if (s->callback) {
+                       ret = -EBUSY;
+                       goto err;
+               }
+
+               s->callback = c;
+
+               if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT)
+                       pcmcia_send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+       } else
+               s->callback = NULL;
+ err:
+       up(&s->skt_sem);
+
+       return ret;
+}
+EXPORT_SYMBOL(pccard_register_pcmcia);
+
 /*====================================================================*/
 
 int pcmcia_release_configuration(client_handle_t handle)
index fbce6b67988b22ed80f55146c767d4e8ad0337c4..dcb1c651724f5998e49e833d2251880ab5bfdbdd 100644 (file)
@@ -173,6 +173,14 @@ int pccard_reset_card(struct pcmcia_socket *skt);
 int pccard_get_status(struct pcmcia_socket *s, unsigned int function, cs_status_t *status);
 int pccard_access_configuration_register(struct pcmcia_socket *s, unsigned int function, conf_reg_t *reg);
 
+
+struct pcmcia_callback{
+       struct module   *owner;
+       int             (*event) (struct pcmcia_socket *s, event_t event, int priority);
+};
+
+int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
+
 #define cs_socket_name(skt)    ((skt)->dev.class_id)
 
 #ifdef DEBUG
index 639c5acf22f1590c8e5874c1fc93b972c66703ed..536dccc5bff1ee929915530905a4a6878a3ba971 100644 (file)
@@ -112,7 +112,7 @@ typedef struct user_info_t {
 /* Socket state information */
 struct pcmcia_bus_socket {
        atomic_t                refcount;
-       client_handle_t         handle;
+       struct pcmcia_callback  callback;
        int                     state;
        user_info_t             *user;
        int                     req_pending, req_result;
@@ -484,14 +484,12 @@ static void handle_removal(void *data)
     
 ======================================================================*/
 
-static int ds_event(event_t event, int priority,
-                   event_callback_args_t *args)
+static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
 {
-    struct pcmcia_bus_socket *s;
+    struct pcmcia_bus_socket *s = skt->pcmcia;
 
     ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
-         event, priority, args->client_handle);
-    s = args->client_data;
+         event, priority, s);
     
     switch (event) {
        
@@ -1082,8 +1080,6 @@ static struct file_operations ds_fops = {
 static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
 {
        struct pcmcia_socket *socket = class_dev->class_data;
-       client_reg_t client_reg;
-       bind_req_t bind;
        struct pcmcia_bus_socket *s;
        int ret;
 
@@ -1107,35 +1103,18 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
        s->parent = socket;
 
        /* Set up hotline to Card Services */
-       client_reg.dev_info = bind.dev_info = &dev_info;
-
-       bind.Socket = socket;
-       bind.Function = BIND_FN_ALL;
-       ret = pcmcia_bind_device(&bind);
-       if (ret != CS_SUCCESS) {
-               cs_error(NULL, BindDevice, ret);
-               kfree(s);
-               return -EINVAL;
-       }
+       s->callback.owner = THIS_MODULE;
+       s->callback.event = &ds_event;
+       socket->pcmcia = s;
 
-       client_reg.Attributes = INFO_MASTER_CLIENT;
-       client_reg.EventMask =
-               CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-               CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-               CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST |
-               CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-       client_reg.event_handler = &ds_event;
-       client_reg.Version = 0x0210;
-       client_reg.event_callback_args.client_data = s;
-       ret = pcmcia_register_client(&s->handle, &client_reg);
-       if (ret != CS_SUCCESS) {
-               cs_error(NULL, RegisterClient, ret);
-               kfree(s);
-               return -EINVAL;
+       ret = pccard_register_pcmcia(socket, &s->callback);
+       if (ret) {
+               printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket);
+               pcmcia_put_bus_socket(s);
+               socket->pcmcia = NULL;
+               return (ret);
        }
 
-       socket->pcmcia = s;
-
        return 0;
 }
 
@@ -1147,9 +1126,9 @@ static void pcmcia_bus_remove_socket(struct class_device *class_dev)
        if (!socket || !socket->pcmcia)
                return;
 
-       flush_scheduled_work();
+       pccard_register_pcmcia(socket, NULL);
 
-       pcmcia_deregister_client(socket->pcmcia->handle);
+       flush_scheduled_work();
 
        socket->pcmcia->state |= DS_SOCKET_DEAD;
        pcmcia_put_bus_socket(socket->pcmcia);
index 1958cda298897844c00d07062b9c83d0b116a8de..c8c53fc0ef072724448054614376ce2838aafc89 100644 (file)
@@ -159,6 +159,7 @@ typedef struct window_t {
 
 struct config_t;
 struct region_t;
+struct pcmcia_callback;
 
 struct pcmcia_socket {
        struct module                   *owner;
@@ -215,6 +216,7 @@ struct pcmcia_socket {
 
        /* pcmcia (16-bit) */
        struct pcmcia_bus_socket        *pcmcia;
+       struct pcmcia_callback          *callback;
 
        /* cardbus (32-bit) */
 #ifdef CONFIG_CARDBUS