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