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

[PATCH] pcmcia: add pcmcia_device(s)

Add pcmcia_device(s).
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 632a82e0
...@@ -101,7 +101,15 @@ struct pcmcia_bus_socket { ...@@ -101,7 +101,15 @@ struct pcmcia_bus_socket {
wait_queue_head_t queue, request; wait_queue_head_t queue, request;
socket_bind_t *bind; socket_bind_t *bind;
struct pcmcia_socket *parent; struct pcmcia_socket *parent;
/* the PCMCIA devices connected to this socket (normally one, more
* for multifunction devices: */
struct list_head devices_list;
u8 device_count; /* the number of devices, used
* only internally and subject
* to incorrectness and change */
}; };
static spinlock_t pcmcia_dev_list_lock;
#define DS_SOCKET_PRESENT 0x01 #define DS_SOCKET_PRESENT 0x01
#define DS_SOCKET_BUSY 0x02 #define DS_SOCKET_BUSY 0x02
...@@ -328,6 +336,16 @@ static int proc_read_drivers(char *buf, char **start, off_t pos, ...@@ -328,6 +336,16 @@ static int proc_read_drivers(char *buf, char **start, off_t pos,
} }
#endif #endif
/* pcmcia_device handling */
static void pcmcia_release_dev(struct device *dev)
{
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
p_dev->socket->pcmcia->device_count = 0;
kfree(p_dev);
}
/*====================================================================== /*======================================================================
These manage a ring buffer of events pending for one user process These manage a ring buffer of events pending for one user process
...@@ -491,8 +509,10 @@ static int bind_mtd(struct pcmcia_bus_socket *bus_sock, mtd_info_t *mtd_info) ...@@ -491,8 +509,10 @@ static int bind_mtd(struct pcmcia_bus_socket *bus_sock, mtd_info_t *mtd_info)
static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
{ {
struct pcmcia_driver *driver; struct pcmcia_driver *driver;
struct pcmcia_device *p_dev;
socket_bind_t *b; socket_bind_t *b;
client_t *client; client_t *client;
unsigned long flags;
if (!s) if (!s)
return -EINVAL; return -EINVAL;
...@@ -543,6 +563,38 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) ...@@ -543,6 +563,38 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
b->next = s->bind; b->next = s->bind;
s->bind = b; s->bind = b;
/* 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) {
/* FIXME: client isn't freed here */
goto no_p_dev;
}
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, "pcmcia%d.%d", p_dev->socket->sock, p_dev->device_no);
p_dev->dev.driver = &driver->drv;
if (device_register(&p_dev->dev)) {
/* FIXME: client isn't freed here */
kfree(p_dev);
goto no_p_dev;
}
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
list_add_tail(&p_dev->socket_device_list, &s->devices_list);
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
no_p_dev:
driver->use_count++; driver->use_count++;
if (driver->attach) { if (driver->attach) {
b->instance = driver->attach(); b->instance = driver->attach();
...@@ -632,6 +684,8 @@ static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, ...@@ -632,6 +684,8 @@ static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info,
static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
{ {
socket_bind_t **b, *c; socket_bind_t **b, *c;
struct pcmcia_device *p_dev;
unsigned long flags;
ds_dbg(2, "unbind_request(%d, '%s')\n", s->parent->sock, ds_dbg(2, "unbind_request(%d, '%s')\n", s->parent->sock,
(char *)bind_info->dev_info); (char *)bind_info->dev_info);
...@@ -652,6 +706,22 @@ static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) ...@@ -652,6 +706,22 @@ static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
module_put(c->driver->owner); module_put(c->driver->owner);
*b = c->next; *b = c->next;
kfree(c); kfree(c);
restart:
/* unregister the pcmcia_device */
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
if (p_dev->func == bind_info->function) {
list_del(&p_dev->socket_device_list);
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
device_unregister(&p_dev->dev);
/* multiple devices may be registered to this "function" */
goto restart;
}
}
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
return 0; return 0;
} /* unbind_request */ } /* unbind_request */
...@@ -1034,6 +1104,7 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) ...@@ -1034,6 +1104,7 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
init_waitqueue_head(&s->queue); init_waitqueue_head(&s->queue);
init_waitqueue_head(&s->request); init_waitqueue_head(&s->request);
INIT_LIST_HEAD(&s->devices_list);
/* initialize data */ /* initialize data */
s->parent = socket; s->parent = socket;
...@@ -1090,6 +1161,8 @@ static int __init init_pcmcia_bus(void) ...@@ -1090,6 +1161,8 @@ static int __init init_pcmcia_bus(void)
{ {
int i; int i;
spin_lock_init(&pcmcia_dev_list_lock);
bus_register(&pcmcia_bus_type); bus_register(&pcmcia_bus_type);
class_interface_register(&pcmcia_bus_interface); class_interface_register(&pcmcia_bus_interface);
......
...@@ -127,6 +127,8 @@ typedef struct dev_link_t { ...@@ -127,6 +127,8 @@ typedef struct dev_link_t {
((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT))) ((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT)))
struct pcmcia_socket;
extern struct bus_type pcmcia_bus_type; extern struct bus_type pcmcia_bus_type;
struct pcmcia_driver { struct pcmcia_driver {
...@@ -141,6 +143,26 @@ struct pcmcia_driver { ...@@ -141,6 +143,26 @@ struct pcmcia_driver {
int pcmcia_register_driver(struct pcmcia_driver *driver); int pcmcia_register_driver(struct pcmcia_driver *driver);
void pcmcia_unregister_driver(struct pcmcia_driver *driver); void pcmcia_unregister_driver(struct pcmcia_driver *driver);
struct pcmcia_device {
/* the socket and the device_no [for multifunction devices]
uniquely define a pcmcia_device */
struct pcmcia_socket *socket;
u8 device_no;
/* the hardware "function" device; certain subdevices can
* share one hardware "function" device. */
u8 func;
struct list_head socket_device_list;
struct device dev;
};
#define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
#define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv)
/* error reporting */ /* error reporting */
void cs_error(client_handle_t handle, int func, int ret); void cs_error(client_handle_t handle, int func, int ret);
......
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