summaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r--drivers/pcmcia/cs.c214
-rw-r--r--drivers/pcmcia/cs_internal.h1
-rw-r--r--drivers/pcmcia/pci_socket.c92
-rw-r--r--drivers/pcmcia/pci_socket.h2
4 files changed, 202 insertions, 107 deletions
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 0c42771ee..f278c9e41 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -309,50 +309,63 @@ static void reset_socket(u_long i);
static void unreset_socket(u_long i);
static void parse_events(void *info, u_int events);
-int register_ss_entry(int nsock, struct pccard_operations * ss_entry)
+socket_info_t *pcmcia_register_socket (int slot,
+ struct pccard_operations * ss_entry,
+ int use_bus_pm)
{
- int i, ns;
socket_info_t *s;
+ int i;
- DEBUG(0, "cs: register_ss_entry(%d, 0x%p)\n", nsock, ss_entry);
+ DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", ss_entry);
+
+ s = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL);
+ memset(s, 0, sizeof(socket_info_t));
+
+ s->ss_entry = ss_entry;
+ s->sock = slot;
+ s->setup.data = sockets;
+ s->setup.function = &setup_socket;
+ s->shutdown.data = sockets;
+ s->shutdown.function = &shutdown_socket;
+ /* base address = 0, map = 0 */
+ s->cis_mem.flags = 0;
+ s->cis_mem.speed = cis_speed;
+ s->use_bus_pm = use_bus_pm;
+ s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
+ spin_lock_init(&s->lock);
+
+ for (i = 0; i < sockets; i++)
+ if (socket_table[i] == NULL) break;
+ socket_table[i] = s;
+ if (i == sockets) sockets++;
- for (ns = 0; ns < nsock; ns++) {
- s = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL);
- memset(s, 0, sizeof(socket_info_t));
-
- s->ss_entry = ss_entry;
- s->sock = ns;
- s->setup.data = sockets;
- s->setup.function = &setup_socket;
- s->shutdown.data = sockets;
- s->shutdown.function = &shutdown_socket;
- /* base address = 0, map = 0 */
- s->cis_mem.flags = 0;
- s->cis_mem.speed = cis_speed;
- s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
- spin_lock_init(&s->lock);
-
- for (i = 0; i < sockets; i++)
- if (socket_table[i] == NULL) break;
- socket_table[i] = s;
- if (i == sockets) sockets++;
-
- init_socket(s);
- ss_entry->inquire_socket(ns, &s->cap);
+ init_socket(s);
+ ss_entry->inquire_socket(slot, &s->cap);
#ifdef CONFIG_PROC_FS
- if (proc_pccard) {
- char name[3];
- sprintf(name, "%02d", i);
- s->proc = proc_mkdir(name, proc_pccard);
- if (s->proc)
- ss_entry->proc_setup(ns, s->proc);
+ if (proc_pccard) {
+ char name[3];
+ sprintf(name, "%02d", i);
+ s->proc = proc_mkdir(name, proc_pccard);
+ if (s->proc)
+ ss_entry->proc_setup(slot, s->proc);
#ifdef PCMCIA_DEBUG
- if (s->proc)
- create_proc_read_entry("clients", 0, s->proc,
- proc_read_clients, s);
+ if (s->proc)
+ create_proc_read_entry("clients", 0, s->proc,
+ proc_read_clients, s);
#endif
- }
+ }
#endif
+ return s;
+} /* pcmcia_register_socket */
+
+int register_ss_entry(int nsock, struct pccard_operations * ss_entry)
+{
+ int ns;
+
+ DEBUG(0, "cs: register_ss_entry(%d, 0x%p)\n", nsock, ss_entry);
+
+ for (ns = 0; ns < nsock; ns++) {
+ pcmcia_register_socket (ns, ss_entry, 0);
}
return 0;
@@ -360,49 +373,57 @@ int register_ss_entry(int nsock, struct pccard_operations * ss_entry)
/*====================================================================*/
-void unregister_ss_entry(struct pccard_operations * ss_entry)
+void pcmcia_unregister_socket(socket_info_t *s)
{
- int i, j;
- socket_info_t *s = NULL;
+ int j, socket = -1;
client_t *client;
+ for (j = 0; j < MAX_SOCK; j++)
+ if (socket_table [j] == s) {
+ socket = j;
+ break;
+ }
+ if (socket < 0)
+ return;
+
#ifdef CONFIG_PROC_FS
- for (i = 0; i < sockets; i++) {
- s = socket_table[i];
- if (s->ss_entry != ss_entry) continue;
- if (proc_pccard) {
- char name[3];
- sprintf(name, "%02d", i);
+ if (proc_pccard) {
+ char name[3];
+ sprintf(name, "%02d", socket);
#ifdef PCMCIA_DEBUG
- remove_proc_entry("clients", s->proc);
+ remove_proc_entry("clients", s->proc);
#endif
- remove_proc_entry(name, proc_pccard);
- }
+ remove_proc_entry(name, proc_pccard);
}
#endif
- for (;;) {
- for (i = 0; i < sockets; i++) {
- s = socket_table[i];
- if (s->ss_entry == ss_entry) break;
- }
- if (i == sockets)
- break;
- shutdown_socket(i);
- release_cis_mem(s);
- while (s->clients) {
- client = s->clients;
- s->clients = s->clients->next;
- kfree(client);
- }
- s->ss_entry = NULL;
- kfree(s);
- socket_table[i] = NULL;
- for (j = i; j < sockets-1; j++)
- socket_table[j] = socket_table[j+1];
- sockets--;
+ shutdown_socket(socket);
+ release_cis_mem(s);
+ while (s->clients) {
+ client = s->clients;
+ s->clients = s->clients->next;
+ kfree(client);
+ }
+ s->ss_entry = NULL;
+ kfree(s);
+
+ socket_table[socket] = NULL;
+ for (j = socket; j < sockets-1; j++)
+ socket_table[j] = socket_table[j+1];
+ sockets--;
+} /* pcmcia_unregister_socket */
+
+void unregister_ss_entry(struct pccard_operations * ss_entry)
+{
+ int i;
+
+ for (i = 0; i < sockets; i++) {
+ socket_info_t *socket = socket_table[i];
+ if (socket->ss_entry == ss_entry)
+ pcmcia_unregister_socket (socket);
+ else
+ i++;
}
-
} /* unregister_ss_entry */
/*======================================================================
@@ -675,35 +696,51 @@ static void parse_events(void *info, u_int events)
======================================================================*/
+void pcmcia_suspend_socket (socket_info_t *s)
+{
+ if ((s->state & SOCKET_PRESENT) && !(s->state & SOCKET_SUSPEND)) {
+ send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
+ suspend_socket(s);
+ s->state |= SOCKET_SUSPEND;
+ }
+}
+
+void pcmcia_resume_socket (socket_info_t *s)
+{
+ int stat;
+
+ /* Do this just to reinitialize the socket */
+ init_socket(s);
+ get_socket_status(s, &stat);
+
+ /* If there was or is a card here, we need to do something
+ about it... but parse_events will sort it all out. */
+ if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT))
+ parse_events(s, SS_DETECT);
+}
+
static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data)
{
- int i, stat;
+ int i;
socket_info_t *s;
-
+
+ /* only for busses that don't suspend/resume slots directly */
+
switch (rqst) {
case PM_SUSPEND:
DEBUG(1, "cs: received suspend notification\n");
for (i = 0; i < sockets; i++) {
- s = socket_table[i];
- if ((s->state & SOCKET_PRESENT) &&
- !(s->state & SOCKET_SUSPEND)){
- send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
- suspend_socket(s);
- s->state |= SOCKET_SUSPEND;
- }
+ s = socket_table [i];
+ if (!s->use_bus_pm)
+ pcmcia_suspend_socket (socket_table [i]);
}
break;
case PM_RESUME:
DEBUG(1, "cs: received resume notification\n");
for (i = 0; i < sockets; i++) {
- s = socket_table[i];
- /* Do this just to reinitialize the socket */
- init_socket(s);
- get_socket_status(s, &stat);
- /* If there was or is a card here, we need to do something
- about it... but parse_events will sort it all out. */
- if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT))
- parse_events(s, SS_DETECT);
+ s = socket_table [i];
+ if (!s->use_bus_pm)
+ pcmcia_resume_socket (socket_table [i]);
}
break;
}
@@ -2331,6 +2368,11 @@ EXPORT_SYMBOL(MTDHelperEntry);
EXPORT_SYMBOL(proc_pccard);
#endif
+EXPORT_SYMBOL(pcmcia_register_socket);
+EXPORT_SYMBOL(pcmcia_unregister_socket);
+EXPORT_SYMBOL(pcmcia_suspend_socket);
+EXPORT_SYMBOL(pcmcia_resume_socket);
+
static int __init init_pcmcia_cs(void)
{
printk(KERN_INFO "%s\n", release);
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index f355c337b..abd518a7f 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -160,6 +160,7 @@ typedef struct socket_info_t {
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc;
#endif
+ int use_bus_pm;
} socket_info_t;
/* Flags in config state */
diff --git a/drivers/pcmcia/pci_socket.c b/drivers/pcmcia/pci_socket.c
index 3f4463e75..9cc901603 100644
--- a/drivers/pcmcia/pci_socket.c
+++ b/drivers/pcmcia/pci_socket.c
@@ -28,6 +28,14 @@
#include "pci_socket.h"
+
+extern struct socket_info_t *pcmcia_register_socket (int slot,
+ struct pccard_operations *vtable, int use_bus_pm);
+extern void pcmcia_unregister_socket (struct socket_info_t *socket);
+extern void pcmcia_suspend_socket (struct socket_info_t *socket);
+extern void pcmcia_resume_socket (struct socket_info_t *socket);
+
+
/*
* Arbitrary define. This is the array of active cardbus
* entries.
@@ -161,45 +169,87 @@ static struct pccard_operations pci_socket_operations = {
pci_proc_setup
};
-static int __init add_pci_socket(int nr, struct pci_dev *dev, struct pci_socket_ops *ops)
+static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_socket_ops *ops)
{
pci_socket_t *socket = nr + pci_socket_array;
memset(socket, 0, sizeof(*socket));
socket->dev = dev;
socket->op = ops;
+ dev->driver_data = socket;
init_waitqueue_head(&socket->wait);
return socket->op->open(socket);
}
-static int __init pci_socket_init(void)
+static int __devinit
+cardbus_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
- struct pci_dev *dev = NULL;
- int nr = 0;
-
- while ((dev = pci_find_class(PCI_CLASS_BRIDGE_CARDBUS << 8, dev)) != NULL) {
- printk("Adding cardbus controller %d: %s\n", nr, dev->name);
- add_pci_socket(nr, dev, &yenta_operations);
- nr++;
+ int s;
+
+ for (s = 0; s < MAX_SOCKETS; s++) {
+ if (pci_socket_array [s].dev == 0) {
+ add_pci_socket (s, dev, &yenta_operations);
+ pci_socket_array [s].pcmcia_socket =
+ pcmcia_register_socket (s,
+ &pci_socket_operations,
+ 1);
+ return 0;
+ }
}
+ return -1;
+}
- if (nr <= 0)
- return -1;
- register_ss_entry(nr, &pci_socket_operations);
- return 0;
+static void __devexit cardbus_remove (struct pci_dev *dev)
+{
+ pci_socket_t *socket = (pci_socket_t *) dev->driver_data;
+
+ pcmcia_unregister_socket (socket->pcmcia_socket);
+ if (socket->op && socket->op->close)
+ socket->op->close(socket);
+ dev->driver_data = 0;
+}
+
+static void cardbus_suspend (struct pci_dev *dev)
+{
+ pci_socket_t *socket = (pci_socket_t *) dev->driver_data;
+ pcmcia_suspend_socket (socket->pcmcia_socket);
}
-static void __exit pci_socket_exit(void)
+static void cardbus_resume (struct pci_dev *dev)
{
- int i;
+ pci_socket_t *socket = (pci_socket_t *) dev->driver_data;
+ pcmcia_resume_socket (socket->pcmcia_socket);
+}
- unregister_ss_entry(&pci_socket_operations);
- for (i = 0; i < MAX_SOCKETS; i++) {
- pci_socket_t *socket = pci_socket_array + i;
- if (socket->op && socket->op->close)
- socket->op->close(socket);
- }
+static struct pci_device_id cardbus_table [] = { {
+ class: PCI_CLASS_BRIDGE_CARDBUS << 8,
+ class_mask: ~0,
+
+ vendor: PCI_ANY_ID,
+ device: PCI_ANY_ID,
+ subvendor: PCI_ANY_ID,
+ subdevice: PCI_ANY_ID,
+}, { /* all zeroes */ }
+};
+
+static struct pci_driver pci_cardbus_driver = {
+ name: "cardbus",
+ id_table: cardbus_table,
+ probe: cardbus_probe,
+ remove: cardbus_remove,
+ suspend: cardbus_suspend,
+ resume: cardbus_resume,
+};
+
+static int __devinit pci_socket_init(void)
+{
+ return pci_module_init (&pci_cardbus_driver);
+}
+
+static void __devexit pci_socket_exit (void)
+{
+ pci_unregister_driver (&pci_cardbus_driver);
}
module_init(pci_socket_init);
diff --git a/drivers/pcmcia/pci_socket.h b/drivers/pcmcia/pci_socket.h
index 8db7c68b5..6893fb1c2 100644
--- a/drivers/pcmcia/pci_socket.h
+++ b/drivers/pcmcia/pci_socket.h
@@ -8,6 +8,7 @@
#define __PCI_SOCKET_H
struct pci_socket_ops;
+struct socket_info_t;
typedef struct pci_socket {
struct pci_dev *dev;
@@ -19,6 +20,7 @@ typedef struct pci_socket {
socket_cap_t cap;
wait_queue_head_t wait;
unsigned int events;
+ struct socket_info_t *pcmcia_socket;
/* A few words of private data for the low-level driver.. */
unsigned int private[8];