1/* 2 comedi/drivers/icp_multi.h 3 4 Stuff for ICP Multi 5 6 Author: Anne Smorthit <anne.smorthit@sfwte.ch> 7 8*/ 9 10#ifndef _ICP_MULTI_H_ 11#define _ICP_MULTI_H_ 12 13#include "../comedidev.h" 14#include "comedi_pci.h" 15 16/****************************************************************************/ 17 18struct pcilst_struct { 19 struct pcilst_struct *next; 20 int used; 21 struct pci_dev *pcidev; 22 unsigned short vendor; 23 unsigned short device; 24 unsigned char pci_bus; 25 unsigned char pci_slot; 26 unsigned char pci_func; 27 resource_size_t io_addr[5]; 28 unsigned int irq; 29}; 30 31struct pcilst_struct *inova_devices; 32/* ptr to root list of all Inova devices */ 33 34/****************************************************************************/ 35 36static void pci_card_list_init(unsigned short pci_vendor, char display); 37static void pci_card_list_cleanup(unsigned short pci_vendor); 38static struct pcilst_struct *find_free_pci_card_by_device(unsigned short 39 vendor_id, 40 unsigned short 41 device_id); 42static int find_free_pci_card_by_position(unsigned short vendor_id, 43 unsigned short device_id, 44 unsigned short pci_bus, 45 unsigned short pci_slot, 46 struct pcilst_struct **card); 47static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id, 48 unsigned short device_id, 49 unsigned short pci_bus, 50 unsigned short pci_slot); 51 52static int pci_card_alloc(struct pcilst_struct *amcc); 53static int pci_card_free(struct pcilst_struct *amcc); 54static void pci_card_list_display(void); 55static int pci_card_data(struct pcilst_struct *amcc, 56 unsigned char *pci_bus, unsigned char *pci_slot, 57 unsigned char *pci_func, resource_size_t * io_addr, 58 unsigned int *irq); 59 60/****************************************************************************/ 61 62/* build list of Inova cards in this system */ 63static void pci_card_list_init(unsigned short pci_vendor, char display) 64{ 65 struct pci_dev *pcidev = NULL; 66 struct pcilst_struct *inova, *last; 67 int i; 68 69 inova_devices = NULL; 70 last = NULL; 71 72 for_each_pci_dev(pcidev) { 73 if (pcidev->vendor == pci_vendor) { 74 inova = kzalloc(sizeof(*inova), GFP_KERNEL); 75 if (!inova) { 76 printk 77 ("icp_multi: pci_card_list_init: allocation failed\n"); 78 pci_dev_put(pcidev); 79 break; 80 } 81 82 inova->pcidev = pci_dev_get(pcidev); 83 if (last) { 84 last->next = inova; 85 } else { 86 inova_devices = inova; 87 } 88 last = inova; 89 90 inova->vendor = pcidev->vendor; 91 inova->device = pcidev->device; 92 inova->pci_bus = pcidev->bus->number; 93 inova->pci_slot = PCI_SLOT(pcidev->devfn); 94 inova->pci_func = PCI_FUNC(pcidev->devfn); 95 /* Note: resources may be invalid if PCI device 96 * not enabled, but they are corrected in 97 * pci_card_alloc. */ 98 for (i = 0; i < 5; i++) 99 inova->io_addr[i] = 100 pci_resource_start(pcidev, i); 101 inova->irq = pcidev->irq; 102 } 103 } 104 105 if (display) 106 pci_card_list_display(); 107} 108 109/****************************************************************************/ 110/* free up list of amcc cards in this system */ 111static void pci_card_list_cleanup(unsigned short pci_vendor) 112{ 113 struct pcilst_struct *inova, *next; 114 115 for (inova = inova_devices; inova; inova = next) { 116 next = inova->next; 117 pci_dev_put(inova->pcidev); 118 kfree(inova); 119 } 120 121 inova_devices = NULL; 122} 123 124/****************************************************************************/ 125/* find first unused card with this device_id */ 126static struct pcilst_struct *find_free_pci_card_by_device(unsigned short 127 vendor_id, 128 unsigned short 129 device_id) 130{ 131 struct pcilst_struct *inova, *next; 132 133 for (inova = inova_devices; inova; inova = next) { 134 next = inova->next; 135 if ((!inova->used) && (inova->device == device_id) 136 && (inova->vendor == vendor_id)) 137 return inova; 138 139 } 140 141 return NULL; 142} 143 144/****************************************************************************/ 145/* find card on requested position */ 146static int find_free_pci_card_by_position(unsigned short vendor_id, 147 unsigned short device_id, 148 unsigned short pci_bus, 149 unsigned short pci_slot, 150 struct pcilst_struct **card) 151{ 152 struct pcilst_struct *inova, *next; 153 154 *card = NULL; 155 for (inova = inova_devices; inova; inova = next) { 156 next = inova->next; 157 if ((inova->vendor == vendor_id) && (inova->device == device_id) 158 && (inova->pci_bus == pci_bus) 159 && (inova->pci_slot == pci_slot)) { 160 if (!(inova->used)) { 161 *card = inova; 162 return 0; /* ok, card is found */ 163 } else { 164 return 2; /* card exist but is used */ 165 } 166 } 167 } 168 169 return 1; /* no card found */ 170} 171 172/****************************************************************************/ 173/* mark card as used */ 174static int pci_card_alloc(struct pcilst_struct *inova) 175{ 176 int i; 177 178 if (!inova) { 179 printk(" - BUG!! inova is NULL!\n"); 180 return -1; 181 } 182 183 if (inova->used) 184 return 1; 185 if (comedi_pci_enable(inova->pcidev, "icp_multi")) { 186 printk(" - Can't enable PCI device and request regions!\n"); 187 return -1; 188 } 189 /* Resources will be accurate now. */ 190 for (i = 0; i < 5; i++) 191 inova->io_addr[i] = pci_resource_start(inova->pcidev, i); 192 inova->irq = inova->pcidev->irq; 193 inova->used = 1; 194 return 0; 195} 196 197/****************************************************************************/ 198/* mark card as free */ 199static int pci_card_free(struct pcilst_struct *inova) 200{ 201 if (!inova) 202 return -1; 203 204 if (!inova->used) 205 return 1; 206 inova->used = 0; 207 comedi_pci_disable(inova->pcidev); 208 return 0; 209} 210 211/****************************************************************************/ 212/* display list of found cards */ 213static void pci_card_list_display(void) 214{ 215 struct pcilst_struct *inova, *next; 216 217 printk("Anne's List of pci cards\n"); 218 printk("bus:slot:func vendor device io_inova io_daq irq used\n"); 219 220 for (inova = inova_devices; inova; inova = next) { 221 next = inova->next; 222 printk 223 ("%2d %2d %2d 0x%4x 0x%4x 0x%8llx 0x%8llx %2u %2d\n", 224 inova->pci_bus, inova->pci_slot, inova->pci_func, 225 inova->vendor, inova->device, 226 (unsigned long long)inova->io_addr[0], 227 (unsigned long long)inova->io_addr[2], inova->irq, 228 inova->used); 229 230 } 231} 232 233/****************************************************************************/ 234/* return all card information for driver */ 235static int pci_card_data(struct pcilst_struct *inova, 236 unsigned char *pci_bus, unsigned char *pci_slot, 237 unsigned char *pci_func, resource_size_t * io_addr, 238 unsigned int *irq) 239{ 240 int i; 241 242 if (!inova) 243 return -1; 244 *pci_bus = inova->pci_bus; 245 *pci_slot = inova->pci_slot; 246 *pci_func = inova->pci_func; 247 for (i = 0; i < 5; i++) 248 io_addr[i] = inova->io_addr[i]; 249 *irq = inova->irq; 250 return 0; 251} 252 253/****************************************************************************/ 254/* select and alloc card */ 255static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id, 256 unsigned short device_id, 257 unsigned short pci_bus, 258 unsigned short pci_slot) 259{ 260 struct pcilst_struct *card; 261 int err; 262 263 if ((pci_bus < 1) & (pci_slot < 1)) { /* use autodetection */ 264 265 card = find_free_pci_card_by_device(vendor_id, device_id); 266 if (card == NULL) { 267 printk(" - Unused card not found in system!\n"); 268 return NULL; 269 } 270 } else { 271 switch (find_free_pci_card_by_position(vendor_id, device_id, 272 pci_bus, pci_slot, 273 &card)) { 274 case 1: 275 printk 276 (" - Card not found on requested position b:s %d:%d!\n", 277 pci_bus, pci_slot); 278 return NULL; 279 case 2: 280 printk 281 (" - Card on requested position is used b:s %d:%d!\n", 282 pci_bus, pci_slot); 283 return NULL; 284 } 285 } 286 287 err = pci_card_alloc(card); 288 if (err != 0) { 289 if (err > 0) 290 printk(" - Can't allocate card!\n"); 291 /* else: error already printed. */ 292 return NULL; 293 } 294 295 return card; 296} 297 298#endif 299