icp_multi.h revision 51b713a684d403bd672b3e4cac55db43dc5cca2d
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, unsigned short device_id);
40static 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);
43static 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
47static int pci_card_alloc(struct pcilst_struct *amcc);
48static int pci_card_free(struct pcilst_struct *amcc);
49static void pci_card_list_display(void);
50static 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 */
57static 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 */
107static 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 */
122static 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 */
140static 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 */
166static 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 */
191static 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 */
205static 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 */
221static 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 */
240static 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
282