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