Commit 01a99f33 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk/linux-2.5-pcmcia

into home.transmeta.com:/home/torvalds/v2.5/linux
parents fff263fe 0f5c57f5
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/list.h>
#include <pcmcia/version.h> #include <pcmcia/version.h>
#include <pcmcia/cs_types.h> #include <pcmcia/cs_types.h>
...@@ -55,6 +56,7 @@ ...@@ -55,6 +56,7 @@
#include <pcmcia/bulkmem.h> #include <pcmcia/bulkmem.h>
#include <pcmcia/cistpl.h> #include <pcmcia/cistpl.h>
#include <pcmcia/ds.h> #include <pcmcia/ds.h>
#include <pcmcia/ss.h>
/*====================================================================*/ /*====================================================================*/
...@@ -97,15 +99,18 @@ typedef struct user_info_t { ...@@ -97,15 +99,18 @@ typedef struct user_info_t {
} user_info_t; } user_info_t;
/* Socket state information */ /* Socket state information */
typedef struct socket_info_t { struct pcmcia_bus_socket {
client_handle_t handle; client_handle_t handle;
int state; int state;
user_info_t *user; user_info_t *user;
int req_pending, req_result; int req_pending, req_result;
wait_queue_head_t queue, request; wait_queue_head_t queue, request;
struct timer_list removal; struct timer_list removal;
socket_bind_t *bind; socket_bind_t *bind;
} socket_info_t; struct device *socket_dev;
struct list_head socket_list;
unsigned int socket_no; /* deprecated */
};
#define SOCKET_PRESENT 0x01 #define SOCKET_PRESENT 0x01
#define SOCKET_BUSY 0x02 #define SOCKET_BUSY 0x02
...@@ -116,13 +121,13 @@ typedef struct socket_info_t { ...@@ -116,13 +121,13 @@ typedef struct socket_info_t {
/* Device driver ID passed to Card Services */ /* Device driver ID passed to Card Services */
static dev_info_t dev_info = "Driver Services"; static dev_info_t dev_info = "Driver Services";
static int sockets = 0, major_dev = -1; static int major_dev = -1;
static socket_info_t *socket_table = NULL;
extern struct proc_dir_entry *proc_pccard; /* list of all sockets registered with the pcmcia bus driver */
static DECLARE_RWSEM(bus_socket_list_rwsem);
static LIST_HEAD(bus_socket_list);
/* We use this to distinguish in-kernel from modular drivers */ extern struct proc_dir_entry *proc_pccard;
static int init_status = 1;
/*====================================================================*/ /*====================================================================*/
...@@ -135,6 +140,7 @@ static void cs_error(client_handle_t handle, int func, int ret) ...@@ -135,6 +140,7 @@ static void cs_error(client_handle_t handle, int func, int ret)
/*======================================================================*/ /*======================================================================*/
static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info); static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info);
static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr);
/** /**
* pcmcia_register_driver - register a PCMCIA driver with the bus core * pcmcia_register_driver - register a PCMCIA driver with the bus core
...@@ -147,7 +153,6 @@ int pcmcia_register_driver(struct pcmcia_driver *driver) ...@@ -147,7 +153,6 @@ int pcmcia_register_driver(struct pcmcia_driver *driver)
return -EINVAL; return -EINVAL;
driver->use_count = 0; driver->use_count = 0;
driver->status = init_status;
driver->drv.bus = &pcmcia_bus_type; driver->drv.bus = &pcmcia_bus_type;
return driver_register(&driver->drv); return driver_register(&driver->drv);
...@@ -160,17 +165,19 @@ EXPORT_SYMBOL(pcmcia_register_driver); ...@@ -160,17 +165,19 @@ EXPORT_SYMBOL(pcmcia_register_driver);
void pcmcia_unregister_driver(struct pcmcia_driver *driver) void pcmcia_unregister_driver(struct pcmcia_driver *driver)
{ {
socket_bind_t *b; socket_bind_t *b;
int i; struct pcmcia_bus_socket *bus_sock;
if (driver->use_count > 0) { if (driver->use_count > 0) {
/* Blank out any left-over device instances */ /* Blank out any left-over device instances */
driver->attach = NULL; driver->detach = NULL; driver->attach = NULL; driver->detach = NULL;
for (i = 0; i < sockets; i++) down_read(&bus_socket_list_rwsem);
for (b = socket_table[i].bind; b; b = b->next) list_for_each_entry(bus_sock, &bus_socket_list, socket_list) {
for (b = bus_sock->bind; b; b = b->next)
if (b->driver == driver) if (b->driver == driver)
b->instance = NULL; b->instance = NULL;
} }
up_read(&bus_socket_list_rwsem);
}
driver_unregister(&driver->drv); driver_unregister(&driver->drv);
} }
EXPORT_SYMBOL(pcmcia_unregister_driver); EXPORT_SYMBOL(pcmcia_unregister_driver);
...@@ -182,7 +189,7 @@ int register_pccard_driver(dev_info_t *dev_info, ...@@ -182,7 +189,7 @@ int register_pccard_driver(dev_info_t *dev_info,
{ {
struct pcmcia_driver *driver; struct pcmcia_driver *driver;
socket_bind_t *b; socket_bind_t *b;
int i; struct pcmcia_bus_socket *bus_sock;
DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info); DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info);
driver = get_pcmcia_driver(dev_info); driver = get_pcmcia_driver(dev_info);
...@@ -199,15 +206,17 @@ int register_pccard_driver(dev_info_t *dev_info, ...@@ -199,15 +206,17 @@ int register_pccard_driver(dev_info_t *dev_info,
if (driver->use_count == 0) return 0; if (driver->use_count == 0) return 0;
/* Instantiate any already-bound devices */ /* Instantiate any already-bound devices */
for (i = 0; i < sockets; i++) down_read(&bus_socket_list_rwsem);
for (b = socket_table[i].bind; b; b = b->next) { list_for_each_entry(bus_sock, &bus_socket_list, socket_list) {
for (b = bus_sock->bind; b; b = b->next) {
if (b->driver != driver) continue; if (b->driver != driver) continue;
b->instance = driver->attach(); b->instance = driver->attach();
if (b->instance == NULL) if (b->instance == NULL)
printk(KERN_NOTICE "ds: unable to create instance " printk(KERN_NOTICE "ds: unable to create instance "
"of '%s'!\n", driver->drv.name); "of '%s'!\n", driver->drv.name);
} }
}
up_read(&bus_socket_list_rwsem);
return 0; return 0;
} /* register_pccard_driver */ } /* register_pccard_driver */
...@@ -238,8 +247,7 @@ static int proc_read_drivers_callback(struct device_driver *driver, void *d) ...@@ -238,8 +247,7 @@ static int proc_read_drivers_callback(struct device_driver *driver, void *d)
struct pcmcia_driver *p_dev = container_of(driver, struct pcmcia_driver *p_dev = container_of(driver,
struct pcmcia_driver, drv); struct pcmcia_driver, drv);
*p += sprintf(*p, "%-24.24s %d %d\n", driver->name, p_dev->status, *p += sprintf(*p, "%-24.24s 1 %d\n", driver->name, p_dev->use_count);
p_dev->use_count);
d = (void *) p; d = (void *) p;
return 0; return 0;
...@@ -282,7 +290,7 @@ static void queue_event(user_info_t *user, event_t event) ...@@ -282,7 +290,7 @@ static void queue_event(user_info_t *user, event_t event)
user->event[user->event_head] = event; user->event[user->event_head] = event;
} }
static void handle_event(socket_info_t *s, event_t event) static void handle_event(struct pcmcia_bus_socket *s, event_t event)
{ {
user_info_t *user; user_info_t *user;
for (user = s->user; user; user = user->next) for (user = s->user; user; user = user->next)
...@@ -290,7 +298,7 @@ static void handle_event(socket_info_t *s, event_t event) ...@@ -290,7 +298,7 @@ static void handle_event(socket_info_t *s, event_t event)
wake_up_interruptible(&s->queue); wake_up_interruptible(&s->queue);
} }
static int handle_request(socket_info_t *s, event_t event) static int handle_request(struct pcmcia_bus_socket *s, event_t event)
{ {
if (s->req_pending != 0) if (s->req_pending != 0)
return CS_IN_USE; return CS_IN_USE;
...@@ -309,7 +317,7 @@ static int handle_request(socket_info_t *s, event_t event) ...@@ -309,7 +317,7 @@ static int handle_request(socket_info_t *s, event_t event)
static void handle_removal(u_long sn) static void handle_removal(u_long sn)
{ {
socket_info_t *s = &socket_table[sn]; struct pcmcia_bus_socket *s = get_socket_info_by_nr(sn);
handle_event(s, CS_EVENT_CARD_REMOVAL); handle_event(s, CS_EVENT_CARD_REMOVAL);
s->state &= ~SOCKET_REMOVAL_PENDING; s->state &= ~SOCKET_REMOVAL_PENDING;
} }
...@@ -323,13 +331,11 @@ static void handle_removal(u_long sn) ...@@ -323,13 +331,11 @@ static void handle_removal(u_long sn)
static int ds_event(event_t event, int priority, static int ds_event(event_t event, int priority,
event_callback_args_t *args) event_callback_args_t *args)
{ {
socket_info_t *s; struct pcmcia_bus_socket *s;
int i;
DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n", DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n",
event, priority, args->client_handle); event, priority, args->client_handle);
s = args->client_data; s = args->client_data;
i = s - socket_table;
switch (event) { switch (event) {
...@@ -366,21 +372,21 @@ static int ds_event(event_t event, int priority, ...@@ -366,21 +372,21 @@ static int ds_event(event_t event, int priority,
======================================================================*/ ======================================================================*/
static int bind_mtd(int i, mtd_info_t *mtd_info) static int bind_mtd(struct pcmcia_bus_socket *bus_sock, mtd_info_t *mtd_info)
{ {
mtd_bind_t bind_req; mtd_bind_t bind_req;
int ret; int ret;
bind_req.dev_info = &mtd_info->dev_info; bind_req.dev_info = &mtd_info->dev_info;
bind_req.Attributes = mtd_info->Attributes; bind_req.Attributes = mtd_info->Attributes;
bind_req.Socket = i; bind_req.Socket = bus_sock->socket_no;
bind_req.CardOffset = mtd_info->CardOffset; bind_req.CardOffset = mtd_info->CardOffset;
ret = pcmcia_bind_mtd(&bind_req); ret = pcmcia_bind_mtd(&bind_req);
if (ret != CS_SUCCESS) { if (ret != CS_SUCCESS) {
cs_error(NULL, BindMTD, ret); cs_error(NULL, BindMTD, ret);
printk(KERN_NOTICE "ds: unable to bind MTD '%s' to socket %d" printk(KERN_NOTICE "ds: unable to bind MTD '%s' to socket %d"
" offset 0x%x\n", " offset 0x%x\n",
(char *)bind_req.dev_info, i, bind_req.CardOffset); (char *)bind_req.dev_info, bus_sock->socket_no, bind_req.CardOffset);
return -ENODEV; return -ENODEV;
} }
return 0; return 0;
...@@ -395,14 +401,16 @@ static int bind_mtd(int i, mtd_info_t *mtd_info) ...@@ -395,14 +401,16 @@ static int bind_mtd(int i, mtd_info_t *mtd_info)
======================================================================*/ ======================================================================*/
static int bind_request(int i, 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;
socket_bind_t *b; socket_bind_t *b;
bind_req_t bind_req; bind_req_t bind_req;
socket_info_t *s = &socket_table[i];
int ret; int ret;
if (!s)
return -EINVAL;
DEBUG(2, "bind_request(%d, '%s')\n", i, DEBUG(2, "bind_request(%d, '%s')\n", i,
(char *)bind_info->dev_info); (char *)bind_info->dev_info);
driver = get_pcmcia_driver(&bind_info->dev_info); driver = get_pcmcia_driver(&bind_info->dev_info);
...@@ -423,14 +431,14 @@ static int bind_request(int i, bind_info_t *bind_info) ...@@ -423,14 +431,14 @@ static int bind_request(int i, bind_info_t *bind_info)
return -EBUSY; return -EBUSY;
} }
bind_req.Socket = i; bind_req.Socket = s->socket_no;
bind_req.Function = bind_info->function; bind_req.Function = bind_info->function;
bind_req.dev_info = (dev_info_t *) driver->drv.name; bind_req.dev_info = (dev_info_t *) driver->drv.name;
ret = pcmcia_bind_device(&bind_req); ret = pcmcia_bind_device(&bind_req);
if (ret != CS_SUCCESS) { if (ret != CS_SUCCESS) {
cs_error(NULL, BindDevice, ret); cs_error(NULL, BindDevice, ret);
printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n", printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n",
(char *)dev_info, i); (char *)dev_info, s->socket_no);
return -ENODEV; return -ENODEV;
} }
...@@ -462,9 +470,8 @@ static int bind_request(int i, bind_info_t *bind_info) ...@@ -462,9 +470,8 @@ static int bind_request(int i, bind_info_t *bind_info)
/*====================================================================*/ /*====================================================================*/
static int get_device_info(int i, bind_info_t *bind_info, int first) static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, int first)
{ {
socket_info_t *s = &socket_table[i];
socket_bind_t *b; socket_bind_t *b;
dev_node_t *node; dev_node_t *node;
...@@ -532,9 +539,8 @@ static int get_device_info(int i, bind_info_t *bind_info, int first) ...@@ -532,9 +539,8 @@ static int get_device_info(int i, bind_info_t *bind_info, int first)
/*====================================================================*/ /*====================================================================*/
static int unbind_request(int i, bind_info_t *bind_info) static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
{ {
socket_info_t *s = &socket_table[i];
socket_bind_t **b, *c; socket_bind_t **b, *c;
DEBUG(2, "unbind_request(%d, '%s')\n", i, DEBUG(2, "unbind_request(%d, '%s')\n", i,
...@@ -568,13 +574,15 @@ static int unbind_request(int i, bind_info_t *bind_info) ...@@ -568,13 +574,15 @@ static int unbind_request(int i, bind_info_t *bind_info)
static int ds_open(struct inode *inode, struct file *file) static int ds_open(struct inode *inode, struct file *file)
{ {
socket_t i = minor(inode->i_rdev); socket_t i = minor(inode->i_rdev);
socket_info_t *s; struct pcmcia_bus_socket *s;
user_info_t *user; user_info_t *user;
DEBUG(0, "ds_open(socket %d)\n", i); DEBUG(0, "ds_open(socket %d)\n", i);
if ((i >= sockets) || (sockets == 0))
return -ENODEV; s = get_socket_info_by_nr(i);
s = &socket_table[i]; if (!s)
return -ENODEV;
if ((file->f_flags & O_ACCMODE) != O_RDONLY) { if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
if (s->state & SOCKET_BUSY) if (s->state & SOCKET_BUSY)
return -EBUSY; return -EBUSY;
...@@ -600,13 +608,15 @@ static int ds_open(struct inode *inode, struct file *file) ...@@ -600,13 +608,15 @@ static int ds_open(struct inode *inode, struct file *file)
static int ds_release(struct inode *inode, struct file *file) static int ds_release(struct inode *inode, struct file *file)
{ {
socket_t i = minor(inode->i_rdev); socket_t i = minor(inode->i_rdev);
socket_info_t *s; struct pcmcia_bus_socket *s;
user_info_t *user, **link; user_info_t *user, **link;
DEBUG(0, "ds_release(socket %d)\n", i); DEBUG(0, "ds_release(socket %d)\n", i);
if ((i >= sockets) || (sockets == 0))
return 0; s = get_socket_info_by_nr(i);
s = &socket_table[i]; if (!s)
return 0;
user = file->private_data; user = file->private_data;
if (CHECK_USER(user)) if (CHECK_USER(user))
goto out; goto out;
...@@ -632,16 +642,18 @@ static ssize_t ds_read(struct file *file, char *buf, ...@@ -632,16 +642,18 @@ static ssize_t ds_read(struct file *file, char *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
socket_t i = minor(file->f_dentry->d_inode->i_rdev); socket_t i = minor(file->f_dentry->d_inode->i_rdev);
socket_info_t *s; struct pcmcia_bus_socket *s;
user_info_t *user; user_info_t *user;
DEBUG(2, "ds_read(socket %d)\n", i); DEBUG(2, "ds_read(socket %d)\n", i);
if ((i >= sockets) || (sockets == 0))
return -ENODEV;
if (count < 4) if (count < 4)
return -EINVAL; return -EINVAL;
s = &socket_table[i];
s = get_socket_info_by_nr(i);
if (!s)
return -ENODEV;
user = file->private_data; user = file->private_data;
if (CHECK_USER(user)) if (CHECK_USER(user))
return -EIO; return -EIO;
...@@ -661,18 +673,20 @@ static ssize_t ds_write(struct file *file, const char *buf, ...@@ -661,18 +673,20 @@ static ssize_t ds_write(struct file *file, const char *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
socket_t i = minor(file->f_dentry->d_inode->i_rdev); socket_t i = minor(file->f_dentry->d_inode->i_rdev);
socket_info_t *s; struct pcmcia_bus_socket *s;
user_info_t *user; user_info_t *user;
DEBUG(2, "ds_write(socket %d)\n", i); DEBUG(2, "ds_write(socket %d)\n", i);
if ((i >= sockets) || (sockets == 0))
return -ENODEV;
if (count != 4) if (count != 4)
return -EINVAL; return -EINVAL;
if ((file->f_flags & O_ACCMODE) == O_RDONLY) if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return -EBADF; return -EBADF;
s = &socket_table[i];
s = get_socket_info_by_nr(i);
if (!s)
return -ENODEV;
user = file->private_data; user = file->private_data;
if (CHECK_USER(user)) if (CHECK_USER(user))
return -EIO; return -EIO;
...@@ -694,14 +708,15 @@ static ssize_t ds_write(struct file *file, const char *buf, ...@@ -694,14 +708,15 @@ static ssize_t ds_write(struct file *file, const char *buf,
static u_int ds_poll(struct file *file, poll_table *wait) static u_int ds_poll(struct file *file, poll_table *wait)
{ {
socket_t i = minor(file->f_dentry->d_inode->i_rdev); socket_t i = minor(file->f_dentry->d_inode->i_rdev);
socket_info_t *s; struct pcmcia_bus_socket *s;
user_info_t *user; user_info_t *user;
DEBUG(2, "ds_poll(socket %d)\n", i); DEBUG(2, "ds_poll(socket %d)\n", i);
if ((i >= sockets) || (sockets == 0)) s = get_socket_info_by_nr(i);
return POLLERR; if (!s)
s = &socket_table[i]; return POLLERR;
user = file->private_data; user = file->private_data;
if (CHECK_USER(user)) if (CHECK_USER(user))
return POLLERR; return POLLERR;
...@@ -717,16 +732,16 @@ static int ds_ioctl(struct inode * inode, struct file * file, ...@@ -717,16 +732,16 @@ static int ds_ioctl(struct inode * inode, struct file * file,
u_int cmd, u_long arg) u_int cmd, u_long arg)
{ {
socket_t i = minor(inode->i_rdev); socket_t i = minor(inode->i_rdev);
socket_info_t *s; struct pcmcia_bus_socket *s;
u_int size; u_int size;
int ret, err; int ret, err;
ds_ioctl_arg_t buf; ds_ioctl_arg_t buf;
DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", i, cmd, arg); DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", i, cmd, arg);
if ((i >= sockets) || (sockets == 0)) s = get_socket_info_by_nr(i);
return -ENODEV; if (!s)
s = &socket_table[i]; return -ENODEV;
size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL; if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
...@@ -827,20 +842,20 @@ static int ds_ioctl(struct inode * inode, struct file * file, ...@@ -827,20 +842,20 @@ static int ds_ioctl(struct inode * inode, struct file * file,
break; break;
case DS_BIND_REQUEST: case DS_BIND_REQUEST:
if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!capable(CAP_SYS_ADMIN)) return -EPERM;
err = bind_request(i, &buf.bind_info); err = bind_request(s, &buf.bind_info);
break; break;
case DS_GET_DEVICE_INFO: case DS_GET_DEVICE_INFO:
err = get_device_info(i, &buf.bind_info, 1); err = get_device_info(s, &buf.bind_info, 1);
break; break;
case DS_GET_NEXT_DEVICE: case DS_GET_NEXT_DEVICE:
err = get_device_info(i, &buf.bind_info, 0); err = get_device_info(s, &buf.bind_info, 0);
break; break;
case DS_UNBIND_REQUEST: case DS_UNBIND_REQUEST:
err = unbind_request(i, &buf.bind_info); err = unbind_request(s, &buf.bind_info);
break; break;
case DS_BIND_MTD: case DS_BIND_MTD:
if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!capable(CAP_SYS_ADMIN)) return -EPERM;
err = bind_mtd(i, &buf.mtd_info); err = bind_mtd(s, &buf.mtd_info);
break; break;
default: default:
err = -EINVAL; err = -EINVAL;
...@@ -889,141 +904,199 @@ EXPORT_SYMBOL(unregister_pccard_driver); ...@@ -889,141 +904,199 @@ EXPORT_SYMBOL(unregister_pccard_driver);
/*====================================================================*/ /*====================================================================*/
struct bus_type pcmcia_bus_type = { static int __devinit pcmcia_bus_add_socket(struct device *dev, unsigned int socket_nr)
.name = "pcmcia",
};
EXPORT_SYMBOL(pcmcia_bus_type);
static int __init init_pcmcia_bus(void)
{ {
bus_register(&pcmcia_bus_type); client_reg_t client_reg;
return 0; bind_req_t bind;
} struct pcmcia_bus_socket *s, *tmp_s;
int ret;
int i;
static int __init init_pcmcia_ds(void) s = kmalloc(sizeof(struct pcmcia_bus_socket), GFP_KERNEL);
{ if(!s)
client_reg_t client_reg; return -ENOMEM;
servinfo_t serv; memset(s, 0, sizeof(struct pcmcia_bus_socket));
bind_req_t bind;
socket_info_t *s;
int i, ret;
DEBUG(0, "%s\n", version); /*
* Ugly. But we want to wait for the socket threads to have started up.
/* * We really should let the drivers themselves drive some of this..
* Ugly. But we want to wait for the socket threads to have started up. */
* We really should let the drivers themselves drive some of this.. current->state = TASK_INTERRUPTIBLE;
*/ schedule_timeout(HZ/4);
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ/4);
pcmcia_get_card_services_info(&serv);
if (serv.Revision != CS_RELEASE_CODE) {
printk(KERN_NOTICE "ds: Card Services release does not match!\n");
return -1;
}
if (serv.Count == 0) {
printk(KERN_NOTICE "ds: no socket drivers loaded!\n");
return -1;
}
sockets = serv.Count;
socket_table = kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL);
if (!socket_table) return -1;
for (i = 0, s = socket_table; i < sockets; i++, s++) {
s->state = 0;
s->user = NULL;
s->req_pending = 0;
init_waitqueue_head(&s->queue); init_waitqueue_head(&s->queue);
init_waitqueue_head(&s->request); init_waitqueue_head(&s->request);
s->handle = NULL;
init_timer(&s->removal); /* find the lowest, unused socket no. Please note that this is a
s->removal.data = i; * temporary workaround until "struct pcmcia_socket" is introduced
* into cs.c which will include this number, and which will be
* accessible to ds.c directly */
i = 0;
next_try:
list_for_each_entry(tmp_s, &bus_socket_list, socket_list) {
if (tmp_s->socket_no == i) {
i++;
goto next_try;
}
}
s->socket_no = i;
/* initialize data */
s->socket_dev = dev;
s->removal.data = s->socket_no;
s->removal.function = &handle_removal; s->removal.function = &handle_removal;
s->bind = NULL; init_timer(&s->removal);
}
/* Set up hotline to Card Services */ /* Set up hotline to Card Services */
client_reg.dev_info = bind.dev_info = &dev_info; client_reg.dev_info = bind.dev_info = &dev_info;
client_reg.Attributes = INFO_MASTER_CLIENT;
client_reg.EventMask = bind.Socket = s->socket_no;
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;
for (i = 0; i < sockets; i++) {
bind.Socket = i;
bind.Function = BIND_FN_ALL; bind.Function = BIND_FN_ALL;
ret = pcmcia_bind_device(&bind); ret = pcmcia_bind_device(&bind);
if (ret != CS_SUCCESS) { if (ret != CS_SUCCESS) {
cs_error(NULL, BindDevice, ret); cs_error(NULL, BindDevice, ret);
break; kfree(s);
return -EINVAL;
} }
client_reg.event_callback_args.client_data = &socket_table[i];
ret = pcmcia_register_client(&socket_table[i].handle, client_reg.Attributes = INFO_MASTER_CLIENT;
&client_reg); 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) { if (ret != CS_SUCCESS) {
cs_error(NULL, RegisterClient, ret); cs_error(NULL, RegisterClient, ret);
break; kfree(s);
return -EINVAL;
} }
}
/* Set up character device for user mode clients */
i = register_chrdev(0, "pcmcia", &ds_fops);
if (i == -EBUSY)
printk(KERN_NOTICE "unable to find a free device # for "
"Driver Services\n");
else
major_dev = i;
#ifdef CONFIG_PROC_FS list_add(&s->socket_list, &bus_socket_list);
if (proc_pccard)
create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL); return 0;
init_status = 0;
#endif
return 0;
} }
static void __exit exit_pcmcia_ds(void) static int __devinit pcmcia_bus_add_socket_dev(struct device *dev)
{
struct pcmcia_socket_class_data *cls_d = dev->class_data;
unsigned int i;
unsigned int ret = 0;
if (!cls_d)
return -ENODEV;
down_write(&bus_socket_list_rwsem);
for (i = 0; i < cls_d->nsock; i++)
ret += pcmcia_bus_add_socket(dev, i);
up_write(&bus_socket_list_rwsem);
return ret;
}
static int __devexit pcmcia_bus_remove_socket_dev(struct device *dev)
{ {
int i; struct pcmcia_socket_class_data *cls_d = dev->class_data;
struct list_head *list_loop;
struct list_head *tmp_storage;
if (!cls_d)
return -ENODEV;
down_write(&bus_socket_list_rwsem);
list_for_each_safe(list_loop, tmp_storage, &bus_socket_list) {
struct pcmcia_bus_socket *bus_sock = container_of(list_loop, struct pcmcia_bus_socket, socket_list);
if (bus_sock->socket_dev == dev) {
pcmcia_deregister_client(bus_sock->handle);
list_del(&bus_sock->socket_list);
kfree(bus_sock);
}
}
up_write(&bus_socket_list_rwsem);
return 0;
}
/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
static struct device_interface pcmcia_bus_interface = {
.name = "pcmcia-bus",
.devclass = &pcmcia_socket_class,
.add_device = &pcmcia_bus_add_socket_dev,
.remove_device = __devexit_p(&pcmcia_bus_remove_socket_dev),
.kset = { .subsys = &pcmcia_socket_class.subsys, },
.devnum = 0,
};
struct bus_type pcmcia_bus_type = {
.name = "pcmcia",
};
EXPORT_SYMBOL(pcmcia_bus_type);
static int __init init_pcmcia_bus(void)
{
int i;
bus_register(&pcmcia_bus_type);
interface_register(&pcmcia_bus_interface);
/* Set up character device for user mode clients */
i = register_chrdev(0, "pcmcia", &ds_fops);
if (i == -EBUSY)
printk(KERN_NOTICE "unable to find a free device # for "
"Driver Services\n");
else
major_dev = i;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
if (proc_pccard) if (proc_pccard)
remove_proc_entry("drivers", proc_pccard); create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
#endif #endif
if (major_dev != -1)
unregister_chrdev(major_dev, "pcmcia"); return 0;
for (i = 0; i < sockets; i++)
pcmcia_deregister_client(socket_table[i].handle);
sockets = 0;
kfree(socket_table);
bus_unregister(&pcmcia_bus_type);
} }
fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
* pcmcia_socket_class is already registered */
#ifdef MODULE
/* init_pcmcia_bus must be done early, init_pcmcia_ds late. If we load this static void __exit exit_pcmcia_bus(void)
* as a module, we can only specify one initcall, though... {
*/ interface_unregister(&pcmcia_bus_interface);
static int __init init_pcmcia_module(void) {
init_pcmcia_bus();
return init_pcmcia_ds();
}
module_init(init_pcmcia_module);
#else /* !MODULE */ #ifdef CONFIG_PROC_FS
subsys_initcall(init_pcmcia_bus); if (proc_pccard)
late_initcall(init_pcmcia_ds); remove_proc_entry("drivers", proc_pccard);
#endif #endif
if (major_dev != -1)
unregister_chrdev(major_dev, "pcmcia");
bus_unregister(&pcmcia_bus_type);
}
module_exit(exit_pcmcia_bus);
module_exit(exit_pcmcia_ds);
/* helpers for backwards-compatible functions */ /* helpers for backwards-compatible functions */
static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr)
{
struct pcmcia_bus_socket * s;
down_read(&bus_socket_list_rwsem);
list_for_each_entry(s, &bus_socket_list, socket_list)
if (s->socket_no == nr) {
up_read(&bus_socket_list_rwsem);
return s;
}
up_read(&bus_socket_list_rwsem);
return NULL;
}
/* backwards-compatible accessing of driver --- by name! */ /* backwards-compatible accessing of driver --- by name! */
struct cmp_data { struct cmp_data {
......
/* /* now empty */
* driver_ops.h 1.15 2000/06/12 21:55:40 #warning please remove the reference to this file
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License
* at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and
* limitations under the License.
*
* The initial developer of the original code is David A. Hinds
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License version 2 (the "GPL"), in which
* case the provisions of the GPL are applicable instead of the
* above. If you wish to allow the use of your version of this file
* only under the terms of the GPL and not to allow others to use
* your version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the GPL. If you do not delete the
* provisions above, a recipient may use your version of this file
* under either the MPL or the GPL.
*/
#ifndef _LINUX_DRIVER_OPS_H
#define _LINUX_DRIVER_OPS_H
#ifndef DEV_NAME_LEN
#define DEV_NAME_LEN 32
#endif
#ifdef __KERNEL__
typedef struct dev_node_t {
char dev_name[DEV_NAME_LEN];
u_short major, minor;
struct dev_node_t *next;
} dev_node_t;
typedef struct dev_locator_t {
enum { LOC_ISA, LOC_PCI } bus;
union {
struct {
u_short io_base_1, io_base_2;
u_long mem_base;
u_char irq, dma;
} isa;
struct {
u_char bus;
u_char devfn;
} pci;
} b;
} dev_locator_t;
typedef struct driver_operations {
char *name;
dev_node_t *(*attach) (dev_locator_t *loc);
void (*suspend) (dev_node_t *dev);
void (*resume) (dev_node_t *dev);
void (*detach) (dev_node_t *dev);
} driver_operations;
int register_driver(struct driver_operations *ops);
void unregister_driver(struct driver_operations *ops);
#endif /* __KERNEL__ */
#endif /* _LINUX_DRIVER_OPS_H */
...@@ -30,9 +30,9 @@ ...@@ -30,9 +30,9 @@
#ifndef _LINUX_DS_H #ifndef _LINUX_DS_H
#define _LINUX_DS_H #define _LINUX_DS_H
#include <pcmcia/driver_ops.h>
#include <pcmcia/bulkmem.h> #include <pcmcia/bulkmem.h>
#include <linux/device.h> #include <linux/device.h>
#include <pcmcia/cs_types.h>
typedef struct tuple_parse_t { typedef struct tuple_parse_t {
tuple_t tuple; tuple_t tuple;
...@@ -108,6 +108,12 @@ typedef union ds_ioctl_arg_t { ...@@ -108,6 +108,12 @@ typedef union ds_ioctl_arg_t {
#ifdef __KERNEL__ #ifdef __KERNEL__
typedef struct dev_node_t {
char dev_name[DEV_NAME_LEN];
u_short major, minor;
struct dev_node_t *next;
} dev_node_t;
typedef struct dev_link_t { typedef struct dev_link_t {
dev_node_t *dev; dev_node_t *dev;
u_int state, open; u_int state, open;
...@@ -144,7 +150,7 @@ int unregister_pccard_driver(dev_info_t *dev_info); ...@@ -144,7 +150,7 @@ int unregister_pccard_driver(dev_info_t *dev_info);
extern struct bus_type pcmcia_bus_type; extern struct bus_type pcmcia_bus_type;
struct pcmcia_driver { struct pcmcia_driver {
int use_count, status; int use_count;
dev_link_t *(*attach)(void); dev_link_t *(*attach)(void);
void (*detach)(dev_link_t *); void (*detach)(dev_link_t *);
struct module *owner; struct module *owner;
......
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