- suspend & remove for pci_socket was broken -- thanks to Paul Mackerras for
noting this
- to correctly initialize multiple pci_socket devices, a sock_offset is
needed.
- s_info doesn't need to be an array.
Please apply,
Dominik
diff -ruN linux-original/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- linux-original/drivers/pcmcia/cs.c 2003-02-23 10:04:03.000000000 +0100
+++ linux/drivers/pcmcia/cs.c 2003-02-23 10:04:25.000000000 +0100
@@ -337,13 +337,14 @@
return -ENOMEM;
memset(s_info, 0, cls_d->nsock * sizeof(socket_info_t));
+ cls_d->s_info = s_info;
+
/* socket initialization */
for (i = 0; i < cls_d->nsock; i++) {
socket_info_t *s = &s_info[i];
- cls_d->s_info[i] = s;
s->ss_entry = cls_d->ops;
- s->sock = i;
+ s->sock = i + cls_d->sock_offset;
/* base address = 0, map = 0 */
s->cis_mem.flags = 0;
diff -ruN linux-original/drivers/pcmcia/pci_socket.c linux/drivers/pcmcia/pci_socket.c
--- linux-original/drivers/pcmcia/pci_socket.c 2003-02-23 10:04:03.000000000 +0100
+++ linux/drivers/pcmcia/pci_socket.c 2003-02-23 10:04:25.000000000 +0100
@@ -171,6 +171,16 @@
int err;
memset(socket, 0, sizeof(*socket));
+
+ /* prepare class_data */
+ socket->cls_d.sock_offset = nr;
+ socket->cls_d.nsock = 1; /* yenta is 1, no other low-level driver uses
+ this yet */
+ socket->cls_d.ops = &pci_socket_operations;
+ socket->cls_d.use_bus_pm = 1;
+ dev->dev.class_data = &socket->cls_d;
+
+ /* prepare pci_socket_t */
socket->dev = dev;
socket->op = ops;
pci_set_drvdata(dev, socket);
@@ -186,18 +196,6 @@
int cardbus_register(struct pci_dev *p_dev)
{
- pci_socket_t *socket = pci_get_drvdata(p_dev);
- struct pcmcia_socket_class_data *cls_d;
-
- if (!socket)
- return -EINVAL;
-
- cls_d = &socket->cls_d;
- cls_d->nsock = 1; /* yenta is 1, no other low-level driver uses
- this yet */
- cls_d->ops = &pci_socket_operations;
- cls_d->use_bus_pm = 1;
- p_dev->dev.class_data = cls_d;
return 0;
}
@@ -227,14 +225,16 @@
static int cardbus_suspend (struct pci_dev *dev, u32 state)
{
pci_socket_t *socket = pci_get_drvdata(dev);
- pcmcia_suspend_socket (socket->pcmcia_socket);
+ if (socket && socket->cls_d.s_info)
+ pcmcia_suspend_socket (socket->cls_d.s_info);
return 0;
}
static int cardbus_resume (struct pci_dev *dev)
{
pci_socket_t *socket = pci_get_drvdata(dev);
- pcmcia_resume_socket (socket->pcmcia_socket);
+ if (socket && socket->cls_d.s_info)
+ pcmcia_resume_socket (socket->cls_d.s_info);
return 0;
}
diff -ruN linux-original/drivers/pcmcia/pci_socket.h linux/drivers/pcmcia/pci_socket.h
--- linux-original/drivers/pcmcia/pci_socket.h 2003-02-23 10:04:03.000000000 +0100
+++ linux/drivers/pcmcia/pci_socket.h 2003-02-23 10:04:25.000000000 +0100
@@ -20,7 +20,6 @@
socket_cap_t cap;
spinlock_t event_lock;
unsigned int events;
- struct socket_info_t *pcmcia_socket;
struct work_struct tq_task;
struct timer_list poll_timer;
diff -ruN linux-original/include/pcmcia/ss.h linux/include/pcmcia/ss.h
--- linux-original/include/pcmcia/ss.h 2003-02-23 10:04:12.000000000 +0100
+++ linux/include/pcmcia/ss.h 2003-02-23 10:04:25.000000000 +0100
@@ -145,12 +145,12 @@
* Calls to set up low-level "Socket Services" drivers
*/
-#define MAX_SOCKETS_PER_DEV 8
-
struct pcmcia_socket_class_data {
unsigned int nsock; /* number of sockets */
+ unsigned int sock_offset; /* socket # (which is
+ * returned to driver) = sock_offset + (0, 1, .. , (nsock-1) */
struct pccard_operations *ops; /* see above */
- void *s_info[MAX_SOCKETS_PER_DEV]; /* socket_info_t */
+ void *s_info; /* socket_info_t */
unsigned int use_bus_pm;
};
On Sun, Feb 23, 2003 at 10:06:08AM +0100, Dominik Brodowski wrote:
> diff -ruN linux-original/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
> --- linux-original/drivers/pcmcia/cs.c 2003-02-23 10:04:03.000000000 +0100
> +++ linux/drivers/pcmcia/cs.c 2003-02-23 10:04:25.000000000 +0100
> @@ -337,13 +337,14 @@
> return -ENOMEM;
> memset(s_info, 0, cls_d->nsock * sizeof(socket_info_t));
>
> + cls_d->s_info = s_info;
> +
> /* socket initialization */
> for (i = 0; i < cls_d->nsock; i++) {
> socket_info_t *s = &s_info[i];
>
> - cls_d->s_info[i] = s;
> s->ss_entry = cls_d->ops;
> - s->sock = i;
> + s->sock = i + cls_d->sock_offset;
>
> /* base address = 0, map = 0 */
> s->cis_mem.flags = 0;
I think you missed changing:
s->ss_entry->inquire_socket(i, &s->cap);
to:
s->ss_entry->inquire_socket(s->sock, &s->cap);
otherwise both sockets end up pointing at the same cb_dev.
--
Russell King ([email protected]) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html
Thanks for the hint, Russell -- here comes an updated patch:
- suspend & remove for pci_socket was broken -- thanks to Paul Mackerras for
noting this
- to correctly initialize multiple pci_socket devices, a sock_offset is
needed.
- s_info doesn't need to be an array.
Please apply,
Dominik
diff -ruN linux-original/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- linux-original/drivers/pcmcia/cs.c 2003-02-23 13:12:56.000000000 +0100
+++ linux/drivers/pcmcia/cs.c 2003-02-23 13:12:23.000000000 +0100
@@ -337,13 +337,14 @@
return -ENOMEM;
memset(s_info, 0, cls_d->nsock * sizeof(socket_info_t));
+ cls_d->s_info = s_info;
+
/* socket initialization */
for (i = 0; i < cls_d->nsock; i++) {
socket_info_t *s = &s_info[i];
- cls_d->s_info[i] = s;
s->ss_entry = cls_d->ops;
- s->sock = i;
+ s->sock = i + cls_d->sock_offset;
/* base address = 0, map = 0 */
s->cis_mem.flags = 0;
@@ -359,7 +360,7 @@
if (j == sockets) sockets++;
init_socket(s);
- s->ss_entry->inquire_socket(i, &s->cap);
+ s->ss_entry->inquire_socket(s->sock, &s->cap);
#ifdef CONFIG_PROC_FS
if (proc_pccard) {
char name[3];
diff -ruN linux-original/drivers/pcmcia/pci_socket.c linux/drivers/pcmcia/pci_socket.c
--- linux-original/drivers/pcmcia/pci_socket.c 2003-02-23 13:12:56.000000000 +0100
+++ linux/drivers/pcmcia/pci_socket.c 2003-02-23 10:04:25.000000000 +0100
@@ -171,6 +171,16 @@
int err;
memset(socket, 0, sizeof(*socket));
+
+ /* prepare class_data */
+ socket->cls_d.sock_offset = nr;
+ socket->cls_d.nsock = 1; /* yenta is 1, no other low-level driver uses
+ this yet */
+ socket->cls_d.ops = &pci_socket_operations;
+ socket->cls_d.use_bus_pm = 1;
+ dev->dev.class_data = &socket->cls_d;
+
+ /* prepare pci_socket_t */
socket->dev = dev;
socket->op = ops;
pci_set_drvdata(dev, socket);
@@ -186,18 +196,6 @@
int cardbus_register(struct pci_dev *p_dev)
{
- pci_socket_t *socket = pci_get_drvdata(p_dev);
- struct pcmcia_socket_class_data *cls_d;
-
- if (!socket)
- return -EINVAL;
-
- cls_d = &socket->cls_d;
- cls_d->nsock = 1; /* yenta is 1, no other low-level driver uses
- this yet */
- cls_d->ops = &pci_socket_operations;
- cls_d->use_bus_pm = 1;
- p_dev->dev.class_data = cls_d;
return 0;
}
@@ -227,14 +225,16 @@
static int cardbus_suspend (struct pci_dev *dev, u32 state)
{
pci_socket_t *socket = pci_get_drvdata(dev);
- pcmcia_suspend_socket (socket->pcmcia_socket);
+ if (socket && socket->cls_d.s_info)
+ pcmcia_suspend_socket (socket->cls_d.s_info);
return 0;
}
static int cardbus_resume (struct pci_dev *dev)
{
pci_socket_t *socket = pci_get_drvdata(dev);
- pcmcia_resume_socket (socket->pcmcia_socket);
+ if (socket && socket->cls_d.s_info)
+ pcmcia_resume_socket (socket->cls_d.s_info);
return 0;
}
diff -ruN linux-original/drivers/pcmcia/pci_socket.h linux/drivers/pcmcia/pci_socket.h
--- linux-original/drivers/pcmcia/pci_socket.h 2003-02-23 13:12:56.000000000 +0100
+++ linux/drivers/pcmcia/pci_socket.h 2003-02-23 10:04:25.000000000 +0100
@@ -20,7 +20,6 @@
socket_cap_t cap;
spinlock_t event_lock;
unsigned int events;
- struct socket_info_t *pcmcia_socket;
struct work_struct tq_task;
struct timer_list poll_timer;
diff -ruN linux-original/include/pcmcia/ss.h linux/include/pcmcia/ss.h
--- linux-original/include/pcmcia/ss.h 2003-02-23 13:12:56.000000000 +0100
+++ linux/include/pcmcia/ss.h 2003-02-23 10:04:25.000000000 +0100
@@ -145,12 +145,12 @@
* Calls to set up low-level "Socket Services" drivers
*/
-#define MAX_SOCKETS_PER_DEV 8
-
struct pcmcia_socket_class_data {
unsigned int nsock; /* number of sockets */
+ unsigned int sock_offset; /* socket # (which is
+ * returned to driver) = sock_offset + (0, 1, .. , (nsock-1) */
struct pccard_operations *ops; /* see above */
- void *s_info[MAX_SOCKETS_PER_DEV]; /* socket_info_t */
+ void *s_info; /* socket_info_t */
unsigned int use_bus_pm;
};