| /* |
| 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 = kzalloc(sizeof(*inova), GFP_KERNEL); |
| if (!inova) { |
| printk |
| ("icp_multi: pci_card_list_init: allocation failed\n"); |
| pci_dev_put(pcidev); |
| break; |
| } |
| |
| 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) { |
| printk(" - BUG!! inova is NULL!\n"); |
| return -1; |
| } |
| |
| if (inova->used) |
| return 1; |
| if (comedi_pci_enable(inova->pcidev, "icp_multi")) { |
| 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 */ |
| |
| card = find_free_pci_card_by_device(vendor_id, device_id); |
| if (card == NULL) { |
| 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: |
| printk |
| (" - Card not found on requested position b:s %d:%d!\n", |
| pci_bus, pci_slot); |
| return NULL; |
| case 2: |
| printk |
| (" - Card on requested position is used b:s %d:%d!\n", |
| pci_bus, pci_slot); |
| return NULL; |
| } |
| } |
| |
| err = pci_card_alloc(card); |
| if (err != 0) { |
| if (err > 0) |
| printk(" - Can't allocate card!\n"); |
| /* else: error already printed. */ |
| return NULL; |
| } |
| |
| return card; |
| } |
| |
| #endif |