staging: comedi: remove inline alloc_private()
[deliverable/linux.git] / drivers / staging / comedi / drivers / pcmmio.c
... / ...
CommitLineData
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
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)
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
75 [1] - IRQ (optional -- for edge-detect interrupt support only,
76 leave out if you don't need this feature)
77*/
78
79#include <linux/interrupt.h>
80#include <linux/slab.h>
81#include "../comedidev.h"
82#include "pcm_common.h"
83#include <linux/pci.h> /* for PCI devices */
84
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
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 */
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))
143#define REG_LOCK_MASK (~(REG_PAGE_MASK))
144#define PAGE_POL 1
145#define PAGE_ENAB 2
146#define PAGE_INT_ID 3
147
148static const struct comedi_lrange ranges_ai = {
149 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)}
150};
151
152static const struct comedi_lrange ranges_ao = {
153 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
154 RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
155};
156
157/* this structure is for data unique to this subdevice. */
158struct pcmmio_subdev_private {
159
160 union {
161 /* for DIO: mapping of halfwords (bytes)
162 in port/chanarray to iobase */
163 unsigned long iobases[PORTS_PER_SUBDEV];
164
165 /* for AI/AO */
166 unsigned long iobase;
167 };
168 union {
169 struct {
170
171 /* The below is only used for intr subdevices */
172 struct {
173 /*
174 * if non-negative, this subdev has an
175 * interrupt asic
176 */
177 int asic;
178 /*
179 * if nonnegative, the first channel id for
180 * interrupts.
181 */
182 int first_chan;
183 /*
184 * the number of asic channels in this subdev
185 * that have interrutps
186 */
187 int num_asic_chans;
188 /*
189 * if nonnegative, the first channel id with
190 * respect to the asic that has interrupts
191 */
192 int asic_chan;
193 /*
194 * subdev-relative channel mask for channels
195 * we are interested in
196 */
197 int enabled_mask;
198 int active;
199 int stop_count;
200 int continuous;
201 spinlock_t spinlock;
202 } intr;
203 } dio;
204 struct {
205 /* the last unsigned int data written */
206 unsigned int shadow_samples[8];
207 } ao;
208 };
209};
210
211/*
212 * this structure is for data unique to this hardware driver. If
213 * several hardware drivers keep similar information in this structure,
214 * feel free to suggest moving the variable to the struct comedi_device struct.
215 */
216struct pcmmio_private {
217 /* stuff for DIO */
218 struct {
219 unsigned char pagelock; /* current page and lock */
220 /* shadow of POLx registers */
221 unsigned char pol[NUM_PAGED_REGS];
222 /* shadow of ENABx registers */
223 unsigned char enab[NUM_PAGED_REGS];
224 int num;
225 unsigned long iobase;
226 unsigned int irq;
227 spinlock_t spinlock;
228 } asics[MAX_ASICS];
229 struct pcmmio_subdev_private *sprivs;
230};
231
232#define subpriv ((struct pcmmio_subdev_private *)s->private)
233
234/* DIO devices are slightly special. Although it is possible to
235 * implement the insn_read/insn_write interface, it is much more
236 * useful to applications if you implement the insn_bits interface.
237 * This allows packed reading/writing of the DIO channels. The
238 * comedi core can convert between insn_bits and insn_read/write */
239static int pcmmio_dio_insn_bits(struct comedi_device *dev,
240 struct comedi_subdevice *s,
241 struct comedi_insn *insn, unsigned int *data)
242{
243 int byte_no;
244
245 /* NOTE:
246 reading a 0 means this channel was high
247 writine a 0 sets the channel high
248 reading a 1 means this channel was low
249 writing a 1 means set this channel low
250
251 Therefore everything is always inverted. */
252
253 /* The insn data is a mask in data[0] and the new data
254 * in data[1], each channel cooresponding to a bit. */
255
256#ifdef DAMMIT_ITS_BROKEN
257 /* DEBUG */
258 printk(KERN_DEBUG "write mask: %08x data: %08x\n", data[0], data[1]);
259#endif
260
261 s->state = 0;
262
263 for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
264 /* address of 8-bit port */
265 unsigned long ioaddr = subpriv->iobases[byte_no],
266 /* bit offset of port in 32-bit doubleword */
267 offset = byte_no * 8;
268 /* this 8-bit port's data */
269 unsigned char byte = 0,
270 /* The write mask for this port (if any) */
271 write_mask_byte = (data[0] >> offset) & 0xff,
272 /* The data byte for this port */
273 data_byte = (data[1] >> offset) & 0xff;
274
275 byte = inb(ioaddr); /* read all 8-bits for this port */
276
277#ifdef DAMMIT_ITS_BROKEN
278 /* DEBUG */
279 printk
280 (KERN_DEBUG "byte %d wmb %02x db %02x offset %02d io %04x,"
281 " data_in %02x ", byte_no, (unsigned)write_mask_byte,
282 (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
283#endif
284
285 if (write_mask_byte) {
286 /*
287 * this byte has some write_bits
288 * -- so set the output lines
289 */
290 /* clear bits for write mask */
291 byte &= ~write_mask_byte;
292 /* set to inverted data_byte */
293 byte |= ~data_byte & write_mask_byte;
294 /* Write out the new digital output state */
295 outb(byte, ioaddr);
296 }
297#ifdef DAMMIT_ITS_BROKEN
298 /* DEBUG */
299 printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte);
300#endif
301 /* save the digital input lines for this byte.. */
302 s->state |= ((unsigned int)byte) << offset;
303 }
304
305 /* now return the DIO lines to data[1] - note they came inverted! */
306 data[1] = ~s->state;
307
308#ifdef DAMMIT_ITS_BROKEN
309 /* DEBUG */
310 printk(KERN_DEBUG "s->state %08x data_out %08x\n", s->state, data[1]);
311#endif
312
313 return insn->n;
314}
315
316/* The input or output configuration of each digital line is
317 * configured by a special insn_config instruction. chanspec
318 * contains the channel to be changed, and data[0] contains the
319 * value COMEDI_INPUT or COMEDI_OUTPUT. */
320static int pcmmio_dio_insn_config(struct comedi_device *dev,
321 struct comedi_subdevice *s,
322 struct comedi_insn *insn, unsigned int *data)
323{
324 int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
325 chan % 8;
326 unsigned long ioaddr;
327 unsigned char byte;
328
329 /* Compute ioaddr for this channel */
330 ioaddr = subpriv->iobases[byte_no];
331
332 /* NOTE:
333 writing a 0 an IO channel's bit sets the channel to INPUT
334 and pulls the line high as well
335
336 writing a 1 to an IO channel's bit pulls the line low
337
338 All channels are implicitly always in OUTPUT mode -- but when
339 they are high they can be considered to be in INPUT mode..
340
341 Thus, we only force channels low if the config request was INPUT,
342 otherwise we do nothing to the hardware. */
343
344 switch (data[0]) {
345 case INSN_CONFIG_DIO_OUTPUT:
346 /* save to io_bits -- don't actually do anything since
347 all input channels are also output channels... */
348 s->io_bits |= 1 << chan;
349 break;
350 case INSN_CONFIG_DIO_INPUT:
351 /* write a 0 to the actual register representing the channel
352 to set it to 'input'. 0 means "float high". */
353 byte = inb(ioaddr);
354 byte &= ~(1 << bit_no);
355 /**< set input channel to '0' */
356
357 /*
358 * write out byte -- this is the only time we actually affect
359 * the hardware as all channels are implicitly output
360 * -- but input channels are set to float-high
361 */
362 outb(byte, ioaddr);
363
364 /* save to io_bits */
365 s->io_bits &= ~(1 << chan);
366 break;
367
368 case INSN_CONFIG_DIO_QUERY:
369 /* retrieve from shadow register */
370 data[1] =
371 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
372 return insn->n;
373 break;
374
375 default:
376 return -EINVAL;
377 break;
378 }
379
380 return insn->n;
381}
382
383static void switch_page(struct comedi_device *dev, int asic, int page)
384{
385 struct pcmmio_private *devpriv = dev->private;
386
387 if (asic < 0 || asic >= 1)
388 return; /* paranoia */
389 if (page < 0 || page >= NUM_PAGES)
390 return; /* more paranoia */
391
392 devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
393 devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
394
395 /* now write out the shadow register */
396 outb(devpriv->asics[asic].pagelock,
397 devpriv->asics[asic].iobase + REG_PAGELOCK);
398}
399
400static void init_asics(struct comedi_device *dev)
401{ /* sets up an
402 ASIC chip to defaults */
403 struct pcmmio_private *devpriv = dev->private;
404 int asic;
405
406 for (asic = 0; asic < 1; ++asic) {
407 int port, page;
408 unsigned long baseaddr = devpriv->asics[asic].iobase;
409
410 switch_page(dev, asic, 0); /* switch back to page 0 */
411
412 /* first, clear all the DIO port bits */
413 for (port = 0; port < PORTS_PER_ASIC; ++port)
414 outb(0, baseaddr + REG_PORT0 + port);
415
416 /* Next, clear all the paged registers for each page */
417 for (page = 1; page < NUM_PAGES; ++page) {
418 int reg;
419 /* now clear all the paged registers */
420 switch_page(dev, asic, page);
421 for (reg = FIRST_PAGED_REG;
422 reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
423 outb(0, baseaddr + reg);
424 }
425
426 /* DEBUG set rising edge interrupts on port0 of both asics */
427 /*switch_page(dev, asic, PAGE_POL);
428 outb(0xff, baseaddr + REG_POL0);
429 switch_page(dev, asic, PAGE_ENAB);
430 outb(0xff, baseaddr + REG_ENAB0); */
431 /* END DEBUG */
432
433 /* switch back to default page 0 */
434 switch_page(dev, asic, 0);
435 }
436}
437
438#ifdef notused
439static void lock_port(struct comedi_device *dev, int asic, int port)
440{
441 struct pcmmio_private *devpriv = dev->private;
442
443 if (asic < 0 || asic >= 1)
444 return; /* paranoia */
445 if (port < 0 || port >= PORTS_PER_ASIC)
446 return; /* more paranoia */
447
448 devpriv->asics[asic].pagelock |= 0x1 << port;
449 /* now write out the shadow register */
450 outb(devpriv->asics[asic].pagelock,
451 devpriv->asics[asic].iobase + REG_PAGELOCK);
452 return;
453}
454
455static void unlock_port(struct comedi_device *dev, int asic, int port)
456{
457 struct pcmmio_private *devpriv = dev->private;
458
459 if (asic < 0 || asic >= 1)
460 return; /* paranoia */
461 if (port < 0 || port >= PORTS_PER_ASIC)
462 return; /* more paranoia */
463 devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
464 /* now write out the shadow register */
465 outb(devpriv->asics[asic].pagelock,
466 devpriv->asics[asic].iobase + REG_PAGELOCK);
467}
468#endif /* notused */
469
470static void pcmmio_stop_intr(struct comedi_device *dev,
471 struct comedi_subdevice *s)
472{
473 struct pcmmio_private *devpriv = dev->private;
474 int nports, firstport, asic, port;
475
476 asic = subpriv->dio.intr.asic;
477 if (asic < 0)
478 return; /* not an interrupt subdev */
479
480 subpriv->dio.intr.enabled_mask = 0;
481 subpriv->dio.intr.active = 0;
482 s->async->inttrig = NULL;
483 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
484 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
485 switch_page(dev, asic, PAGE_ENAB);
486 for (port = firstport; port < firstport + nports; ++port) {
487 /* disable all intrs for this subdev.. */
488 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
489 }
490}
491
492static irqreturn_t interrupt_pcmmio(int irq, void *d)
493{
494 int asic, got1 = 0;
495 struct comedi_device *dev = (struct comedi_device *)d;
496 struct pcmmio_private *devpriv = dev->private;
497 int i;
498
499 for (asic = 0; asic < MAX_ASICS; ++asic) {
500 if (irq == devpriv->asics[asic].irq) {
501 unsigned long flags;
502 unsigned triggered = 0;
503 unsigned long iobase = devpriv->asics[asic].iobase;
504 /* it is an interrupt for ASIC #asic */
505 unsigned char int_pend;
506
507 spin_lock_irqsave(&devpriv->asics[asic].spinlock,
508 flags);
509
510 int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
511
512 if (int_pend) {
513 int port;
514 for (port = 0; port < INTR_PORTS_PER_ASIC;
515 ++port) {
516 if (int_pend & (0x1 << port)) {
517 unsigned char
518 io_lines_with_edges = 0;
519 switch_page(dev, asic,
520 PAGE_INT_ID);
521 io_lines_with_edges =
522 inb(iobase +
523 REG_INT_ID0 + port);
524
525 if (io_lines_with_edges)
526 /*
527 * clear pending
528 * interrupt
529 */
530 outb(0, iobase +
531 REG_INT_ID0 +
532 port);
533
534 triggered |=
535 io_lines_with_edges <<
536 port * 8;
537 }
538 }
539
540 ++got1;
541 }
542
543 spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
544 flags);
545
546 if (triggered) {
547 struct comedi_subdevice *s;
548 /*
549 * TODO here: dispatch io lines to subdevs
550 * with commands..
551 */
552 printk
553 (KERN_DEBUG "got edge detect interrupt %d asic %d which_chans: %06x\n",
554 irq, asic, triggered);
555 for (i = 2; i < dev->n_subdevices; i++) {
556 s = &dev->subdevices[i];
557 /*
558 * this is an interrupt subdev,
559 * and it matches this asic!
560 */
561 if (subpriv->dio.intr.asic == asic) {
562 unsigned long flags;
563 unsigned oldevents;
564
565 spin_lock_irqsave(&subpriv->dio.
566 intr.spinlock,
567 flags);
568
569 oldevents = s->async->events;
570
571 if (subpriv->dio.intr.active) {
572 unsigned mytrig =
573 ((triggered >>
574 subpriv->dio.intr.asic_chan)
575 &
576 ((0x1 << subpriv->
577 dio.intr.
578 num_asic_chans) -
579 1)) << subpriv->
580 dio.intr.first_chan;
581 if (mytrig &
582 subpriv->dio.
583 intr.enabled_mask) {
584 unsigned int val
585 = 0;
586 unsigned int n,
587 ch, len;
588
589 len =
590 s->
591 async->cmd.chanlist_len;
592 for (n = 0;
593 n < len;
594 n++) {
595 ch = CR_CHAN(s->async->cmd.chanlist[n]);
596 if (mytrig & (1U << ch))
597 val |= (1U << n);
598 }
599 /* Write the scan to the buffer. */
600 if (comedi_buf_put(s->async, ((short *)&val)[0])
601 &&
602 comedi_buf_put
603 (s->async,
604 ((short *)
605 &val)[1])) {
606 s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
607 } else {
608 /* Overflow! Stop acquisition!! */
609 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
610 pcmmio_stop_intr
611 (dev,
612 s);
613 }
614
615 /* Check for end of acquisition. */
616 if (!subpriv->dio.intr.continuous) {
617 /* stop_src == TRIG_COUNT */
618 if (subpriv->dio.intr.stop_count > 0) {
619 subpriv->dio.intr.stop_count--;
620 if (subpriv->dio.intr.stop_count == 0) {
621 s->async->events |= COMEDI_CB_EOA;
622 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
623 pcmmio_stop_intr
624 (dev,
625 s);
626 }
627 }
628 }
629 }
630 }
631
632 spin_unlock_irqrestore
633 (&subpriv->dio.intr.
634 spinlock, flags);
635
636 if (oldevents !=
637 s->async->events) {
638 comedi_event(dev, s);
639 }
640
641 }
642
643 }
644 }
645
646 }
647 }
648 if (!got1)
649 return IRQ_NONE; /* interrupt from other source */
650 return IRQ_HANDLED;
651}
652
653static int pcmmio_start_intr(struct comedi_device *dev,
654 struct comedi_subdevice *s)
655{
656 struct pcmmio_private *devpriv = dev->private;
657
658 if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
659 /* An empty acquisition! */
660 s->async->events |= COMEDI_CB_EOA;
661 subpriv->dio.intr.active = 0;
662 return 1;
663 } else {
664 unsigned bits = 0, pol_bits = 0, n;
665 int nports, firstport, asic, port;
666 struct comedi_cmd *cmd = &s->async->cmd;
667
668 asic = subpriv->dio.intr.asic;
669 if (asic < 0)
670 return 1; /* not an interrupt
671 subdev */
672 subpriv->dio.intr.enabled_mask = 0;
673 subpriv->dio.intr.active = 1;
674 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
675 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
676 if (cmd->chanlist) {
677 for (n = 0; n < cmd->chanlist_len; n++) {
678 bits |= (1U << CR_CHAN(cmd->chanlist[n]));
679 pol_bits |= (CR_AREF(cmd->chanlist[n])
680 || CR_RANGE(cmd->
681 chanlist[n]) ? 1U : 0U)
682 << CR_CHAN(cmd->chanlist[n]);
683 }
684 }
685 bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
686 1) << subpriv->dio.intr.first_chan;
687 subpriv->dio.intr.enabled_mask = bits;
688
689 {
690 /*
691 * the below code configures the board
692 * to use a specific IRQ from 0-15.
693 */
694 unsigned char b;
695 /*
696 * set resource enable register
697 * to enable IRQ operation
698 */
699 outb(1 << 4, dev->iobase + 3);
700 /* set bits 0-3 of b to the irq number from 0-15 */
701 b = dev->irq & ((1 << 4) - 1);
702 outb(b, dev->iobase + 2);
703 /* done, we told the board what irq to use */
704 }
705
706 switch_page(dev, asic, PAGE_ENAB);
707 for (port = firstport; port < firstport + nports; ++port) {
708 unsigned enab =
709 bits >> (subpriv->dio.intr.first_chan + (port -
710 firstport)
711 * 8) & 0xff, pol =
712 pol_bits >> (subpriv->dio.intr.first_chan +
713 (port - firstport) * 8) & 0xff;
714 /* set enab intrs for this subdev.. */
715 outb(enab,
716 devpriv->asics[asic].iobase + REG_ENAB0 + port);
717 switch_page(dev, asic, PAGE_POL);
718 outb(pol,
719 devpriv->asics[asic].iobase + REG_ENAB0 + port);
720 }
721 }
722 return 0;
723}
724
725static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
726{
727 unsigned long flags;
728
729 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
730 if (subpriv->dio.intr.active)
731 pcmmio_stop_intr(dev, s);
732 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
733
734 return 0;
735}
736
737/*
738 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
739 */
740static int
741pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
742 unsigned int trignum)
743{
744 unsigned long flags;
745 int event = 0;
746
747 if (trignum != 0)
748 return -EINVAL;
749
750 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
751 s->async->inttrig = NULL;
752 if (subpriv->dio.intr.active)
753 event = pcmmio_start_intr(dev, s);
754 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
755
756 if (event)
757 comedi_event(dev, s);
758
759 return 1;
760}
761
762/*
763 * 'do_cmd' function for an 'INTERRUPT' subdevice.
764 */
765static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
766{
767 struct comedi_cmd *cmd = &s->async->cmd;
768 unsigned long flags;
769 int event = 0;
770
771 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
772 subpriv->dio.intr.active = 1;
773
774 /* Set up end of acquisition. */
775 switch (cmd->stop_src) {
776 case TRIG_COUNT:
777 subpriv->dio.intr.continuous = 0;
778 subpriv->dio.intr.stop_count = cmd->stop_arg;
779 break;
780 default:
781 /* TRIG_NONE */
782 subpriv->dio.intr.continuous = 1;
783 subpriv->dio.intr.stop_count = 0;
784 break;
785 }
786
787 /* Set up start of acquisition. */
788 switch (cmd->start_src) {
789 case TRIG_INT:
790 s->async->inttrig = pcmmio_inttrig_start_intr;
791 break;
792 default:
793 /* TRIG_NOW */
794 event = pcmmio_start_intr(dev, s);
795 break;
796 }
797 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
798
799 if (event)
800 comedi_event(dev, s);
801
802 return 0;
803}
804
805static int
806pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
807 struct comedi_cmd *cmd)
808{
809 return comedi_pcm_cmdtest(dev, s, cmd);
810}
811
812static int adc_wait_ready(unsigned long iobase)
813{
814 unsigned long retry = 100000;
815 while (retry--)
816 if (inb(iobase + 3) & 0x80)
817 return 0;
818 return 1;
819}
820
821/* All this is for AI and AO */
822static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
823 struct comedi_insn *insn, unsigned int *data)
824{
825 int n;
826 unsigned long iobase = subpriv->iobase;
827
828 /*
829 1. write the CMD byte (to BASE+2)
830 2. read junk lo byte (BASE+0)
831 3. read junk hi byte (BASE+1)
832 4. (mux settled so) write CMD byte again (BASE+2)
833 5. read valid lo byte(BASE+0)
834 6. read valid hi byte(BASE+1)
835
836 Additionally note that the BASE += 4 if the channel >= 8
837 */
838
839 /* convert n samples */
840 for (n = 0; n < insn->n; n++) {
841 unsigned chan = CR_CHAN(insn->chanspec), range =
842 CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
843 unsigned char command_byte = 0;
844 unsigned iooffset = 0;
845 short sample, adc_adjust = 0;
846
847 if (chan > 7)
848 chan -= 8, iooffset = 4; /*
849 * use the second dword
850 * for channels > 7
851 */
852
853 if (aref != AREF_DIFF) {
854 aref = AREF_GROUND;
855 command_byte |= 1 << 7; /*
856 * set bit 7 to indicate
857 * single-ended
858 */
859 }
860 if (range < 2)
861 adc_adjust = 0x8000; /*
862 * bipolar ranges
863 * (-5,5 .. -10,10 need to be
864 * adjusted -- that is.. they
865 * need to wrap around by
866 * adding 0x8000
867 */
868
869 if (chan % 2) {
870 command_byte |= 1 << 6; /*
871 * odd-numbered channels
872 * have bit 6 set
873 */
874 }
875
876 /* select the channel, bits 4-5 == chan/2 */
877 command_byte |= ((chan / 2) & 0x3) << 4;
878
879 /* set the range, bits 2-3 */
880 command_byte |= (range & 0x3) << 2;
881
882 /* need to do this twice to make sure mux settled */
883 /* chan/range/aref select */
884 outb(command_byte, iobase + iooffset + 2);
885
886 /* wait for the adc to say it finised the conversion */
887 adc_wait_ready(iobase + iooffset);
888
889 /* select the chan/range/aref AGAIN */
890 outb(command_byte, iobase + iooffset + 2);
891
892 adc_wait_ready(iobase + iooffset);
893
894 /* read data lo byte */
895 sample = inb(iobase + iooffset + 0);
896
897 /* read data hi byte */
898 sample |= inb(iobase + iooffset + 1) << 8;
899 sample += adc_adjust; /* adjustment .. munge data */
900 data[n] = sample;
901 }
902 /* return the number of samples read/written */
903 return n;
904}
905
906static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
907 struct comedi_insn *insn, unsigned int *data)
908{
909 int n;
910 for (n = 0; n < insn->n; n++) {
911 unsigned chan = CR_CHAN(insn->chanspec);
912 if (chan < s->n_chan)
913 data[n] = subpriv->ao.shadow_samples[chan];
914 }
915 return n;
916}
917
918static int wait_dac_ready(unsigned long iobase)
919{
920 unsigned long retry = 100000L;
921
922 /* This may seem like an absurd way to handle waiting and violates the
923 "no busy waiting" policy. The fact is that the hardware is
924 normally so fast that we usually only need one time through the loop
925 anyway. The longer timeout is for rare occasions and for detecting
926 non-existent hardware. */
927
928 while (retry--) {
929 if (inb(iobase + 3) & 0x80)
930 return 0;
931
932 }
933 return 1;
934}
935
936static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
937 struct comedi_insn *insn, unsigned int *data)
938{
939 int n;
940 unsigned iobase = subpriv->iobase, iooffset = 0;
941
942 for (n = 0; n < insn->n; n++) {
943 unsigned chan = CR_CHAN(insn->chanspec), range =
944 CR_RANGE(insn->chanspec);
945 if (chan < s->n_chan) {
946 unsigned char command_byte = 0, range_byte =
947 range & ((1 << 4) - 1);
948 if (chan >= 4)
949 chan -= 4, iooffset += 4;
950 /* set the range.. */
951 outb(range_byte, iobase + iooffset + 0);
952 outb(0, iobase + iooffset + 1);
953
954 /* tell it to begin */
955 command_byte = (chan << 1) | 0x60;
956 outb(command_byte, iobase + iooffset + 2);
957
958 wait_dac_ready(iobase + iooffset);
959
960 /* low order byte */
961 outb(data[n] & 0xff, iobase + iooffset + 0);
962
963 /* high order byte */
964 outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
965
966 /*
967 * set bit 4 of command byte to indicate
968 * data is loaded and trigger conversion
969 */
970 command_byte = 0x70 | (chan << 1);
971 /* trigger converion */
972 outb(command_byte, iobase + iooffset + 2);
973
974 wait_dac_ready(iobase + iooffset);
975
976 /* save to shadow register for ao_rinsn */
977 subpriv->ao.shadow_samples[chan] = data[n];
978 }
979 }
980 return n;
981}
982
983static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
984{
985 struct pcmmio_private *devpriv;
986 struct comedi_subdevice *s;
987 int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
988 thisasic_chanct = 0;
989 unsigned long iobase;
990 unsigned int irq[MAX_ASICS];
991 int ret;
992
993 dev->board_name = dev->driver->driver_name;
994
995 iobase = it->options[0];
996 irq[0] = it->options[1];
997
998 printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
999 dev->board_name, iobase);
1000
1001 dev->iobase = iobase;
1002
1003 if (!iobase || !request_region(iobase, 32, dev->board_name)) {
1004 printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
1005 return -EIO;
1006 }
1007
1008 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1009 if (!devpriv)
1010 return -ENOMEM;
1011 dev->private = devpriv;
1012
1013 for (asic = 0; asic < MAX_ASICS; ++asic) {
1014 devpriv->asics[asic].num = asic;
1015 devpriv->asics[asic].iobase =
1016 dev->iobase + 16 + asic * ASIC_IOSIZE;
1017 /*
1018 * this gets actually set at the end of this function when we
1019 * request_irqs
1020 */
1021 devpriv->asics[asic].irq = 0;
1022 spin_lock_init(&devpriv->asics[asic].spinlock);
1023 }
1024
1025 chans_left = CHANS_PER_ASIC * 1;
1026 n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
1027 n_subdevs = n_dio_subdevs + 2;
1028 devpriv->sprivs =
1029 kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
1030 GFP_KERNEL);
1031 if (!devpriv->sprivs) {
1032 printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
1033 dev->minor);
1034 return -ENOMEM;
1035 }
1036
1037 ret = comedi_alloc_subdevices(dev, n_subdevs);
1038 if (ret)
1039 return ret;
1040
1041 /* First, AI */
1042 s = &dev->subdevices[0];
1043 s->private = &devpriv->sprivs[0];
1044 s->maxdata = 0xffff;
1045 s->range_table = &ranges_ai;
1046 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
1047 s->type = COMEDI_SUBD_AI;
1048 s->n_chan = 16;
1049 s->len_chanlist = s->n_chan;
1050 s->insn_read = ai_rinsn;
1051 subpriv->iobase = dev->iobase + 0;
1052 /* initialize the resource enable register by clearing it */
1053 outb(0, subpriv->iobase + 3);
1054 outb(0, subpriv->iobase + 4 + 3);
1055
1056 /* Next, AO */
1057 s = &dev->subdevices[1];
1058 s->private = &devpriv->sprivs[1];
1059 s->maxdata = 0xffff;
1060 s->range_table = &ranges_ao;
1061 s->subdev_flags = SDF_READABLE;
1062 s->type = COMEDI_SUBD_AO;
1063 s->n_chan = 8;
1064 s->len_chanlist = s->n_chan;
1065 s->insn_read = ao_rinsn;
1066 s->insn_write = ao_winsn;
1067 subpriv->iobase = dev->iobase + 8;
1068 /* initialize the resource enable register by clearing it */
1069 outb(0, subpriv->iobase + 3);
1070 outb(0, subpriv->iobase + 4 + 3);
1071
1072 port = 0;
1073 asic = 0;
1074 for (sdev_no = 2; sdev_no < dev->n_subdevices; ++sdev_no) {
1075 int byte_no;
1076
1077 s = &dev->subdevices[sdev_no];
1078 s->private = &devpriv->sprivs[sdev_no];
1079 s->maxdata = 1;
1080 s->range_table = &range_digital;
1081 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1082 s->type = COMEDI_SUBD_DIO;
1083 s->insn_bits = pcmmio_dio_insn_bits;
1084 s->insn_config = pcmmio_dio_insn_config;
1085 s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
1086 subpriv->dio.intr.asic = -1;
1087 subpriv->dio.intr.first_chan = -1;
1088 subpriv->dio.intr.asic_chan = -1;
1089 subpriv->dio.intr.num_asic_chans = -1;
1090 subpriv->dio.intr.active = 0;
1091 s->len_chanlist = 1;
1092
1093 /* save the ioport address for each 'port' of 8 channels in the
1094 subdevice */
1095 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
1096 if (port >= PORTS_PER_ASIC) {
1097 port = 0;
1098 ++asic;
1099 thisasic_chanct = 0;
1100 }
1101 subpriv->iobases[byte_no] =
1102 devpriv->asics[asic].iobase + port;
1103
1104 if (thisasic_chanct <
1105 CHANS_PER_PORT * INTR_PORTS_PER_ASIC
1106 && subpriv->dio.intr.asic < 0) {
1107 /*
1108 * this is an interrupt subdevice,
1109 * so setup the struct
1110 */
1111 subpriv->dio.intr.asic = asic;
1112 subpriv->dio.intr.active = 0;
1113 subpriv->dio.intr.stop_count = 0;
1114 subpriv->dio.intr.first_chan = byte_no * 8;
1115 subpriv->dio.intr.asic_chan = thisasic_chanct;
1116 subpriv->dio.intr.num_asic_chans =
1117 s->n_chan - subpriv->dio.intr.first_chan;
1118 s->cancel = pcmmio_cancel;
1119 s->do_cmd = pcmmio_cmd;
1120 s->do_cmdtest = pcmmio_cmdtest;
1121 s->len_chanlist =
1122 subpriv->dio.intr.num_asic_chans;
1123 }
1124 thisasic_chanct += CHANS_PER_PORT;
1125 }
1126 spin_lock_init(&subpriv->dio.intr.spinlock);
1127
1128 chans_left -= s->n_chan;
1129
1130 if (!chans_left) {
1131 /*
1132 * reset the asic to our first asic,
1133 * to do intr subdevs
1134 */
1135 asic = 0;
1136 port = 0;
1137 }
1138
1139 }
1140
1141 init_asics(dev); /* clear out all the registers, basically */
1142
1143 for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
1144 if (irq[asic]
1145 && request_irq(irq[asic], interrupt_pcmmio,
1146 IRQF_SHARED, dev->board_name, dev)) {
1147 int i;
1148 /* unroll the allocated irqs.. */
1149 for (i = asic - 1; i >= 0; --i) {
1150 free_irq(irq[i], dev);
1151 devpriv->asics[i].irq = irq[i] = 0;
1152 }
1153 irq[asic] = 0;
1154 }
1155 devpriv->asics[asic].irq = irq[asic];
1156 }
1157
1158 dev->irq = irq[0]; /*
1159 * grr.. wish comedi dev struct supported
1160 * multiple irqs..
1161 */
1162
1163 printk(KERN_INFO "comedi%d: attached\n", dev->minor);
1164
1165 return 1;
1166}
1167
1168static void pcmmio_detach(struct comedi_device *dev)
1169{
1170 struct pcmmio_private *devpriv = dev->private;
1171 int i;
1172
1173 if (dev->iobase)
1174 release_region(dev->iobase, 32);
1175 for (i = 0; i < MAX_ASICS; ++i) {
1176 if (devpriv && devpriv->asics[i].irq)
1177 free_irq(devpriv->asics[i].irq, dev);
1178 }
1179 if (devpriv && devpriv->sprivs)
1180 kfree(devpriv->sprivs);
1181}
1182
1183static struct comedi_driver pcmmio_driver = {
1184 .driver_name = "pcmmio",
1185 .module = THIS_MODULE,
1186 .attach = pcmmio_attach,
1187 .detach = pcmmio_detach,
1188};
1189module_comedi_driver(pcmmio_driver);
1190
1191MODULE_AUTHOR("Comedi http://www.comedi.org");
1192MODULE_DESCRIPTION("Comedi low-level driver");
1193MODULE_LICENSE("GPL");
This page took 0.027778 seconds and 5 git commands to generate.