1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47#include "../comedidev.h"
48
49#include "comedi_pci.h"
50
51#define PC263_DRIVER_NAME "amplc_pc263"
52
53
54#define PCI_VENDOR_ID_AMPLICON 0x14dc
55#define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c
56#define PCI_DEVICE_ID_INVALID 0xffff
57
58
59#define PC263_IO_SIZE 2
60
61
62
63
64
65enum pc263_bustype { isa_bustype, pci_bustype };
66enum pc263_model { pc263_model, pci263_model, anypci_model };
67
68struct pc263_board {
69 const char *name;
70 const char *fancy_name;
71 unsigned short devid;
72 enum pc263_bustype bustype;
73 enum pc263_model model;
74};
75static const struct pc263_board pc263_boards[] = {
76 {
77 .name = "pc263",
78 .fancy_name = "PC263",
79 .bustype = isa_bustype,
80 .model = pc263_model,
81 },
82#ifdef CONFIG_COMEDI_PCI
83 {
84 .name = "pci263",
85 .fancy_name = "PCI263",
86 .devid = PCI_DEVICE_ID_AMPLICON_PCI263,
87 .bustype = pci_bustype,
88 .model = pci263_model,
89 },
90#endif
91#ifdef CONFIG_COMEDI_PCI
92 {
93 .name = PC263_DRIVER_NAME,
94 .fancy_name = PC263_DRIVER_NAME,
95 .devid = PCI_DEVICE_ID_INVALID,
96 .bustype = pci_bustype,
97 .model = anypci_model,
98 },
99#endif
100};
101
102#ifdef CONFIG_COMEDI_PCI
103static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = {
104 {
105 PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263,
106 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
107 0}
108};
109
110MODULE_DEVICE_TABLE(pci, pc263_pci_table);
111#endif
112
113
114
115
116#define thisboard ((const struct pc263_board *)dev->board_ptr)
117
118
119
120
121#ifdef CONFIG_COMEDI_PCI
122struct pc263_private {
123
124 struct pci_dev *pci_dev;
125};
126
127#define devpriv ((struct pc263_private *)dev->private)
128#endif
129
130
131
132
133
134
135
136static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it);
137static int pc263_detach(struct comedi_device *dev);
138static struct comedi_driver driver_amplc_pc263 = {
139 .driver_name = PC263_DRIVER_NAME,
140 .module = THIS_MODULE,
141 .attach = pc263_attach,
142 .detach = pc263_detach,
143 .board_name = &pc263_boards[0].name,
144 .offset = sizeof(struct pc263_board),
145 .num_names = ARRAY_SIZE(pc263_boards),
146};
147
148static int pc263_request_region(unsigned minor, unsigned long from,
149 unsigned long extent);
150static int pc263_dio_insn_bits(struct comedi_device *dev,
151 struct comedi_subdevice *s,
152 struct comedi_insn *insn, unsigned int *data);
153static int pc263_dio_insn_config(struct comedi_device *dev,
154 struct comedi_subdevice *s,
155 struct comedi_insn *insn, unsigned int *data);
156
157
158
159
160
161#ifdef CONFIG_COMEDI_PCI
162static int
163pc263_find_pci(struct comedi_device *dev, int bus, int slot,
164 struct pci_dev **pci_dev_p)
165{
166 struct pci_dev *pci_dev = NULL;
167
168 *pci_dev_p = NULL;
169
170
171 for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
172 pci_dev != NULL;
173 pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
174 PCI_ANY_ID, pci_dev)) {
175
176 if (bus || slot) {
177 if (bus != pci_dev->bus->number
178 || slot != PCI_SLOT(pci_dev->devfn))
179 continue;
180 }
181 if (thisboard->model == anypci_model) {
182
183 int i;
184
185 for (i = 0; i < ARRAY_SIZE(pc263_boards); i++) {
186 if (pc263_boards[i].bustype != pci_bustype)
187 continue;
188 if (pci_dev->device == pc263_boards[i].devid) {
189
190 dev->board_ptr = &pc263_boards[i];
191 break;
192 }
193 }
194 if (i == ARRAY_SIZE(pc263_boards))
195 continue;
196 } else {
197
198 if (pci_dev->device != thisboard->devid)
199 continue;
200 }
201
202
203 *pci_dev_p = pci_dev;
204 return 0;
205 }
206
207 if (bus || slot) {
208 printk(KERN_ERR
209 "comedi%d: error! no %s found at pci %02x:%02x!\n",
210 dev->minor, thisboard->name, bus, slot);
211 } else {
212 printk(KERN_ERR "comedi%d: error! no %s found!\n",
213 dev->minor, thisboard->name);
214 }
215 return -EIO;
216}
217#endif
218
219
220
221
222
223
224
225static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
226{
227 struct comedi_subdevice *s;
228 unsigned long iobase = 0;
229#ifdef CONFIG_COMEDI_PCI
230 struct pci_dev *pci_dev = NULL;
231 int bus = 0, slot = 0;
232#endif
233 int ret;
234
235 printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
236 PC263_DRIVER_NAME);
237
238
239
240
241#ifdef CONFIG_COMEDI_PCI
242 ret = alloc_private(dev, sizeof(struct pc263_private));
243 if (ret < 0) {
244 printk(KERN_ERR "comedi%d: error! out of memory!\n",
245 dev->minor);
246 return ret;
247 }
248#endif
249
250 switch (thisboard->bustype) {
251 case isa_bustype:
252 iobase = it->options[0];
253 break;
254#ifdef CONFIG_COMEDI_PCI
255 case pci_bustype:
256 bus = it->options[0];
257 slot = it->options[1];
258
259 ret = pc263_find_pci(dev, bus, slot, &pci_dev);
260 if (ret < 0)
261 return ret;
262 devpriv->pci_dev = pci_dev;
263 break;
264#endif
265 default:
266 printk(KERN_ERR
267 "comedi%d: %s: BUG! cannot determine board type!\n",
268 dev->minor, PC263_DRIVER_NAME);
269 return -EINVAL;
270 break;
271 }
272
273
274
275
276 dev->board_name = thisboard->name;
277
278
279#ifdef CONFIG_COMEDI_PCI
280 if (pci_dev) {
281 ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME);
282 if (ret < 0) {
283 printk(KERN_ERR
284 "comedi%d: error! cannot enable PCI device and request regions!\n",
285 dev->minor);
286 return ret;
287 }
288 iobase = pci_resource_start(pci_dev, 2);
289 } else
290#endif
291 {
292 ret = pc263_request_region(dev->minor, iobase, PC263_IO_SIZE);
293 if (ret < 0) {
294 return ret;
295 }
296 }
297 dev->iobase = iobase;
298
299
300
301
302
303 ret = alloc_subdevices(dev, 1);
304 if (ret < 0) {
305 printk(KERN_ERR "comedi%d: error! out of memory!\n",
306 dev->minor);
307 return ret;
308 }
309
310 s = dev->subdevices + 0;
311
312 s->type = COMEDI_SUBD_DIO;
313 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
314 s->n_chan = 16;
315 s->maxdata = 1;
316 s->range_table = &range_digital;
317 s->insn_bits = pc263_dio_insn_bits;
318 s->insn_config = pc263_dio_insn_config;
319
320 s->io_bits = 0xffff;
321
322 s->state = inb(dev->iobase);
323 s->state = s->state | (inb(dev->iobase) << 8);
324
325 printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
326 if (thisboard->bustype == isa_bustype) {
327 printk("(base %#lx) ", iobase);
328 } else {
329#ifdef CONFIG_COMEDI_PCI
330 printk("(pci %s) ", pci_name(pci_dev));
331#endif
332 }
333
334 printk("attached\n");
335
336 return 1;
337}
338
339
340
341
342
343
344
345
346
347static int pc263_detach(struct comedi_device *dev)
348{
349 printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
350 PC263_DRIVER_NAME);
351
352#ifdef CONFIG_COMEDI_PCI
353 if (devpriv)
354#endif
355 {
356#ifdef CONFIG_COMEDI_PCI
357 if (devpriv->pci_dev) {
358 if (dev->iobase) {
359 comedi_pci_disable(devpriv->pci_dev);
360 }
361 pci_dev_put(devpriv->pci_dev);
362 } else
363#endif
364 {
365 if (dev->iobase) {
366 release_region(dev->iobase, PC263_IO_SIZE);
367 }
368 }
369 }
370 if (dev->board_name) {
371 printk(KERN_INFO "comedi%d: %s removed\n",
372 dev->minor, dev->board_name);
373 }
374 return 0;
375}
376
377
378
379
380
381static int pc263_request_region(unsigned minor, unsigned long from,
382 unsigned long extent)
383{
384 if (!from || !request_region(from, extent, PC263_DRIVER_NAME)) {
385 printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
386 minor, from, extent);
387 return -EIO;
388 }
389 return 0;
390}
391
392
393
394
395
396
397static int pc263_dio_insn_bits(struct comedi_device *dev,
398 struct comedi_subdevice *s,
399 struct comedi_insn *insn, unsigned int *data)
400{
401 if (insn->n != 2)
402 return -EINVAL;
403
404
405
406 if (data[0]) {
407 s->state &= ~data[0];
408 s->state |= data[0] & data[1];
409
410 outb(s->state & 0xFF, dev->iobase);
411 outb(s->state >> 8, dev->iobase + 1);
412 }
413
414
415
416
417
418 data[1] = s->state;
419
420 return 2;
421}
422
423static int pc263_dio_insn_config(struct comedi_device *dev,
424 struct comedi_subdevice *s,
425 struct comedi_insn *insn, unsigned int *data)
426{
427 if (insn->n != 1)
428 return -EINVAL;
429 return 1;
430}
431
432
433
434
435
436#ifdef CONFIG_COMEDI_PCI
437COMEDI_PCI_INITCLEANUP(driver_amplc_pc263, pc263_pci_table);
438#else
439COMEDI_INITCLEANUP(driver_amplc_pc263);
440#endif
441