[PATCHES] replace socket_bind_t with struct pcmcia_device
Dominik Brodowski
linux at brodo.de
Tue Sep 30 08:55:36 BST 2003
Hi,
These three patches replace struct socket_bind_t with a new
struct pcmcia_device and register it with the device core.
Please consider applying,
Dominik
change-ds-license
As previously discussed and ack'ed by David Hinds, change the
license of ds.c ands.h to GPL only.
pcmcia-device
Introduce a new struct pcmcia_device. So far it doesn't do anything
useful besides showing up in the sysfs tree, but this will change soon.
The device registration is only done after the userspace carmgr
detected a pcmcia card, found it in its database, and then tries to bind
a driver for this device. This can only properly be moved up if the PCMCIA
socket resource management is done within the kernel. And this still has
to wait for other changes...
remove_socket_bind_t
Remove struct socket_bind_t by moving "dev_link_t *instance" to struct
pcmcia_device, and transforming all users of socket_bind_t to use struct
pcmcia_device instead. Also, CodingStyle updates for
bind_request and unbind_request.
-------------- next part --------------
As previously discussed and ack'ed by David Hinds, change the
license of ds.c ands.h to GPL only.
drivers/pcmcia/ds.c | 33 ++++++---------------------------
include/pcmcia/ds.h | 27 +++------------------------
2 files changed, 9 insertions(+), 51 deletions(-)
diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c 2003-09-29 22:42:34.228551424 +0200
+++ linux/drivers/pcmcia/ds.c 2003-09-29 22:48:06.989964000 +0200
@@ -3,32 +3,11 @@
PC Card Driver Services
ds.c 1.112 2001/10/13 00:08:28
-
- 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 at 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.
-
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
======================================================================*/
#include <linux/config.h>
@@ -65,7 +44,7 @@
MODULE_AUTHOR("David Hinds <dahinds at users.sourceforge.net>");
MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE);
-MODULE_LICENSE("Dual MPL/GPL");
+MODULE_LICENSE("GPL");
#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
diff -ruN linux-original/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- linux-original/include/pcmcia/ds.h 2003-09-29 22:42:42.768253192 +0200
+++ linux/include/pcmcia/ds.h 2003-09-29 22:47:25.016344960 +0200
@@ -1,30 +1,9 @@
/*
* ds.h 1.56 2000/06/12 21:55:40
*
- * 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 at 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.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
*/
#ifndef _LINUX_DS_H
-------------- next part --------------
Introduce a new struct pcmcia_device. So far it doesn't do anything
useful besides showing up in the sysfs tree, but this will change soon.
The device registration is only done after the userspace carmgr
detected a pcmcia card, found it in its database, and then tries to bind
a driver for this device. This can only properly be moved up if the PCMCIA
socket resource management is done within the kernel. And this still has
to wait for other changes...
drivers/pcmcia/ds.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++--
include/pcmcia/ds.h | 16 ++++++++++++
2 files changed, 82 insertions(+), 2 deletions(-)
diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c 2003-09-29 22:49:49.528375792 +0200
+++ linux/drivers/pcmcia/ds.c 2003-09-29 23:50:33.033478824 +0200
@@ -87,7 +87,12 @@
socket_bind_t *bind;
struct device *socket_dev;
struct pcmcia_socket *parent;
+
+ /* the PCMCIA devices connected to this socket (normally one, more
+ * for multifunction devices: */
+ struct list_head devices_list;
};
+static spinlock_t pcmcia_dev_list_lock = SPIN_LOCK_UNLOCKED;
#define SOCKET_PRESENT 0x01
#define SOCKET_BUSY 0x02
@@ -169,6 +174,15 @@
}
#endif
+/* pcmcia_device handling */
+
+static void pcmcia_release_dev(struct device *dev)
+{
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+ kfree(p_dev);
+}
+
+
/*======================================================================
These manage a ring buffer of events pending for one user process
@@ -306,9 +320,11 @@
static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
{
struct pcmcia_driver *driver;
+ struct pcmcia_device *p_dev;
socket_bind_t *b;
bind_req_t bind_req;
int ret;
+ unsigned long flags;
if (!s)
return -EINVAL;
@@ -357,7 +373,36 @@
b->instance = NULL;
b->next = s->bind;
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)
+ goto no_p_dev;
+ memset(p_dev, 0, sizeof(struct pcmcia_device));
+
+ p_dev->socket = s->parent;
+ 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->func);
+ p_dev->dev.driver = &driver->drv;
+ ret = device_register(&p_dev->dev);
+ if (ret) {
+ 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:
+
if (driver->attach) {
b->instance = driver->attach();
if (b->instance == NULL) {
@@ -367,7 +412,7 @@
return -ENODEV;
}
}
-
+
return 0;
} /* bind_request */
@@ -443,6 +488,8 @@
static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
{
socket_bind_t **b, *c;
+ struct pcmcia_device *p_dev;
+ unsigned long flags;
DEBUG(2, "unbind_request(%d, '%s')\n", s->parent->sock,
(char *)bind_info->dev_info);
@@ -463,6 +510,22 @@
module_put(c->driver->owner);
*b = c->next;
kfree(c);
+
+ /* 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)
+ goto found;
+ }
+ spin_unlock_irqrestore(pcmcia_dev_list_lock, flags);
+ return 0;
+
+ found:
+ list_del(&p_dev->socket_device_list);
+ spin_unlock_irqrestore(pcmcia_dev_list_lock, flags);
+
+ device_unregister(&p_dev->dev);
+
return 0;
} /* unbind_request */
@@ -822,6 +885,7 @@
init_waitqueue_head(&s->queue);
init_waitqueue_head(&s->request);
+ INIT_LIST_HEAD(&s->devices_list);
/* initialize data */
s->socket_dev = socket->dev.dev;
diff -ruN linux-original/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- linux-original/include/pcmcia/ds.h 2003-09-29 22:49:49.000000000 +0200
+++ linux/include/pcmcia/ds.h 2003-09-29 23:27:12.000000000 +0200
@@ -137,5 +137,21 @@
/* error reporting */
void cs_error(client_handle_t handle, int func, int ret);
+struct pcmcia_socket;
+
+struct pcmcia_device {
+ /* the socket and the function no [for multifunction devices]
+ uniquely define a pcmcia_device */
+ struct pcmcia_socket *socket;
+ 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)
+
#endif /* __KERNEL__ */
#endif /* _LINUX_DS_H */
-------------- next part --------------
Remove struct socket_bind_t by moving "dev_link_t *instance" to struct
pcmcia_device, and transforming all users of socket_bind_t to use struct
pcmcia_device instead. Also, CodingStyle updates for
bind_request and unbind_request.
drivers/pcmcia/ds.c | 280 +++++++++++++++++++++++++---------------------------
include/pcmcia/ds.h | 4
2 files changed, 140 insertions(+), 144 deletions(-)
diff -ruN linux-original/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-original/drivers/pcmcia/ds.c 2003-09-30 00:09:24.930404336 +0200
+++ linux/drivers/pcmcia/ds.c 2003-09-30 00:38:01.674419576 +0200
@@ -57,13 +57,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
@@ -84,8 +77,7 @@
int req_pending, req_result;
wait_queue_head_t queue, request;
struct work_struct removal;
- socket_bind_t *bind;
- struct device *socket_dev;
+
struct pcmcia_socket *parent;
/* the PCMCIA devices connected to this socket (normally one, more
@@ -319,109 +311,115 @@
static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
{
- struct pcmcia_driver *driver;
- struct pcmcia_device *p_dev;
- socket_bind_t *b;
- bind_req_t bind_req;
- int ret;
- unsigned long flags;
+ struct pcmcia_driver *p_drv;
+ struct pcmcia_device *p_dev;
+ bind_req_t bind_req;
+ int ret;
+ unsigned long flags;
- if (!s)
- return -EINVAL;
+ if (!s)
+ return -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;
- }
-
- 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;
- }
+ DEBUG(2, "bind_request(%d, '%s')\n", s->parent->sock,
+ (char *)bind_info->dev_info);
- /* 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;
-
- /* Currently, the userspace pcmcia cardmgr detects pcmcia devices.
- * Here this information is translated into a kernel
- * struct pcmcia_device.
- */
+ /* find the driver which shall be bound to this device */
+ p_drv = get_pcmcia_driver(&bind_info->dev_info);
+ if (!p_drv)
+ return -EINVAL;
+ if (!try_module_get(p_drv->owner))
+ return -EINVAL;
- p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
- if (!p_dev)
- goto no_p_dev;
- memset(p_dev, 0, sizeof(struct pcmcia_device));
-
- p_dev->socket = s->parent;
- 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->func);
- p_dev->dev.driver = &driver->drv;
- ret = device_register(&p_dev->dev);
- if (ret) {
- 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);
+ /* verify that no such device exists at the moment. */
+ 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) {
+ spin_unlock_irqrestore(pcmcia_dev_list_lock, flags);
+ bind_info->instance = p_dev->instance;
+ ret = -EBUSY;
+ goto err_put;
+ }
+ }
+ spin_unlock_irqrestore(pcmcia_dev_list_lock, flags);
- no_p_dev:
+ /* pcmcia-cs bind -- will be unified soon */
+ bind_req.Socket = s->parent;
+ bind_req.Function = bind_info->function;
+ bind_req.dev_info = (dev_info_t *) p_drv->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);
+ ret = -ENODEV;
+ goto err_put;
+ }
- 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;
+ /* 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) {
+ ret = -ENOMEM;
+ goto err_put;
}
- }
+ memset(p_dev, 0, sizeof(struct pcmcia_device));
- return 0;
+ p_dev->socket = s->parent;
+ 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->func);
+ p_dev->dev.driver = &p_drv->drv;
+ ret = device_register(&p_dev->dev);
+ if (ret) {
+ ret = -ENODEV;
+ kfree(p_dev);
+ goto err_put;
+ }
+ 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);
+
+
+ /* try to create an "instance"... */
+ 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 *)bind_info->dev_info);
+ ret = -ENODEV;
+ goto err_unreg;
+ }
+ }
+
+ return 0;
+
+
+ err_unreg:
+ spin_lock_irqsave(pcmcia_dev_list_lock, flags);
+ list_del(&p_dev->socket_device_list);
+ spin_unlock_irqrestore(pcmcia_dev_list_lock, flags);
+
+ device_unregister(&p_dev->dev);
+
+ err_put:
+ module_put(p_drv->owner);
+ 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_device *p_dev;
+ unsigned long flags;
#ifdef CONFIG_CARDBUS
/*
@@ -459,19 +457,23 @@
}
#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))
+ 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)
+ goto found;
+ }
+ spin_unlock_irqrestore(pcmcia_dev_list_lock, flags);
+ return -ENODEV;
+
+ found:
+ spin_unlock_irqrestore(pcmcia_dev_list_lock, flags);
+ if ((p_dev->instance == NULL) ||
+ (p_dev->instance->state & DEV_CONFIG_PENDING))
return -EAGAIN;
if (first)
- node = b->instance->dev;
+ node = p_dev->instance->dev;
else
- for (node = b->instance->dev; node; node = node->next)
+ for (node = p_dev->instance->dev; node; node = node->next)
if (node == bind_info->next) break;
if (node == NULL) return -ENODEV;
@@ -487,46 +489,37 @@
static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
{
- socket_bind_t **b, *c;
- struct pcmcia_device *p_dev;
- unsigned long flags;
-
- 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)
+ struct pcmcia_device *p_dev;
+ struct pcmcia_driver *p_drv;
+ unsigned long flags;
+
+ DEBUG(2, "unbind_request(%d, '%s')\n", s->parent->sock,
+ (char *)bind_info->dev_info);
+
+ 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)
+ goto found;
+ }
+ spin_unlock_irqrestore(pcmcia_dev_list_lock, flags);
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);
-
- /* 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)
- goto found;
- }
- spin_unlock_irqrestore(pcmcia_dev_list_lock, flags);
- return 0;
found:
- list_del(&p_dev->socket_device_list);
- spin_unlock_irqrestore(pcmcia_dev_list_lock, flags);
+ list_del(&p_dev->socket_device_list);
+ spin_unlock_irqrestore(pcmcia_dev_list_lock, flags);
- device_unregister(&p_dev->dev);
-
- return 0;
+ /* detach the "instance" */
+ p_drv = to_pcmcia_drv(p_dev->dev.driver);
+ if (p_drv) {
+ p_drv->use_count--;
+ if ((p_drv->detach) && (p_dev->instance))
+ p_drv->detach(p_dev->instance);
+ }
+ module_put(p_drv->owner);
+
+ device_unregister(&p_dev->dev);
+
+ return 0;
} /* unbind_request */
/*======================================================================
@@ -888,7 +881,6 @@
INIT_LIST_HEAD(&s->devices_list);
/* initialize data */
- s->socket_dev = socket->dev.dev;
INIT_WORK(&s->removal, handle_removal, s);
s->parent = socket;
diff -ruN linux-original/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- linux-original/include/pcmcia/ds.h 2003-09-30 00:09:24.930404336 +0200
+++ linux/include/pcmcia/ds.h 2003-09-30 00:11:47.440739472 +0200
@@ -147,6 +147,10 @@
struct list_head socket_device_list;
+ /* deprecated, a cleaned up version will be moved into this
+ struct soon */
+ dev_link_t *instance;
+
struct device dev;
};
More information about the linux-pcmcia
mailing list