Commit f1395ea3 authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Linus Torvalds

[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: default avatarDominik Brodowski <linux@brodo.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 8dce684c
...@@ -349,8 +349,6 @@ static void free_regions(memory_handle_t *list) ...@@ -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) static void shutdown_socket(struct pcmcia_socket *s)
{ {
client_t **c; client_t **c;
...@@ -402,6 +400,26 @@ static void shutdown_socket(struct pcmcia_socket *s) ...@@ -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) static int send_event(struct pcmcia_socket *s, event_t event, int priority)
{ {
client_t *client = s->clients; client_t *client = s->clients;
...@@ -411,6 +429,11 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) ...@@ -411,6 +429,11 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority)
ret = 0; ret = 0;
if (s->state & SOCKET_CARDBUS) if (s->state & SOCKET_CARDBUS)
return 0; return 0;
ret = pcmcia_send_event(s, event, priority);
if (ret)
return (ret);
for (; client; client = client->next) { for (; client; client = client->next) {
if (client->state & (CLIENT_UNBOUND|CLIENT_STALE)) if (client->state & (CLIENT_UNBOUND|CLIENT_STALE))
continue; continue;
...@@ -1363,6 +1386,34 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) ...@@ -1363,6 +1386,34 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
return CS_OUT_OF_RESOURCE; return CS_OUT_OF_RESOURCE;
} /* register_client */ } /* 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) int pcmcia_release_configuration(client_handle_t handle)
......
...@@ -173,6 +173,14 @@ int pccard_reset_card(struct pcmcia_socket *skt); ...@@ -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_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); 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) #define cs_socket_name(skt) ((skt)->dev.class_id)
#ifdef DEBUG #ifdef DEBUG
......
...@@ -112,7 +112,7 @@ typedef struct user_info_t { ...@@ -112,7 +112,7 @@ typedef struct user_info_t {
/* Socket state information */ /* Socket state information */
struct pcmcia_bus_socket { struct pcmcia_bus_socket {
atomic_t refcount; atomic_t refcount;
client_handle_t handle; struct pcmcia_callback callback;
int state; int state;
user_info_t *user; user_info_t *user;
int req_pending, req_result; int req_pending, req_result;
...@@ -484,14 +484,12 @@ static void handle_removal(void *data) ...@@ -484,14 +484,12 @@ static void handle_removal(void *data)
======================================================================*/ ======================================================================*/
static int ds_event(event_t event, int priority, static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
event_callback_args_t *args)
{ {
struct pcmcia_bus_socket *s; struct pcmcia_bus_socket *s = skt->pcmcia;
ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
event, priority, args->client_handle); event, priority, s);
s = args->client_data;
switch (event) { switch (event) {
...@@ -1082,8 +1080,6 @@ static struct file_operations ds_fops = { ...@@ -1082,8 +1080,6 @@ static struct file_operations ds_fops = {
static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
{ {
struct pcmcia_socket *socket = class_dev->class_data; struct pcmcia_socket *socket = class_dev->class_data;
client_reg_t client_reg;
bind_req_t bind;
struct pcmcia_bus_socket *s; struct pcmcia_bus_socket *s;
int ret; int ret;
...@@ -1107,35 +1103,18 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) ...@@ -1107,35 +1103,18 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
s->parent = socket; s->parent = socket;
/* Set up hotline to Card Services */ /* Set up hotline to Card Services */
client_reg.dev_info = bind.dev_info = &dev_info; s->callback.owner = THIS_MODULE;
s->callback.event = &ds_event;
bind.Socket = socket; socket->pcmcia = s;
bind.Function = BIND_FN_ALL;
ret = pcmcia_bind_device(&bind);
if (ret != CS_SUCCESS) {
cs_error(NULL, BindDevice, ret);
kfree(s);
return -EINVAL;
}
client_reg.Attributes = INFO_MASTER_CLIENT; ret = pccard_register_pcmcia(socket, &s->callback);
client_reg.EventMask = if (ret) {
CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket);
CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | pcmcia_put_bus_socket(s);
CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST | socket->pcmcia = NULL;
CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; return (ret);
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;
} }
socket->pcmcia = s;
return 0; return 0;
} }
...@@ -1147,9 +1126,9 @@ static void pcmcia_bus_remove_socket(struct class_device *class_dev) ...@@ -1147,9 +1126,9 @@ static void pcmcia_bus_remove_socket(struct class_device *class_dev)
if (!socket || !socket->pcmcia) if (!socket || !socket->pcmcia)
return; return;
flush_scheduled_work(); pccard_register_pcmcia(socket, NULL);
pcmcia_deregister_client(socket->pcmcia->handle); flush_scheduled_work();
socket->pcmcia->state |= DS_SOCKET_DEAD; socket->pcmcia->state |= DS_SOCKET_DEAD;
pcmcia_put_bus_socket(socket->pcmcia); pcmcia_put_bus_socket(socket->pcmcia);
......
...@@ -159,6 +159,7 @@ typedef struct window_t { ...@@ -159,6 +159,7 @@ typedef struct window_t {
struct config_t; struct config_t;
struct region_t; struct region_t;
struct pcmcia_callback;
struct pcmcia_socket { struct pcmcia_socket {
struct module *owner; struct module *owner;
...@@ -215,6 +216,7 @@ struct pcmcia_socket { ...@@ -215,6 +216,7 @@ struct pcmcia_socket {
/* pcmcia (16-bit) */ /* pcmcia (16-bit) */
struct pcmcia_bus_socket *pcmcia; struct pcmcia_bus_socket *pcmcia;
struct pcmcia_callback *callback;
/* cardbus (32-bit) */ /* cardbus (32-bit) */
#ifdef CONFIG_CARDBUS #ifdef CONFIG_CARDBUS
......
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