[PATCHES] pcmcia: two more ds.c patches
Dominik Brodowski
linux at brodo.de
Sun Jun 22 11:24:38 BST 2003
... which are based on the earlier ds_device patch. Finally, we're doing
something useful with struct pcmcia_device:
pcmcia_ds_bind_probe: replace socket_bind_t with struct pcmcia_device
pcmcia_ds_sysfs_output: add some sysfs output.
Dominik
based on / requires:
pcmcia_ds_no_sleep
pcmcia_ds_license
pcmcia_ds_resources_1ab
pcmcia_ds_device
-------------- next part --------------
Replace pcmcia_bind_device and pcmcia_unbind_device with more generic
->probe and ->remove callbacks which may be called from an in-kernel
matching function as well. A cardmgr compatibility layer makes sure
that existing setups work.
drivers/pcmcia/ds.c | 241 +++++++++++++++++++++++++++++-----------------------
include/pcmcia/ds.h | 3
2 files changed, 141 insertions(+), 103 deletions(-)
diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c 2003-06-22 08:28:19.000000000 +0200
+++ linux/drivers/pcmcia/ds.c 2003-06-22 08:27:34.000000000 +0200
@@ -63,13 +63,6 @@
/*====================================================================*/
-typedef struct socket_bind_t {
- struct pcmcia_driver *driver;
- u_char function;
- dev_link_t *instance;
- struct socket_bind_t *next;
-} socket_bind_t;
-
/* Device user information */
#define MAX_EVENTS 32
#define USER_MAGIC 0x7ea4
@@ -89,7 +82,7 @@
user_info_t *user;
int req_pending, req_result;
wait_queue_head_t queue, request;
- socket_bind_t *bind;
+
struct device *socket_dev;
struct pcmcia_socket *parent;
@@ -137,6 +130,10 @@
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);
+static int pcmcia_device_probe(struct device *dev);
+static int pcmcia_device_remove(struct device *dev);
+
+
/**
* pcmcia_register_driver - register a PCMCIA driver with the bus core
*
@@ -149,6 +146,8 @@
driver->use_count = 0;
driver->drv.bus = &pcmcia_bus_type;
+ driver->drv.probe = pcmcia_device_probe;
+ driver->drv.remove = pcmcia_device_remove;
return driver_register(&driver->drv);
}
@@ -190,6 +189,71 @@
}
#endif
+
+/********************* generic probe/remove callbacks ***********************/
+
+
+static int pcmcia_device_probe(struct device *dev)
+{
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+ struct pcmcia_driver *p_drv = to_pcmcia_drv(dev->driver);
+ struct pcmcia_socket *s = p_dev->socket;
+ int ret = 0;
+ bind_req_t bind_req;
+
+ DEBUG(0, "ds: pcmcia_device_probe()");
+
+ bind_req.Socket = s;
+ bind_req.Function = p_dev->func;
+ bind_req.dev_info = (dev_info_t *) p_drv->drv.name;
+ ret = pcmcia_bind_device(&bind_req);
+ if (ret) {
+ cs_error(NULL, BindDevice, ret);
+ printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n",
+ (char *)dev_info, s->sock);
+ ret = -ENODEV;
+ goto e_out;
+ }
+
+ /* Add binding to list for this socket */
+ p_drv->use_count++;
+
+ if (p_drv->attach) {
+ p_dev->instance = p_drv->attach();
+ if (!p_dev->instance) {
+ printk(KERN_NOTICE "ds: unable to create instance "
+ "of '%s'!\n", (char *)p_drv->drv.name);
+ ret = -ENODEV;
+ goto e_dec_out;
+ }
+ }
+ return 0;
+
+ e_dec_out:
+ p_drv->use_count--;
+ e_out:
+ module_put(p_drv->owner);
+ return (ret);
+}
+
+
+static int pcmcia_device_remove(struct device *dev)
+{
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+ struct pcmcia_driver *p_drv = to_pcmcia_drv(dev->driver);
+
+ DEBUG(0, "ds: pcmcia_device_remove()");
+
+ if (p_drv->detach)
+ p_drv->detach(p_dev->instance);
+
+ p_drv->use_count--;
+ module_put(p_drv->owner);
+
+ return 0;
+}
+
+
/*********************** device adding / removing ***************************/
@@ -455,78 +519,46 @@
static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
{
- struct pcmcia_driver *driver;
- socket_bind_t *b;
- bind_req_t bind_req;
- int ret;
-
- if (!s)
- return -EINVAL;
+ struct pcmcia_driver *driver;
+ struct pcmcia_device *dev;
+ int ret = -EINVAL;
- DEBUG(2, "bind_request(%d, '%s')\n", s->parent->sock,
- (char *)bind_info->dev_info);
- driver = get_pcmcia_driver(&bind_info->dev_info);
- if (!driver)
- return -EINVAL;
-
- for (b = s->bind; b; b = b->next)
- if ((driver == b->driver) &&
- (bind_info->function == b->function))
- break;
- if (b != NULL) {
- bind_info->instance = b->instance;
- return -EBUSY;
- }
+ driver = get_pcmcia_driver(&bind_info->dev_info);
+ if (!driver)
+ return -EINVAL;
- if (!try_module_get(driver->owner))
- return -EINVAL;
+ if (!try_module_get(driver->owner))
+ return -EINVAL;
- bind_req.Socket = s->parent;
- bind_req.Function = bind_info->function;
- bind_req.dev_info = (dev_info_t *) driver->drv.name;
- ret = pcmcia_bind_device(&bind_req);
- if (ret != CS_SUCCESS) {
- cs_error(NULL, BindDevice, ret);
- printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n",
- (char *)dev_info, s->parent->sock);
- module_put(driver->owner);
- return -ENODEV;
- }
+ if (!get_bus(&pcmcia_bus_type))
+ return -EINVAL;
- /* Add binding to list for this socket */
- driver->use_count++;
- b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL);
- if (!b)
- {
- driver->use_count--;
- module_put(driver->owner);
- return -ENOMEM;
- }
- b->driver = driver;
- b->function = bind_info->function;
- b->instance = NULL;
- b->next = s->bind;
- s->bind = b;
-
- if (driver->attach) {
- b->instance = driver->attach();
- if (b->instance == NULL) {
- printk(KERN_NOTICE "ds: unable to create instance "
- "of '%s'!\n", (char *)bind_info->dev_info);
- module_put(driver->owner);
- return -ENODEV;
+ down(&s->devices_list_sem);
+ list_for_each_entry(dev, &s->devices_list, socket_device_list) {
+ if (dev->func == bind_info->function) {
+ if (dev->dev.driver == &driver->drv) {
+ ret = 0; /* in-kernel matching got here first */
+ break;
+ }
+ dev->dev.driver = &driver->drv;
+ ret = pcmcia_device_probe(&dev->dev);
+ if (!ret)
+ device_bind_driver(&dev->dev);
+ }
}
- }
-
- return 0;
+ up(&s->devices_list_sem);
+
+ return (ret);
} /* bind_request */
/*====================================================================*/
static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, int first)
{
- socket_bind_t *b;
dev_node_t *node;
+ struct pcmcia_driver *driver;
+ struct pcmcia_device *dev;
+ int ret = -ENODEV;
#ifdef CONFIG_CARDBUS
/*
@@ -564,27 +596,40 @@
}
#endif
- for (b = s->bind; b; b = b->next)
- if ((strcmp((char *)b->driver->drv.name,
- (char *)bind_info->dev_info) == 0) &&
- (b->function == bind_info->function))
- break;
- if (b == NULL) return -ENODEV;
- if ((b->instance == NULL) ||
- (b->instance->state & DEV_CONFIG_PENDING))
- return -EAGAIN;
+ driver = get_pcmcia_driver(&bind_info->dev_info);
+ if (!driver)
+ return -ENODEV;
+
+ down(&s->devices_list_sem);
+ list_for_each_entry(dev, &s->devices_list, socket_device_list) {
+ if ((dev->func == bind_info->function) &&
+ (dev->dev.driver == &driver->drv)) {
+ ret = 0;
+ break;
+ }
+ }
+ up(&s->devices_list_sem);
+
+ if (ret)
+ return (ret);
+
+ if ((!dev->instance) ||
+ (dev->instance->state & DEV_CONFIG_PENDING))
+ return -EAGAIN;
if (first)
- node = b->instance->dev;
+ node = dev->instance->dev;
else
- for (node = b->instance->dev; node; node = node->next)
- if (node == bind_info->next) break;
- if (node == NULL) return -ENODEV;
+ for (node = dev->instance->dev; node; node = node->next)
+ if (node == bind_info->next)
+ break;
+ if (!node)
+ return -ENODEV;
strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
bind_info->major = node->major;
bind_info->minor = node->minor;
bind_info->next = node->next;
-
+
return 0;
} /* get_device_info */
@@ -592,28 +637,18 @@
static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
{
- socket_bind_t **b, *c;
+ struct pcmcia_device *dev;
- DEBUG(2, "unbind_request(%d, '%s')\n", s->parent->sock,
- (char *)bind_info->dev_info);
- for (b = &s->bind; *b; b = &(*b)->next)
- if ((strcmp((char *)(*b)->driver->drv.name,
- (char *)bind_info->dev_info) == 0) &&
- ((*b)->function == bind_info->function))
- break;
- if (*b == NULL)
- return -ENODEV;
-
- c = *b;
- c->driver->use_count--;
- if (c->driver->detach) {
- if (c->instance)
- c->driver->detach(c->instance);
- }
- module_put(c->driver->owner);
- *b = c->next;
- kfree(c);
- return 0;
+ down(&s->devices_list_sem);
+ list_for_each_entry(dev, &s->devices_list, socket_device_list) {
+ if ((dev->func == bind_info->function) && dev->dev.driver) {
+ device_release_driver(&dev->dev);
+ put_bus(&pcmcia_bus_type);
+ }
+ }
+ up(&s->devices_list_sem);
+
+ return 0;
} /* unbind_request */
/*======================================================================
diff -ruN linux-original/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- linux-original/include/pcmcia/ds.h 2003-06-22 08:28:19.000000000 +0200
+++ linux/include/pcmcia/ds.h 2003-06-21 07:52:02.000000000 +0200
@@ -179,6 +179,9 @@
unsigned int has_funcid;
cistpl_funcid_t funcid;
+
+ /* deprecated */
+ dev_link_t *instance;
};
#define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
-------------- next part --------------
This patch adds seven files (manf_id, card_id, func_id, vers1 to
vers4) to any pcmcia device registered with the driver model core.
ds.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 55 insertions(+)
diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c 2003-06-22 08:54:50.000000000 +0200
+++ linux/drivers/pcmcia/ds.c 2003-06-22 08:58:32.000000000 +0200
@@ -254,6 +254,43 @@
}
+/************************ per-device sysfs output ***************************/
+
+#define show_one(file_name, object, test) \
+static ssize_t show_##file_name \
+(struct device *dev, char *buf) \
+{ \
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
+ return p_dev->test ? sprintf (buf, "%x\n", p_dev->object) : \
+ sprintf(buf, "unknown\n"); \
+} \
+DEVICE_ATTR(file_name, 0444, show_##file_name, NULL);
+
+show_one(func_id, funcid.func, has_funcid);
+show_one(manf_id, manfid.manf, has_manfid);
+show_one(card_id, manfid.card, has_manfid);
+
+#define show_one_s(file_name, object, test) \
+static ssize_t show_##file_name \
+(struct device *dev, char *buf) \
+{ \
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
+ return test ? sprintf (buf, "%s\n", object) : \
+ sprintf(buf, "\n"); \
+} \
+DEVICE_ATTR(file_name, 0444, show_##file_name, NULL);
+
+show_one_s(vers1, (p_dev->vers1.str + p_dev->vers1.ofs[0]),
+ (p_dev->vers1.ns >= 1));
+show_one_s(vers2, (p_dev->vers1.str + p_dev->vers1.ofs[1]),
+ (p_dev->vers1.ns >= 2));
+show_one_s(vers3, (p_dev->vers1.str + p_dev->vers1.ofs[2]),
+ (p_dev->vers1.ns >= 3));
+show_one_s(vers4, (p_dev->vers1.str + p_dev->vers1.ofs[3]),
+ (p_dev->vers1.ns >= 4));
+
+
+
/*********************** device adding / removing ***************************/
@@ -360,6 +397,15 @@
}
list_add(&p_dev->socket_device_list, &s->pcmcia->devices_list);
+ /* add sysfs files */
+ device_create_file(&p_dev->dev, &dev_attr_func_id);
+ device_create_file(&p_dev->dev, &dev_attr_manf_id);
+ device_create_file(&p_dev->dev, &dev_attr_card_id);
+ device_create_file(&p_dev->dev, &dev_attr_vers1);
+ device_create_file(&p_dev->dev, &dev_attr_vers2);
+ device_create_file(&p_dev->dev, &dev_attr_vers3);
+ device_create_file(&p_dev->dev, &dev_attr_vers4);
+
/* if we got a multifunction device, we need to register more devices,
* so go back up */
func++;
@@ -381,6 +427,15 @@
down(&s->pcmcia->devices_list_sem);
list_for_each_safe(p1, p2, &s->pcmcia->devices_list) {
struct pcmcia_device *p_dev = container_of(p1, struct pcmcia_device, socket_device_list);
+
+ device_remove_file(&p_dev->dev, &dev_attr_func_id);
+ device_remove_file(&p_dev->dev, &dev_attr_manf_id);
+ device_remove_file(&p_dev->dev, &dev_attr_card_id);
+ device_remove_file(&p_dev->dev, &dev_attr_vers1);
+ device_remove_file(&p_dev->dev, &dev_attr_vers2);
+ device_remove_file(&p_dev->dev, &dev_attr_vers3);
+ device_remove_file(&p_dev->dev, &dev_attr_vers4);
+
device_unregister(&p_dev->dev);
list_del(&p_dev->socket_device_list);
kfree(p_dev);
More information about the linux-pcmcia
mailing list