aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDominik Brodowski <linux@dominikbrodowski.de>2005-01-11 03:19:00 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-01-11 03:19:00 -0800
commitf1395ea3c1fbf67824ff83e5d4fd7aefb5346e90 (patch)
tree575e189ee0e9b5b43a87ce1851a025f32962d04f /drivers
parent8dce684cff3c14dd87ea3fce604152a7468751e8 (diff)
downloadhistory-f1395ea3c1fbf67824ff83e5d4fd7aefb5346e90.tar.gz
[PATCH] pcmcia: new ds - cs interface
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pcmcia/cs.c55
-rw-r--r--drivers/pcmcia/cs_internal.h8
-rw-r--r--drivers/pcmcia/ds.c51
3 files changed, 76 insertions, 38 deletions
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 4e4c964f7e01bf..7a522f0eed8853 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -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)
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index fbce6b67988b22..dcb1c651724f59 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -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
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 639c5acf22f159..536dccc5bff1ee 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -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);