Staging: comedi: fix line over 80 character issue in usbduxfast.c
[deliverable/linux.git] / drivers / staging / comedi / drivers / pcmmio.c
CommitLineData
6baef150
CC
1/*
2 comedi/drivers/pcmmio.c
3 Driver for Winsystems PC-104 based multifunction IO board.
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2007 Calin A. Culianu <calin@ajvar.org>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22/*
23Driver: pcmmio
24Description: A driver for the PCM-MIO multifunction board
25Devices: [Winsystems] PCM-MIO (pcmmio)
26Author: Calin Culianu <calin@ajvar.org>
27Updated: Wed, May 16 2007 16:21:10 -0500
28Status: works
29
30A driver for the relatively new PCM-MIO multifunction board from
31Winsystems. This board is a PC-104 based I/O board. It contains
32four subdevices:
33 subdevice 0 - 16 channels of 16-bit AI
34 subdevice 1 - 8 channels of 16-bit AO
d2d08955
DPJ
35 subdevice 2 - first 24 channels of the 48 channel of DIO
36 (with edge-triggered interrupt support)
37 subdevice 3 - last 24 channels of the 48 channel DIO
38 (no interrupt support for this bank of channels)
6baef150
CC
39
40 Some notes:
41
42 Synchronous reads and writes are the only things implemented for AI and AO,
43 even though the hardware itself can do streaming acquisition, etc. Anyone
44 want to add asynchronous I/O for AI/AO as a feature? Be my guest...
45
46 Asynchronous I/O for the DIO subdevices *is* implemented, however! They are
47 basically edge-triggered interrupts for any configuration of the first
48 24 DIO-lines.
49
50 Also note that this interrupt support is untested.
51
52 A few words about edge-detection IRQ support (commands on DIO):
53
54 * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
55 of the board to the comedi_config command. The board IRQ is not jumpered
56 but rather configured through software, so any IRQ from 1-15 is OK.
57
58 * Due to the genericity of the comedi API, you need to create a special
59 comedi_command in order to use edge-triggered interrupts for DIO.
60
61 * Use comedi_commands with TRIG_NOW. Your callback will be called each
62 time an edge is detected on the specified DIO line(s), and the data
63 values will be two sample_t's, which should be concatenated to form
64 one 32-bit unsigned int. This value is the mask of channels that had
65 edges detected from your channel list. Note that the bits positions
66 in the mask correspond to positions in your chanlist when you
67 specified the command and *not* channel id's!
68
69 * To set the polarity of the edge-detection interrupts pass a nonzero value
70 for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
71 value for both CR_RANGE and CR_AREF if you want edge-down polarity.
72
73Configuration Options:
74 [0] - I/O port base address
d2d08955
DPJ
75 [1] - IRQ (optional -- for edge-detect interrupt support only,
76 leave out if you don't need this feature)
6baef150
CC
77*/
78
25436dc9 79#include <linux/interrupt.h>
5a0e3ad6 80#include <linux/slab.h>
6baef150 81#include "../comedidev.h"
0b8f754a 82#include "pcm_common.h"
6baef150
CC
83#include <linux/pci.h> /* for PCI devices */
84
6baef150
CC
85/* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
86#define CHANS_PER_PORT 8
87#define PORTS_PER_ASIC 6
88#define INTR_PORTS_PER_ASIC 3
89#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */
90#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
91#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
92#define INTR_CHANS_PER_ASIC 24
93#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
94#define MAX_DIO_CHANS (PORTS_PER_ASIC*1*CHANS_PER_PORT)
95#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC)
96#define SDEV_NO ((int)(s - dev->subdevices))
97#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
98/* IO Memory sizes */
99#define ASIC_IOSIZE (0x0B)
100#define PCMMIO48_IOSIZE ASIC_IOSIZE
101
102/* Some offsets - these are all in the 16byte IO memory offset from
103 the base address. Note that there is a paging scheme to swap out
104 offsets 0x8-0xA using the PAGELOCK register. See the table below.
105
106 Register(s) Pages R/W? Description
107 --------------------------------------------------------------
108 REG_PORTx All R/W Read/Write/Configure IO
109 REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int.
110 REG_PAGELOCK All WriteOnly Select a page
111 REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity
112 REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int.
113 REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints.
114 */
115#define REG_PORT0 0x0
116#define REG_PORT1 0x1
117#define REG_PORT2 0x2
118#define REG_PORT3 0x3
119#define REG_PORT4 0x4
120#define REG_PORT5 0x5
121#define REG_INT_PENDING 0x6
d2d08955
DPJ
122#define REG_PAGELOCK 0x7 /*
123 * page selector register, upper 2 bits select
124 * a page and bits 0-5 are used to 'lock down'
125 * a particular port above to make it readonly.
126 */
6baef150
CC
127#define REG_POL0 0x8
128#define REG_POL1 0x9
129#define REG_POL2 0xA
130#define REG_ENAB0 0x8
131#define REG_ENAB1 0x9
132#define REG_ENAB2 0xA
133#define REG_INT_ID0 0x8
134#define REG_INT_ID1 0x9
135#define REG_INT_ID2 0xA
136
137#define NUM_PAGED_REGS 3
138#define NUM_PAGES 4
139#define FIRST_PAGED_REG 0x8
140#define REG_PAGE_BITOFFSET 6
141#define REG_LOCK_BITOFFSET 0
142#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
d2d08955 143#define REG_LOCK_MASK (~(REG_PAGE_MASK))
6baef150
CC
144#define PAGE_POL 1
145#define PAGE_ENAB 2
146#define PAGE_INT_ID 3
147
6baef150
CC
148/*
149 * Board descriptions for two imaginary boards. Describing the
150 * boards in this way is optional, and completely driver-dependent.
151 * Some drivers use arrays such as this, other do not.
152 */
657f81ec 153struct pcmmio_board {
6baef150
CC
154 const char *name;
155 const int dio_num_asics;
156 const int dio_num_ports;
157 const int total_iosize;
158 const int ai_bits;
159 const int ao_bits;
160 const int n_ai_chans;
161 const int n_ao_chans;
9ced1de6 162 const struct comedi_lrange *ai_range_table, *ao_range_table;
56b8421c
AT
163 int (*ai_rinsn) (struct comedi_device *dev,
164 struct comedi_subdevice *s,
165 struct comedi_insn *insn,
166 unsigned int *data);
167 int (*ao_rinsn) (struct comedi_device *dev,
168 struct comedi_subdevice *s,
169 struct comedi_insn *insn,
170 unsigned int *data);
171 int (*ao_winsn) (struct comedi_device *dev,
172 struct comedi_subdevice *s,
173 struct comedi_insn *insn,
174 unsigned int *data);
657f81ec 175};
6baef150 176
d2d08955
DPJ
177static const struct comedi_lrange ranges_ai = {
178 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)}
6baef150
CC
179};
180
d2d08955
DPJ
181static const struct comedi_lrange ranges_ao = {
182 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
0a85b6f0 183 RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
6baef150
CC
184};
185
6baef150
CC
186/*
187 * Useful for shorthand access to the particular board structure
188 */
657f81ec 189#define thisboard ((const struct pcmmio_board *)dev->board_ptr)
6baef150
CC
190
191/* this structure is for data unique to this subdevice. */
4467df94 192struct pcmmio_subdev_private {
6baef150
CC
193
194 union {
d2d08955
DPJ
195 /* for DIO: mapping of halfwords (bytes)
196 in port/chanarray to iobase */
6baef150
CC
197 unsigned long iobases[PORTS_PER_SUBDEV];
198
199 /* for AI/AO */
200 unsigned long iobase;
201 };
202 union {
203 struct {
204
205 /* The below is only used for intr subdevices */
206 struct {
d2d08955
DPJ
207 /*
208 * if non-negative, this subdev has an
209 * interrupt asic
210 */
211 int asic;
212 /*
213 * if nonnegative, the first channel id for
214 * interrupts.
215 */
216 int first_chan;
217 /*
218 * the number of asic channels in this subdev
219 * that have interrutps
220 */
221 int num_asic_chans;
222 /*
223 * if nonnegative, the first channel id with
224 * respect to the asic that has interrupts
225 */
226 int asic_chan;
227 /*
228 * subdev-relative channel mask for channels
229 * we are interested in
230 */
231 int enabled_mask;
6baef150
CC
232 int active;
233 int stop_count;
234 int continuous;
235 spinlock_t spinlock;
236 } intr;
237 } dio;
238 struct {
d2d08955
DPJ
239 /* the last unsigned int data written */
240 unsigned int shadow_samples[8];
6baef150
CC
241 } ao;
242 };
4467df94 243};
6baef150 244
d2d08955
DPJ
245/*
246 * this structure is for data unique to this hardware driver. If
247 * several hardware drivers keep similar information in this structure,
248 * feel free to suggest moving the variable to the struct comedi_device struct.
249 */
e56ab715 250struct pcmmio_private {
6baef150
CC
251 /* stuff for DIO */
252 struct {
253 unsigned char pagelock; /* current page and lock */
d2d08955
DPJ
254 /* shadow of POLx registers */
255 unsigned char pol[NUM_PAGED_REGS];
256 /* shadow of ENABx registers */
257 unsigned char enab[NUM_PAGED_REGS];
6baef150
CC
258 int num;
259 unsigned long iobase;
260 unsigned int irq;
261 spinlock_t spinlock;
262 } asics[MAX_ASICS];
4467df94 263 struct pcmmio_subdev_private *sprivs;
e56ab715 264};
6baef150
CC
265
266/*
267 * most drivers define the following macro to make it easy to
268 * access the private structure.
269 */
e56ab715 270#define devpriv ((struct pcmmio_private *)dev->private)
4467df94 271#define subpriv ((struct pcmmio_subdev_private *)s->private)
6baef150
CC
272
273/* DIO devices are slightly special. Although it is possible to
274 * implement the insn_read/insn_write interface, it is much more
275 * useful to applications if you implement the insn_bits interface.
276 * This allows packed reading/writing of the DIO channels. The
277 * comedi core can convert between insn_bits and insn_read/write */
0a85b6f0
MT
278static int pcmmio_dio_insn_bits(struct comedi_device *dev,
279 struct comedi_subdevice *s,
280 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
281{
282 int byte_no;
283 if (insn->n != 2)
284 return -EINVAL;
285
286 /* NOTE:
287 reading a 0 means this channel was high
288 writine a 0 sets the channel high
289 reading a 1 means this channel was low
290 writing a 1 means set this channel low
291
292 Therefore everything is always inverted. */
293
294 /* The insn data is a mask in data[0] and the new data
295 * in data[1], each channel cooresponding to a bit. */
296
297#ifdef DAMMIT_ITS_BROKEN
298 /* DEBUG */
bcd9a1e9 299 printk(KERN_DEBUG "write mask: %08x data: %08x\n", data[0], data[1]);
6baef150
CC
300#endif
301
302 s->state = 0;
303
304 for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
305 /* address of 8-bit port */
306 unsigned long ioaddr = subpriv->iobases[byte_no],
0a85b6f0
MT
307 /* bit offset of port in 32-bit doubleword */
308 offset = byte_no * 8;
6baef150
CC
309 /* this 8-bit port's data */
310 unsigned char byte = 0,
0a85b6f0
MT
311 /* The write mask for this port (if any) */
312 write_mask_byte = (data[0] >> offset) & 0xff,
313 /* The data byte for this port */
314 data_byte = (data[1] >> offset) & 0xff;
6baef150
CC
315
316 byte = inb(ioaddr); /* read all 8-bits for this port */
317
318#ifdef DAMMIT_ITS_BROKEN
319 /* DEBUG */
0a85b6f0 320 printk
bcd9a1e9
JT
321 (KERN_DEBUG "byte %d wmb %02x db %02x offset %02d io %04x,"
322 " data_in %02x ", byte_no, (unsigned)write_mask_byte,
323 (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
6baef150
CC
324#endif
325
326 if (write_mask_byte) {
d2d08955
DPJ
327 /*
328 * this byte has some write_bits
329 * -- so set the output lines
330 */
331 /* clear bits for write mask */
332 byte &= ~write_mask_byte;
333 /* set to inverted data_byte */
334 byte |= ~data_byte & write_mask_byte;
6baef150
CC
335 /* Write out the new digital output state */
336 outb(byte, ioaddr);
337 }
338#ifdef DAMMIT_ITS_BROKEN
339 /* DEBUG */
cf568278 340 printk("data_out_byte %02x\n", (unsigned)byte);
6baef150
CC
341#endif
342 /* save the digital input lines for this byte.. */
343 s->state |= ((unsigned int)byte) << offset;
344 }
345
346 /* now return the DIO lines to data[1] - note they came inverted! */
347 data[1] = ~s->state;
348
349#ifdef DAMMIT_ITS_BROKEN
350 /* DEBUG */
bcd9a1e9 351 printk(KERN_DEBUG "s->state %08x data_out %08x\n", s->state, data[1]);
6baef150
CC
352#endif
353
354 return 2;
355}
356
357/* The input or output configuration of each digital line is
358 * configured by a special insn_config instruction. chanspec
359 * contains the channel to be changed, and data[0] contains the
360 * value COMEDI_INPUT or COMEDI_OUTPUT. */
0a85b6f0
MT
361static int pcmmio_dio_insn_config(struct comedi_device *dev,
362 struct comedi_subdevice *s,
363 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
364{
365 int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
0a85b6f0 366 chan % 8;
6baef150
CC
367 unsigned long ioaddr;
368 unsigned char byte;
369
370 /* Compute ioaddr for this channel */
371 ioaddr = subpriv->iobases[byte_no];
372
373 /* NOTE:
374 writing a 0 an IO channel's bit sets the channel to INPUT
375 and pulls the line high as well
376
377 writing a 1 to an IO channel's bit pulls the line low
378
379 All channels are implicitly always in OUTPUT mode -- but when
380 they are high they can be considered to be in INPUT mode..
381
382 Thus, we only force channels low if the config request was INPUT,
383 otherwise we do nothing to the hardware. */
384
385 switch (data[0]) {
386 case INSN_CONFIG_DIO_OUTPUT:
387 /* save to io_bits -- don't actually do anything since
388 all input channels are also output channels... */
389 s->io_bits |= 1 << chan;
390 break;
391 case INSN_CONFIG_DIO_INPUT:
392 /* write a 0 to the actual register representing the channel
393 to set it to 'input'. 0 means "float high". */
394 byte = inb(ioaddr);
395 byte &= ~(1 << bit_no);
396 /**< set input channel to '0' */
397
013f230c
DPJ
398 /*
399 * write out byte -- this is the only time we actually affect
400 * the hardware as all channels are implicitly output
401 * -- but input channels are set to float-high
402 */
6baef150
CC
403 outb(byte, ioaddr);
404
405 /* save to io_bits */
406 s->io_bits &= ~(1 << chan);
407 break;
408
409 case INSN_CONFIG_DIO_QUERY:
25985edc 410 /* retrieve from shadow register */
6baef150 411 data[1] =
0a85b6f0 412 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
6baef150
CC
413 return insn->n;
414 break;
415
416 default:
417 return -EINVAL;
418 break;
419 }
420
421 return insn->n;
422}
423
b2bb98e1
HS
424static void switch_page(struct comedi_device *dev, int asic, int page)
425{
426 if (asic < 0 || asic >= thisboard->dio_num_asics)
427 return; /* paranoia */
428 if (page < 0 || page >= NUM_PAGES)
429 return; /* more paranoia */
430
431 devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
432 devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
433
434 /* now write out the shadow register */
435 outb(devpriv->asics[asic].pagelock,
436 devpriv->asics[asic].iobase + REG_PAGELOCK);
437}
438
da91b269 439static void init_asics(struct comedi_device *dev)
6baef150
CC
440{ /* sets up an
441 ASIC chip to defaults */
442 int asic;
443
444 for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
445 int port, page;
446 unsigned long baseaddr = devpriv->asics[asic].iobase;
447
448 switch_page(dev, asic, 0); /* switch back to page 0 */
449
450 /* first, clear all the DIO port bits */
451 for (port = 0; port < PORTS_PER_ASIC; ++port)
452 outb(0, baseaddr + REG_PORT0 + port);
453
454 /* Next, clear all the paged registers for each page */
455 for (page = 1; page < NUM_PAGES; ++page) {
456 int reg;
457 /* now clear all the paged registers */
458 switch_page(dev, asic, page);
459 for (reg = FIRST_PAGED_REG;
0a85b6f0 460 reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
6baef150
CC
461 outb(0, baseaddr + reg);
462 }
463
464 /* DEBUG set rising edge interrupts on port0 of both asics */
465 /*switch_page(dev, asic, PAGE_POL);
466 outb(0xff, baseaddr + REG_POL0);
467 switch_page(dev, asic, PAGE_ENAB);
468 outb(0xff, baseaddr + REG_ENAB0); */
469 /* END DEBUG */
470
013f230c
DPJ
471 /* switch back to default page 0 */
472 switch_page(dev, asic, 0);
6baef150
CC
473 }
474}
475
6baef150 476#ifdef notused
da91b269 477static void lock_port(struct comedi_device *dev, int asic, int port)
6baef150
CC
478{
479 if (asic < 0 || asic >= thisboard->dio_num_asics)
480 return; /* paranoia */
481 if (port < 0 || port >= PORTS_PER_ASIC)
482 return; /* more paranoia */
483
484 devpriv->asics[asic].pagelock |= 0x1 << port;
485 /* now write out the shadow register */
486 outb(devpriv->asics[asic].pagelock,
0a85b6f0 487 devpriv->asics[asic].iobase + REG_PAGELOCK);
6baef150
CC
488 return;
489}
490
da91b269 491static void unlock_port(struct comedi_device *dev, int asic, int port)
6baef150
CC
492{
493 if (asic < 0 || asic >= thisboard->dio_num_asics)
494 return; /* paranoia */
495 if (port < 0 || port >= PORTS_PER_ASIC)
496 return; /* more paranoia */
497 devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
498 /* now write out the shadow register */
499 outb(devpriv->asics[asic].pagelock,
0a85b6f0 500 devpriv->asics[asic].iobase + REG_PAGELOCK);
6baef150
CC
501}
502#endif /* notused */
503
b2bb98e1
HS
504static void pcmmio_stop_intr(struct comedi_device *dev,
505 struct comedi_subdevice *s)
506{
507 int nports, firstport, asic, port;
508
509 asic = subpriv->dio.intr.asic;
510 if (asic < 0)
511 return; /* not an interrupt subdev */
512
513 subpriv->dio.intr.enabled_mask = 0;
514 subpriv->dio.intr.active = 0;
515 s->async->inttrig = 0;
516 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
517 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
518 switch_page(dev, asic, PAGE_ENAB);
519 for (port = firstport; port < firstport + nports; ++port) {
520 /* disable all intrs for this subdev.. */
521 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
522 }
523}
524
70265d24 525static irqreturn_t interrupt_pcmmio(int irq, void *d)
6baef150
CC
526{
527 int asic, got1 = 0;
0a85b6f0 528 struct comedi_device *dev = (struct comedi_device *)d;
6baef150
CC
529
530 for (asic = 0; asic < MAX_ASICS; ++asic) {
531 if (irq == devpriv->asics[asic].irq) {
532 unsigned long flags;
533 unsigned triggered = 0;
534 unsigned long iobase = devpriv->asics[asic].iobase;
535 /* it is an interrupt for ASIC #asic */
536 unsigned char int_pend;
537
0a85b6f0
MT
538 spin_lock_irqsave(&devpriv->asics[asic].spinlock,
539 flags);
6baef150
CC
540
541 int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
542
543 if (int_pend) {
544 int port;
545 for (port = 0; port < INTR_PORTS_PER_ASIC;
0a85b6f0 546 ++port) {
6baef150
CC
547 if (int_pend & (0x1 << port)) {
548 unsigned char
0a85b6f0 549 io_lines_with_edges = 0;
6baef150 550 switch_page(dev, asic,
0a85b6f0 551 PAGE_INT_ID);
6baef150 552 io_lines_with_edges =
0a85b6f0 553 inb(iobase +
6baef150
CC
554 REG_INT_ID0 + port);
555
556 if (io_lines_with_edges)
013f230c
DPJ
557 /*
558 * clear pending
559 * interrupt
560 */
6baef150 561 outb(0, iobase +
0a85b6f0
MT
562 REG_INT_ID0 +
563 port);
6baef150
CC
564
565 triggered |=
0a85b6f0
MT
566 io_lines_with_edges <<
567 port * 8;
6baef150
CC
568 }
569 }
570
571 ++got1;
572 }
573
0a85b6f0
MT
574 spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
575 flags);
6baef150
CC
576
577 if (triggered) {
34c43922 578 struct comedi_subdevice *s;
013f230c
DPJ
579 /*
580 * TODO here: dispatch io lines to subdevs
581 * with commands..
582 */
0a85b6f0 583 printk
bcd9a1e9 584 (KERN_DEBUG "got edge detect interrupt %d asic %d which_chans: %06x\n",
0a85b6f0 585 irq, asic, triggered);
6baef150 586 for (s = dev->subdevices + 2;
0a85b6f0
MT
587 s < dev->subdevices + dev->n_subdevices;
588 ++s) {
013f230c
DPJ
589 /*
590 * this is an interrupt subdev,
591 * and it matches this asic!
592 */
593 if (subpriv->dio.intr.asic == asic) {
6baef150
CC
594 unsigned long flags;
595 unsigned oldevents;
596
0a85b6f0
MT
597 spin_lock_irqsave(&subpriv->dio.
598 intr.spinlock,
599 flags);
6baef150
CC
600
601 oldevents = s->async->events;
602
603 if (subpriv->dio.intr.active) {
604 unsigned mytrig =
0a85b6f0
MT
605 ((triggered >>
606 subpriv->dio.intr.asic_chan)
607 &
608 ((0x1 << subpriv->
609 dio.intr.
610 num_asic_chans) -
611 1)) << subpriv->
612 dio.intr.first_chan;
613 if (mytrig &
614 subpriv->dio.
615 intr.enabled_mask) {
616 unsigned int val
617 = 0;
6baef150 618 unsigned int n,
0a85b6f0 619 ch, len;
6baef150 620
0a85b6f0
MT
621 len =
622 s->
623 async->cmd.chanlist_len;
6baef150 624 for (n = 0;
0a85b6f0
MT
625 n < len;
626 n++) {
6baef150 627 ch = CR_CHAN(s->async->cmd.chanlist[n]);
013f230c 628 if (mytrig & (1U << ch))
6baef150 629 val |= (1U << n);
6baef150
CC
630 }
631 /* Write the scan to the buffer. */
0a85b6f0
MT
632 if (comedi_buf_put(s->async, ((short *)&val)[0])
633 &&
634 comedi_buf_put
635 (s->async,
636 ((short *)
013f230c 637 &val)[1])) {
6baef150
CC
638 s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
639 } else {
640 /* Overflow! Stop acquisition!! */
641 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
642 pcmmio_stop_intr
0a85b6f0
MT
643 (dev,
644 s);
6baef150
CC
645 }
646
647 /* Check for end of acquisition. */
0a85b6f0 648 if (!subpriv->dio.intr.continuous) {
6baef150
CC
649 /* stop_src == TRIG_COUNT */
650 if (subpriv->dio.intr.stop_count > 0) {
0a85b6f0 651 subpriv->dio.intr.stop_count--;
6baef150
CC
652 if (subpriv->dio.intr.stop_count == 0) {
653 s->async->events |= COMEDI_CB_EOA;
654 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
655 pcmmio_stop_intr
0a85b6f0
MT
656 (dev,
657 s);
6baef150
CC
658 }
659 }
660 }
661 }
662 }
663
0a85b6f0
MT
664 spin_unlock_irqrestore
665 (&subpriv->dio.intr.
666 spinlock, flags);
6baef150
CC
667
668 if (oldevents !=
0a85b6f0 669 s->async->events) {
6baef150
CC
670 comedi_event(dev, s);
671 }
672
673 }
674
b2bb98e1
HS
675 }
676 }
677
678 }
6baef150 679 }
b2bb98e1
HS
680 if (!got1)
681 return IRQ_NONE; /* interrupt from other source */
682 return IRQ_HANDLED;
6baef150
CC
683}
684
0a85b6f0
MT
685static int pcmmio_start_intr(struct comedi_device *dev,
686 struct comedi_subdevice *s)
6baef150
CC
687{
688 if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
689 /* An empty acquisition! */
690 s->async->events |= COMEDI_CB_EOA;
691 subpriv->dio.intr.active = 0;
692 return 1;
693 } else {
694 unsigned bits = 0, pol_bits = 0, n;
695 int nports, firstport, asic, port;
ea6d0d4c 696 struct comedi_cmd *cmd = &s->async->cmd;
6baef150 697
c3744138 698 asic = subpriv->dio.intr.asic;
0a85b6f0 699 if (asic < 0)
6baef150
CC
700 return 1; /* not an interrupt
701 subdev */
702 subpriv->dio.intr.enabled_mask = 0;
703 subpriv->dio.intr.active = 1;
704 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
705 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
706 if (cmd->chanlist) {
707 for (n = 0; n < cmd->chanlist_len; n++) {
708 bits |= (1U << CR_CHAN(cmd->chanlist[n]));
709 pol_bits |= (CR_AREF(cmd->chanlist[n])
0a85b6f0
MT
710 || CR_RANGE(cmd->
711 chanlist[n]) ? 1U : 0U)
712 << CR_CHAN(cmd->chanlist[n]);
6baef150
CC
713 }
714 }
715 bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
0a85b6f0 716 1) << subpriv->dio.intr.first_chan;
6baef150
CC
717 subpriv->dio.intr.enabled_mask = bits;
718
013f230c
DPJ
719 {
720 /*
721 * the below code configures the board
722 * to use a specific IRQ from 0-15.
723 */
6baef150 724 unsigned char b;
013f230c
DPJ
725 /*
726 * set resource enable register
727 * to enable IRQ operation
728 */
6baef150
CC
729 outb(1 << 4, dev->iobase + 3);
730 /* set bits 0-3 of b to the irq number from 0-15 */
731 b = dev->irq & ((1 << 4) - 1);
732 outb(b, dev->iobase + 2);
733 /* done, we told the board what irq to use */
734 }
735
736 switch_page(dev, asic, PAGE_ENAB);
737 for (port = firstport; port < firstport + nports; ++port) {
738 unsigned enab =
0a85b6f0
MT
739 bits >> (subpriv->dio.intr.first_chan + (port -
740 firstport)
741 * 8) & 0xff, pol =
742 pol_bits >> (subpriv->dio.intr.first_chan +
743 (port - firstport) * 8) & 0xff;
6baef150
CC
744 /* set enab intrs for this subdev.. */
745 outb(enab,
0a85b6f0 746 devpriv->asics[asic].iobase + REG_ENAB0 + port);
6baef150
CC
747 switch_page(dev, asic, PAGE_POL);
748 outb(pol,
0a85b6f0 749 devpriv->asics[asic].iobase + REG_ENAB0 + port);
6baef150
CC
750 }
751 }
752 return 0;
753}
754
da91b269 755static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
6baef150
CC
756{
757 unsigned long flags;
758
5f74ea14 759 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
6baef150
CC
760 if (subpriv->dio.intr.active)
761 pcmmio_stop_intr(dev, s);
5f74ea14 762 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
6baef150
CC
763
764 return 0;
765}
766
767/*
768 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
769 */
770static int
da91b269 771pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 772 unsigned int trignum)
6baef150
CC
773{
774 unsigned long flags;
775 int event = 0;
776
777 if (trignum != 0)
778 return -EINVAL;
779
5f74ea14 780 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
6baef150 781 s->async->inttrig = 0;
013f230c 782 if (subpriv->dio.intr.active)
6baef150 783 event = pcmmio_start_intr(dev, s);
5f74ea14 784 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
6baef150 785
013f230c 786 if (event)
6baef150 787 comedi_event(dev, s);
6baef150
CC
788
789 return 1;
790}
791
792/*
793 * 'do_cmd' function for an 'INTERRUPT' subdevice.
794 */
da91b269 795static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
6baef150 796{
ea6d0d4c 797 struct comedi_cmd *cmd = &s->async->cmd;
6baef150
CC
798 unsigned long flags;
799 int event = 0;
800
5f74ea14 801 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
6baef150
CC
802 subpriv->dio.intr.active = 1;
803
804 /* Set up end of acquisition. */
805 switch (cmd->stop_src) {
806 case TRIG_COUNT:
807 subpriv->dio.intr.continuous = 0;
808 subpriv->dio.intr.stop_count = cmd->stop_arg;
809 break;
810 default:
811 /* TRIG_NONE */
812 subpriv->dio.intr.continuous = 1;
813 subpriv->dio.intr.stop_count = 0;
814 break;
815 }
816
817 /* Set up start of acquisition. */
818 switch (cmd->start_src) {
819 case TRIG_INT:
820 s->async->inttrig = pcmmio_inttrig_start_intr;
821 break;
822 default:
823 /* TRIG_NOW */
824 event = pcmmio_start_intr(dev, s);
825 break;
826 }
5f74ea14 827 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
6baef150 828
013f230c 829 if (event)
6baef150 830 comedi_event(dev, s);
6baef150
CC
831
832 return 0;
833}
834
6baef150 835static int
0a85b6f0
MT
836pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
837 struct comedi_cmd *cmd)
6baef150 838{
0b8f754a 839 return comedi_pcm_cmdtest(dev, s, cmd);
6baef150
CC
840}
841
842static int adc_wait_ready(unsigned long iobase)
843{
844 unsigned long retry = 100000;
845 while (retry--)
846 if (inb(iobase + 3) & 0x80)
847 return 0;
848 return 1;
849}
850
851/* All this is for AI and AO */
da91b269 852static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 853 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
854{
855 int n;
856 unsigned long iobase = subpriv->iobase;
857
858 /*
859 1. write the CMD byte (to BASE+2)
860 2. read junk lo byte (BASE+0)
861 3. read junk hi byte (BASE+1)
862 4. (mux settled so) write CMD byte again (BASE+2)
863 5. read valid lo byte(BASE+0)
864 6. read valid hi byte(BASE+1)
865
866 Additionally note that the BASE += 4 if the channel >= 8
867 */
868
869 /* convert n samples */
870 for (n = 0; n < insn->n; n++) {
871 unsigned chan = CR_CHAN(insn->chanspec), range =
0a85b6f0 872 CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
6baef150
CC
873 unsigned char command_byte = 0;
874 unsigned iooffset = 0;
790c5541 875 short sample, adc_adjust = 0;
6baef150
CC
876
877 if (chan > 7)
013f230c
DPJ
878 chan -= 8, iooffset = 4; /*
879 * use the second dword
880 * for channels > 7
881 */
6baef150
CC
882
883 if (aref != AREF_DIFF) {
884 aref = AREF_GROUND;
013f230c
DPJ
885 command_byte |= 1 << 7; /*
886 * set bit 7 to indicate
887 * single-ended
888 */
6baef150
CC
889 }
890 if (range < 2)
013f230c
DPJ
891 adc_adjust = 0x8000; /*
892 * bipolar ranges
893 * (-5,5 .. -10,10 need to be
894 * adjusted -- that is.. they
895 * need to wrap around by
896 * adding 0x8000
897 */
6baef150
CC
898
899 if (chan % 2) {
013f230c
DPJ
900 command_byte |= 1 << 6; /*
901 * odd-numbered channels
902 * have bit 6 set
903 */
6baef150
CC
904 }
905
906 /* select the channel, bits 4-5 == chan/2 */
907 command_byte |= ((chan / 2) & 0x3) << 4;
908
909 /* set the range, bits 2-3 */
910 command_byte |= (range & 0x3) << 2;
911
912 /* need to do this twice to make sure mux settled */
013f230c
DPJ
913 /* chan/range/aref select */
914 outb(command_byte, iobase + iooffset + 2);
6baef150 915
013f230c
DPJ
916 /* wait for the adc to say it finised the conversion */
917 adc_wait_ready(iobase + iooffset);
6baef150 918
013f230c
DPJ
919 /* select the chan/range/aref AGAIN */
920 outb(command_byte, iobase + iooffset + 2);
6baef150
CC
921
922 adc_wait_ready(iobase + iooffset);
923
013f230c
DPJ
924 /* read data lo byte */
925 sample = inb(iobase + iooffset + 0);
926
927 /* read data hi byte */
928 sample |= inb(iobase + iooffset + 1) << 8;
6baef150
CC
929 sample += adc_adjust; /* adjustment .. munge data */
930 data[n] = sample;
931 }
932 /* return the number of samples read/written */
933 return n;
934}
935
da91b269 936static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 937 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
938{
939 int n;
940 for (n = 0; n < insn->n; n++) {
941 unsigned chan = CR_CHAN(insn->chanspec);
942 if (chan < s->n_chan)
943 data[n] = subpriv->ao.shadow_samples[chan];
944 }
945 return n;
946}
947
948static int wait_dac_ready(unsigned long iobase)
949{
950 unsigned long retry = 100000L;
951
952 /* This may seem like an absurd way to handle waiting and violates the
953 "no busy waiting" policy. The fact is that the hardware is
954 normally so fast that we usually only need one time through the loop
955 anyway. The longer timeout is for rare occasions and for detecting
25985edc 956 non-existent hardware. */
6baef150
CC
957
958 while (retry--) {
959 if (inb(iobase + 3) & 0x80)
960 return 0;
961
962 }
963 return 1;
964}
965
da91b269 966static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 967 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
968{
969 int n;
970 unsigned iobase = subpriv->iobase, iooffset = 0;
971
972 for (n = 0; n < insn->n; n++) {
973 unsigned chan = CR_CHAN(insn->chanspec), range =
0a85b6f0 974 CR_RANGE(insn->chanspec);
6baef150
CC
975 if (chan < s->n_chan) {
976 unsigned char command_byte = 0, range_byte =
0a85b6f0 977 range & ((1 << 4) - 1);
6baef150
CC
978 if (chan >= 4)
979 chan -= 4, iooffset += 4;
980 /* set the range.. */
981 outb(range_byte, iobase + iooffset + 0);
982 outb(0, iobase + iooffset + 1);
983
984 /* tell it to begin */
985 command_byte = (chan << 1) | 0x60;
986 outb(command_byte, iobase + iooffset + 2);
987
988 wait_dac_ready(iobase + iooffset);
989
013f230c
DPJ
990 /* low order byte */
991 outb(data[n] & 0xff, iobase + iooffset + 0);
992
993 /* high order byte */
994 outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
995
996 /*
997 * set bit 4 of command byte to indicate
998 * data is loaded and trigger conversion
999 */
1000 command_byte = 0x70 | (chan << 1);
6baef150
CC
1001 /* trigger converion */
1002 outb(command_byte, iobase + iooffset + 2);
1003
1004 wait_dac_ready(iobase + iooffset);
1005
013f230c
DPJ
1006 /* save to shadow register for ao_rinsn */
1007 subpriv->ao.shadow_samples[chan] = data[n];
6baef150
CC
1008 }
1009 }
1010 return n;
1011}
1012
b2bb98e1
HS
1013static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1014{
1015 struct comedi_subdevice *s;
1016 int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
1017 thisasic_chanct = 0;
1018 unsigned long iobase;
1019 unsigned int irq[MAX_ASICS];
1020
1021 iobase = it->options[0];
1022 irq[0] = it->options[1];
1023
1024 printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
1025 driver.driver_name, iobase);
1026
1027 dev->iobase = iobase;
1028
1029 if (!iobase || !request_region(iobase,
1030 thisboard->total_iosize,
1031 driver.driver_name)) {
1032 printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
1033 return -EIO;
1034 }
1035
1036/*
1037 * Initialize dev->board_name. Note that we can use the "thisboard"
1038 * macro now, since we just initialized it in the last line.
1039 */
1040 dev->board_name = thisboard->name;
1041
6baef150 1042/*
b2bb98e1
HS
1043 * Allocate the private structure area. alloc_private() is a
1044 * convenient macro defined in comedidev.h.
6baef150 1045 */
b2bb98e1
HS
1046 if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
1047 printk(KERN_ERR "comedi%d: cannot allocate private data structure\n",
1048 dev->minor);
1049 return -ENOMEM;
1050 }
1051
1052 for (asic = 0; asic < MAX_ASICS; ++asic) {
1053 devpriv->asics[asic].num = asic;
1054 devpriv->asics[asic].iobase =
1055 dev->iobase + 16 + asic * ASIC_IOSIZE;
1056 /*
1057 * this gets actually set at the end of this function when we
1058 * request_irqs
1059 */
1060 devpriv->asics[asic].irq = 0;
1061 spin_lock_init(&devpriv->asics[asic].spinlock);
1062 }
1063
1064 chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
1065 n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
1066 n_subdevs = n_dio_subdevs + 2;
1067 devpriv->sprivs =
1068 kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
1069 GFP_KERNEL);
1070 if (!devpriv->sprivs) {
1071 printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
1072 dev->minor);
1073 return -ENOMEM;
1074 }
1075 /*
1076 * Allocate the subdevice structures. alloc_subdevice() is a
1077 * convenient macro defined in comedidev.h.
1078 *
1079 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
1080 */
1081 if (alloc_subdevices(dev, n_subdevs) < 0) {
1082 printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n",
1083 dev->minor);
1084 return -ENOMEM;
1085 }
1086
1087 /* First, AI */
1088 sdev_no = 0;
1089 s = dev->subdevices + sdev_no;
1090 s->private = devpriv->sprivs + sdev_no;
1091 s->maxdata = (1 << thisboard->ai_bits) - 1;
1092 s->range_table = thisboard->ai_range_table;
1093 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
1094 s->type = COMEDI_SUBD_AI;
1095 s->n_chan = thisboard->n_ai_chans;
1096 s->len_chanlist = s->n_chan;
1097 s->insn_read = thisboard->ai_rinsn;
1098 subpriv->iobase = dev->iobase + 0;
1099 /* initialize the resource enable register by clearing it */
1100 outb(0, subpriv->iobase + 3);
1101 outb(0, subpriv->iobase + 4 + 3);
1102
1103 /* Next, AO */
1104 ++sdev_no;
1105 s = dev->subdevices + sdev_no;
1106 s->private = devpriv->sprivs + sdev_no;
1107 s->maxdata = (1 << thisboard->ao_bits) - 1;
1108 s->range_table = thisboard->ao_range_table;
1109 s->subdev_flags = SDF_READABLE;
1110 s->type = COMEDI_SUBD_AO;
1111 s->n_chan = thisboard->n_ao_chans;
1112 s->len_chanlist = s->n_chan;
1113 s->insn_read = thisboard->ao_rinsn;
1114 s->insn_write = thisboard->ao_winsn;
1115 subpriv->iobase = dev->iobase + 8;
1116 /* initialize the resource enable register by clearing it */
1117 outb(0, subpriv->iobase + 3);
1118 outb(0, subpriv->iobase + 4 + 3);
1119
1120 ++sdev_no;
1121 port = 0;
1122 asic = 0;
1123 for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
1124 int byte_no;
1125
1126 s = dev->subdevices + sdev_no;
1127 s->private = devpriv->sprivs + sdev_no;
1128 s->maxdata = 1;
1129 s->range_table = &range_digital;
1130 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1131 s->type = COMEDI_SUBD_DIO;
1132 s->insn_bits = pcmmio_dio_insn_bits;
1133 s->insn_config = pcmmio_dio_insn_config;
1134 s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
1135 subpriv->dio.intr.asic = -1;
1136 subpriv->dio.intr.first_chan = -1;
1137 subpriv->dio.intr.asic_chan = -1;
1138 subpriv->dio.intr.num_asic_chans = -1;
1139 subpriv->dio.intr.active = 0;
1140 s->len_chanlist = 1;
1141
1142 /* save the ioport address for each 'port' of 8 channels in the
1143 subdevice */
1144 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
1145 if (port >= PORTS_PER_ASIC) {
1146 port = 0;
1147 ++asic;
1148 thisasic_chanct = 0;
1149 }
1150 subpriv->iobases[byte_no] =
1151 devpriv->asics[asic].iobase + port;
1152
1153 if (thisasic_chanct <
1154 CHANS_PER_PORT * INTR_PORTS_PER_ASIC
1155 && subpriv->dio.intr.asic < 0) {
1156 /*
1157 * this is an interrupt subdevice,
1158 * so setup the struct
1159 */
1160 subpriv->dio.intr.asic = asic;
1161 subpriv->dio.intr.active = 0;
1162 subpriv->dio.intr.stop_count = 0;
1163 subpriv->dio.intr.first_chan = byte_no * 8;
1164 subpriv->dio.intr.asic_chan = thisasic_chanct;
1165 subpriv->dio.intr.num_asic_chans =
1166 s->n_chan - subpriv->dio.intr.first_chan;
1167 s->cancel = pcmmio_cancel;
1168 s->do_cmd = pcmmio_cmd;
1169 s->do_cmdtest = pcmmio_cmdtest;
1170 s->len_chanlist =
1171 subpriv->dio.intr.num_asic_chans;
1172 }
1173 thisasic_chanct += CHANS_PER_PORT;
1174 }
1175 spin_lock_init(&subpriv->dio.intr.spinlock);
1176
1177 chans_left -= s->n_chan;
1178
1179 if (!chans_left) {
1180 /*
1181 * reset the asic to our first asic,
1182 * to do intr subdevs
1183 */
1184 asic = 0;
1185 port = 0;
1186 }
1187
1188 }
1189
1190 init_asics(dev); /* clear out all the registers, basically */
1191
1192 for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
1193 if (irq[asic]
1194 && request_irq(irq[asic], interrupt_pcmmio,
1195 IRQF_SHARED, thisboard->name, dev)) {
1196 int i;
1197 /* unroll the allocated irqs.. */
1198 for (i = asic - 1; i >= 0; --i) {
1199 free_irq(irq[i], dev);
1200 devpriv->asics[i].irq = irq[i] = 0;
1201 }
1202 irq[asic] = 0;
1203 }
1204 devpriv->asics[asic].irq = irq[asic];
1205 }
1206
1207 dev->irq = irq[0]; /*
1208 * grr.. wish comedi dev struct supported
1209 * multiple irqs..
1210 */
1211
1212 if (irq[0]) {
1213 printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]);
1214 if (thisboard->dio_num_asics == 2 && irq[1])
1215 printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n",
1216 dev->minor, irq[1]);
1217 } else {
1218 printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor);
1219 }
1220
1221 printk(KERN_INFO "comedi%d: attached\n", dev->minor);
1222
1223 return 1;
1224}
1225
1226static int pcmmio_detach(struct comedi_device *dev)
1227{
1228 int i;
1229
1230 printk(KERN_INFO "comedi%d: %s: remove\n", dev->minor, driver.driver_name);
1231 if (dev->iobase)
1232 release_region(dev->iobase, thisboard->total_iosize);
1233
1234 for (i = 0; i < MAX_ASICS; ++i) {
1235 if (devpriv && devpriv->asics[i].irq)
1236 free_irq(devpriv->asics[i].irq, dev);
1237 }
1238
1239 if (devpriv && devpriv->sprivs)
1240 kfree(devpriv->sprivs);
1241
1242 return 0;
1243}
1244
1245static const struct pcmmio_board pcmmio_boards[] = {
1246 {
1247 .name = "pcmmio",
1248 .dio_num_asics = 1,
1249 .dio_num_ports = 6,
1250 .total_iosize = 32,
1251 .ai_bits = 16,
1252 .ao_bits = 16,
1253 .n_ai_chans = 16,
1254 .n_ao_chans = 8,
1255 .ai_range_table = &ranges_ai,
1256 .ao_range_table = &ranges_ao,
1257 .ai_rinsn = ai_rinsn,
1258 .ao_rinsn = ao_rinsn,
1259 .ao_winsn = ao_winsn
1260 },
1261};
1262
1263static struct comedi_driver driver = {
1264 .driver_name = "pcmmio",
1265 .module = THIS_MODULE,
1266 .attach = pcmmio_attach,
1267 .detach = pcmmio_detach,
1268 .board_name = &pcmmio_boards[0].name,
1269 .offset = sizeof(struct pcmmio_board),
1270 .num_names = ARRAY_SIZE(pcmmio_boards),
1271};
1272
7114a280
AT
1273static int __init driver_init_module(void)
1274{
1275 return comedi_driver_register(&driver);
1276}
b2bb98e1 1277module_init(driver_init_module);
7114a280
AT
1278
1279static void __exit driver_cleanup_module(void)
1280{
1281 comedi_driver_unregister(&driver);
1282}
7114a280 1283module_exit(driver_cleanup_module);
90f703d3
AT
1284
1285MODULE_AUTHOR("Comedi http://www.comedi.org");
1286MODULE_DESCRIPTION("Comedi low-level driver");
1287MODULE_LICENSE("GPL");
This page took 0.368897 seconds and 5 git commands to generate.