/* * Generic PCI pccard driver interface. * * (C) Copyright 1999 Linus Torvalds * * This implements the common parts of PCI pccard drivers, * notably detection and infrastructure conversion (ie change * from socket index to "struct pci_dev" etc) * * This does NOT implement the actual low-level driver details, * and this has on purpose been left generic enough that it can * be used to set up a PCI PCMCIA controller (ie non-cardbus), * or to set up a controller. * * See for example the "yenta" driver for PCI cardbus controllers * conforming to the yenta cardbus specifications. */ #include #include #include #include #include #include #include #include "pci_socket.h" /* * Arbitrary define. This is the array of active cardbus * entries. */ #define MAX_SOCKETS (8) static pci_socket_t pci_socket_array[MAX_SOCKETS]; static int pci_init_socket(unsigned int sock) { pci_socket_t *socket = pci_socket_array + sock; if (socket->op && socket->op->init) return socket->op->init(socket); return -EINVAL; } static int pci_suspend_socket(unsigned int sock) { pci_socket_t *socket = pci_socket_array + sock; if (socket->op && socket->op->suspend) return socket->op->suspend(socket); return -EINVAL; } static int pci_register_callback(unsigned int sock, void (*handler)(void *, unsigned int), void * info) { pci_socket_t *socket = pci_socket_array + sock; socket->handler = handler; socket->info = info; if (handler) MOD_INC_USE_COUNT; else MOD_DEC_USE_COUNT; return 0; } static int pci_inquire_socket(unsigned int sock, socket_cap_t *cap) { pci_socket_t *socket = pci_socket_array + sock; *cap = socket->cap; return 0; } static int pci_get_status(unsigned int sock, unsigned int *value) { pci_socket_t *socket = pci_socket_array + sock; if (socket->op && socket->op->get_status) return socket->op->get_status(socket, value); *value = 0; return -EINVAL; } static int pci_get_socket(unsigned int sock, socket_state_t *state) { pci_socket_t *socket = pci_socket_array + sock; if (socket->op && socket->op->get_socket) return socket->op->get_socket(socket, state); return -EINVAL; } static int pci_set_socket(unsigned int sock, socket_state_t *state) { pci_socket_t *socket = pci_socket_array + sock; if (socket->op && socket->op->set_socket) return socket->op->set_socket(socket, state); return -EINVAL; } static int pci_get_io_map(unsigned int sock, struct pccard_io_map *io) { pci_socket_t *socket = pci_socket_array + sock; if (socket->op && socket->op->get_io_map) return socket->op->get_io_map(socket, io); return -EINVAL; } static int pci_set_io_map(unsigned int sock, struct pccard_io_map *io) { pci_socket_t *socket = pci_socket_array + sock; if (socket->op && socket->op->set_io_map) return socket->op->set_io_map(socket, io); return -EINVAL; } static int pci_get_mem_map(unsigned int sock, struct pccard_mem_map *mem) { pci_socket_t *socket = pci_socket_array + sock; if (socket->op && socket->op->get_mem_map) return socket->op->get_mem_map(socket, mem); return -EINVAL; } static int pci_set_mem_map(unsigned int sock, struct pccard_mem_map *mem) { pci_socket_t *socket = pci_socket_array + sock; if (socket->op && socket->op->set_mem_map) return socket->op->set_mem_map(socket, mem); return -EINVAL; } static void pci_proc_setup(unsigned int sock, struct proc_dir_entry *base) { pci_socket_t *socket = pci_socket_array + sock; if (socket->op && socket->op->proc_setup) socket->op->proc_setup(socket, base); } static struct pccard_operations pci_socket_operations = { pci_init_socket, pci_suspend_socket, pci_register_callback, pci_inquire_socket, pci_get_status, pci_get_socket, pci_set_socket, pci_get_io_map, pci_set_io_map, pci_get_mem_map, pci_set_mem_map, pci_proc_setup }; static int __init 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; init_waitqueue_head(&socket->wait); return socket->op->open(socket); } static int __init pci_socket_init(void) { 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++; } if (nr <= 0) return -1; register_ss_entry(nr, &pci_socket_operations); return 0; } static void __exit pci_socket_exit(void) { int i; 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); } } module_init(pci_socket_init); module_exit(pci_socket_exit);