diff options
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r-- | drivers/pcmcia/cs.c | 214 | ||||
-rw-r--r-- | drivers/pcmcia/cs_internal.h | 1 | ||||
-rw-r--r-- | drivers/pcmcia/pci_socket.c | 92 | ||||
-rw-r--r-- | drivers/pcmcia/pci_socket.h | 2 |
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, ¥ta_operations); - nr++; + int s; + + for (s = 0; s < MAX_SOCKETS; s++) { + if (pci_socket_array [s].dev == 0) { + add_pci_socket (s, dev, ¥ta_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]; |