aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/drivers/icp_multi.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi/drivers/icp_multi.h')
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.h278
1 files changed, 278 insertions, 0 deletions
diff --git a/drivers/staging/comedi/drivers/icp_multi.h b/drivers/staging/comedi/drivers/icp_multi.h
new file mode 100644
index 000000000000..6df4a8d15ff2
--- /dev/null
+++ b/drivers/staging/comedi/drivers/icp_multi.h
@@ -0,0 +1,278 @@
+/*
+ comedi/drivers/icp_multi.h
+
+ Stuff for ICP Multi
+
+ Author: Anne Smorthit <anne.smorthit@sfwte.ch>
+
+*/
+
+#ifndef _ICP_MULTI_H_
+#define _ICP_MULTI_H_
+
+#include "../comedidev.h"
+#include "comedi_pci.h"
+
+/****************************************************************************/
+
+struct pcilst_struct {
+ struct pcilst_struct *next;
+ int used;
+ struct pci_dev *pcidev;
+ unsigned short vendor;
+ unsigned short device;
+ unsigned char pci_bus;
+ unsigned char pci_slot;
+ unsigned char pci_func;
+ resource_size_t io_addr[5];
+ unsigned int irq;
+};
+
+struct pcilst_struct *inova_devices; // ptr to root list of all Inova devices
+
+/****************************************************************************/
+
+static void pci_card_list_init(unsigned short pci_vendor, char display);
+static void pci_card_list_cleanup(unsigned short pci_vendor);
+static struct pcilst_struct *find_free_pci_card_by_device(unsigned short
+ vendor_id, unsigned short device_id);
+static int find_free_pci_card_by_position(unsigned short vendor_id,
+ unsigned short device_id, unsigned short pci_bus,
+ unsigned short pci_slot, struct pcilst_struct **card);
+static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id,
+ unsigned short device_id, unsigned short pci_bus,
+ unsigned short pci_slot);
+
+static int pci_card_alloc(struct pcilst_struct *amcc);
+static int pci_card_free(struct pcilst_struct *amcc);
+static void pci_card_list_display(void);
+static int pci_card_data(struct pcilst_struct *amcc,
+ unsigned char *pci_bus, unsigned char *pci_slot,
+ unsigned char *pci_func, resource_size_t * io_addr, unsigned int *irq);
+
+/****************************************************************************/
+
+/* build list of Inova cards in this system */
+static void pci_card_list_init(unsigned short pci_vendor, char display)
+{
+ struct pci_dev *pcidev;
+ struct pcilst_struct *inova, *last;
+ int i;
+
+ inova_devices = NULL;
+ last = NULL;
+
+ for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
+ pcidev != NULL;
+ pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
+ if (pcidev->vendor == pci_vendor) {
+ inova = kmalloc(sizeof(*inova), GFP_KERNEL);
+ if (!inova) {
+ printk("icp_multi: pci_card_list_init: allocation failed\n");
+ pci_dev_put(pcidev);
+ break;
+ }
+ memset(inova, 0, sizeof(*inova));
+
+ inova->pcidev = pci_dev_get(pcidev);
+ if (last) {
+ last->next = inova;
+ } else {
+ inova_devices = inova;
+ }
+ last = inova;
+
+ inova->vendor = pcidev->vendor;
+ inova->device = pcidev->device;
+ inova->pci_bus = pcidev->bus->number;
+ inova->pci_slot = PCI_SLOT(pcidev->devfn);
+ inova->pci_func = PCI_FUNC(pcidev->devfn);
+ /* Note: resources may be invalid if PCI device
+ * not enabled, but they are corrected in
+ * pci_card_alloc. */
+ for (i = 0; i < 5; i++)
+ inova->io_addr[i] =
+ pci_resource_start(pcidev, i);
+ inova->irq = pcidev->irq;
+ }
+ }
+
+ if (display)
+ pci_card_list_display();
+}
+
+/****************************************************************************/
+/* free up list of amcc cards in this system */
+static void pci_card_list_cleanup(unsigned short pci_vendor)
+{
+ struct pcilst_struct *inova, *next;
+
+ for (inova = inova_devices; inova; inova = next) {
+ next = inova->next;
+ pci_dev_put(inova->pcidev);
+ kfree(inova);
+ }
+
+ inova_devices = NULL;
+}
+
+/****************************************************************************/
+/* find first unused card with this device_id */
+static struct pcilst_struct *find_free_pci_card_by_device(unsigned short
+ vendor_id, unsigned short device_id)
+{
+ struct pcilst_struct *inova, *next;
+
+ for (inova = inova_devices; inova; inova = next) {
+ next = inova->next;
+ if ((!inova->used) && (inova->device == device_id)
+ && (inova->vendor == vendor_id))
+ return inova;
+
+ }
+
+ return NULL;
+}
+
+/****************************************************************************/
+/* find card on requested position */
+static int find_free_pci_card_by_position(unsigned short vendor_id,
+ unsigned short device_id, unsigned short pci_bus,
+ unsigned short pci_slot, struct pcilst_struct **card)
+{
+ struct pcilst_struct *inova, *next;
+
+ *card = NULL;
+ for (inova = inova_devices; inova; inova = next) {
+ next = inova->next;
+ if ((inova->vendor == vendor_id) && (inova->device == device_id)
+ && (inova->pci_bus == pci_bus)
+ && (inova->pci_slot == pci_slot)) {
+ if (!(inova->used)) {
+ *card = inova;
+ return 0; // ok, card is found
+ } else {
+ return 2; // card exist but is used
+ }
+ }
+ }
+
+ return 1; // no card found
+}
+
+/****************************************************************************/
+/* mark card as used */
+static int pci_card_alloc(struct pcilst_struct *inova)
+{
+ int i;
+
+ if (!inova) {
+ rt_printk(" - BUG!! inova is NULL!\n");
+ return -1;
+ }
+
+ if (inova->used)
+ return 1;
+ if (comedi_pci_enable(inova->pcidev, "icp_multi")) {
+ rt_printk(" - Can't enable PCI device and request regions!\n");
+ return -1;
+ }
+ /* Resources will be accurate now. */
+ for (i = 0; i < 5; i++)
+ inova->io_addr[i] = pci_resource_start(inova->pcidev, i);
+ inova->irq = inova->pcidev->irq;
+ inova->used = 1;
+ return 0;
+}
+
+/****************************************************************************/
+/* mark card as free */
+static int pci_card_free(struct pcilst_struct *inova)
+{
+ if (!inova)
+ return -1;
+
+ if (!inova->used)
+ return 1;
+ inova->used = 0;
+ comedi_pci_disable(inova->pcidev);
+ return 0;
+}
+
+/****************************************************************************/
+/* display list of found cards */
+static void pci_card_list_display(void)
+{
+ struct pcilst_struct *inova, *next;
+
+ printk("Anne's List of pci cards\n");
+ printk("bus:slot:func vendor device io_inova io_daq irq used\n");
+
+ for (inova = inova_devices; inova; inova = next) {
+ next = inova->next;
+ printk("%2d %2d %2d 0x%4x 0x%4x 0x%8llx 0x%8llx %2u %2d\n", inova->pci_bus, inova->pci_slot, inova->pci_func, inova->vendor, inova->device, (unsigned long long)inova->io_addr[0], (unsigned long long)inova->io_addr[2], inova->irq, inova->used);
+
+ }
+}
+
+/****************************************************************************/
+/* return all card information for driver */
+static int pci_card_data(struct pcilst_struct *inova,
+ unsigned char *pci_bus, unsigned char *pci_slot,
+ unsigned char *pci_func, resource_size_t * io_addr, unsigned int *irq)
+{
+ int i;
+
+ if (!inova)
+ return -1;
+ *pci_bus = inova->pci_bus;
+ *pci_slot = inova->pci_slot;
+ *pci_func = inova->pci_func;
+ for (i = 0; i < 5; i++)
+ io_addr[i] = inova->io_addr[i];
+ *irq = inova->irq;
+ return 0;
+}
+
+/****************************************************************************/
+/* select and alloc card */
+static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id,
+ unsigned short device_id, unsigned short pci_bus,
+ unsigned short pci_slot)
+{
+ struct pcilst_struct *card;
+ int err;
+
+ if ((pci_bus < 1) & (pci_slot < 1)) { // use autodetection
+ if ((card = find_free_pci_card_by_device(vendor_id,
+ device_id)) == NULL) {
+ rt_printk(" - Unused card not found in system!\n");
+ return NULL;
+ }
+ } else {
+ switch (find_free_pci_card_by_position(vendor_id, device_id,
+ pci_bus, pci_slot, &card)) {
+ case 1:
+ rt_printk
+ (" - Card not found on requested position b:s %d:%d!\n",
+ pci_bus, pci_slot);
+ return NULL;
+ case 2:
+ rt_printk
+ (" - Card on requested position is used b:s %d:%d!\n",
+ pci_bus, pci_slot);
+ return NULL;
+ }
+ }
+
+ if ((err = pci_card_alloc(card)) != 0) {
+ if (err > 0)
+ rt_printk(" - Can't allocate card!\n");
+ /* else: error already printed. */
+ return NULL;
+ }
+
+ return card;
+}
+
+#endif