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)
}
}
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)
......
......@@ -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
......
......@@ -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);
......
......@@ -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
......
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