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