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