icp_multi.h revision 0a85b6f0ab0d2edb0d41b32697111ce0e4f43496
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;
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 */
114static 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 */
129static 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 */
149static 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 */
177static 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 */
202static 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 */
216static 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 */
238static 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 */
258static 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
302