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 
18 struct 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 
31 struct pcilst_struct *inova_devices;
32 /* ptr to root list of all Inova devices */
33 
34 /****************************************************************************/
35 
36 static void pci_card_list_init(unsigned short pci_vendor, char display);
37 static void pci_card_list_cleanup(unsigned short pci_vendor);
38 static struct pcilst_struct *find_free_pci_card_by_device(unsigned short
39 							  vendor_id,
40 							  unsigned short
41 							  device_id);
42 static 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);
47 static 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 
52 static int pci_card_alloc(struct pcilst_struct *amcc);
53 static int pci_card_free(struct pcilst_struct *amcc);
54 static void pci_card_list_display(void);
55 static 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 */
pci_card_list_init(unsigned short pci_vendor,char display)63 static 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 */
pci_card_list_cleanup(unsigned short pci_vendor)111 static 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 */
find_free_pci_card_by_device(unsigned short vendor_id,unsigned short device_id)126 static 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 */
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)146 static 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 */
pci_card_alloc(struct pcilst_struct * inova)174 static 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 */
pci_card_free(struct pcilst_struct * inova)199 static 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 */
pci_card_list_display(void)213 static 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 */
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)235 static 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 */
select_and_alloc_pci_card(unsigned short vendor_id,unsigned short device_id,unsigned short pci_bus,unsigned short pci_slot)255 static 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