staging: comedi: remove inline alloc_private()
[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
d2d08955
DPJ
148static const struct comedi_lrange ranges_ai = {
149 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)}
6baef150
CC
150};
151
d2d08955
DPJ
152static const struct comedi_lrange ranges_ao = {
153 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
0a85b6f0 154 RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
6baef150
CC
155};
156
6baef150 157/* this structure is for data unique to this subdevice. */
4467df94 158struct pcmmio_subdev_private {
6baef150
CC
159
160 union {
d2d08955
DPJ
161 /* for DIO: mapping of halfwords (bytes)
162 in port/chanarray to iobase */
6baef150
CC
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 {
d2d08955
DPJ
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;
6baef150
CC
198 int active;
199 int stop_count;
200 int continuous;
201 spinlock_t spinlock;
202 } intr;
203 } dio;
204 struct {
d2d08955
DPJ
205 /* the last unsigned int data written */
206 unsigned int shadow_samples[8];
6baef150
CC
207 } ao;
208 };
4467df94 209};
6baef150 210
d2d08955
DPJ
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 */
e56ab715 216struct pcmmio_private {
6baef150
CC
217 /* stuff for DIO */
218 struct {
219 unsigned char pagelock; /* current page and lock */
d2d08955
DPJ
220 /* shadow of POLx registers */
221 unsigned char pol[NUM_PAGED_REGS];
222 /* shadow of ENABx registers */
223 unsigned char enab[NUM_PAGED_REGS];
6baef150
CC
224 int num;
225 unsigned long iobase;
226 unsigned int irq;
227 spinlock_t spinlock;
228 } asics[MAX_ASICS];
4467df94 229 struct pcmmio_subdev_private *sprivs;
e56ab715 230};
6baef150 231
4467df94 232#define subpriv ((struct pcmmio_subdev_private *)s->private)
6baef150
CC
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 */
0a85b6f0
MT
239static int pcmmio_dio_insn_bits(struct comedi_device *dev,
240 struct comedi_subdevice *s,
241 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
242{
243 int byte_no;
6baef150
CC
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 */
bcd9a1e9 258 printk(KERN_DEBUG "write mask: %08x data: %08x\n", data[0], data[1]);
6baef150
CC
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],
0a85b6f0
MT
266 /* bit offset of port in 32-bit doubleword */
267 offset = byte_no * 8;
6baef150
CC
268 /* this 8-bit port's data */
269 unsigned char byte = 0,
0a85b6f0
MT
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;
6baef150
CC
274
275 byte = inb(ioaddr); /* read all 8-bits for this port */
276
277#ifdef DAMMIT_ITS_BROKEN
278 /* DEBUG */
0a85b6f0 279 printk
bcd9a1e9
JT
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);
6baef150
CC
283#endif
284
285 if (write_mask_byte) {
d2d08955
DPJ
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;
6baef150
CC
294 /* Write out the new digital output state */
295 outb(byte, ioaddr);
296 }
297#ifdef DAMMIT_ITS_BROKEN
298 /* DEBUG */
6a857636 299 printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte);
6baef150
CC
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 */
bcd9a1e9 310 printk(KERN_DEBUG "s->state %08x data_out %08x\n", s->state, data[1]);
6baef150
CC
311#endif
312
a2714e3e 313 return insn->n;
6baef150
CC
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. */
0a85b6f0
MT
320static int pcmmio_dio_insn_config(struct comedi_device *dev,
321 struct comedi_subdevice *s,
322 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
323{
324 int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
0a85b6f0 325 chan % 8;
6baef150
CC
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
013f230c
DPJ
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 */
6baef150
CC
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:
25985edc 369 /* retrieve from shadow register */
6baef150 370 data[1] =
0a85b6f0 371 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
6baef150
CC
372 return insn->n;
373 break;
374
375 default:
376 return -EINVAL;
377 break;
378 }
379
380 return insn->n;
381}
382
b2bb98e1
HS
383static void switch_page(struct comedi_device *dev, int asic, int page)
384{
9a1a6cf8
HS
385 struct pcmmio_private *devpriv = dev->private;
386
16339125 387 if (asic < 0 || asic >= 1)
b2bb98e1
HS
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
da91b269 400static void init_asics(struct comedi_device *dev)
6baef150
CC
401{ /* sets up an
402 ASIC chip to defaults */
9a1a6cf8 403 struct pcmmio_private *devpriv = dev->private;
6baef150
CC
404 int asic;
405
16339125 406 for (asic = 0; asic < 1; ++asic) {
6baef150
CC
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;
0a85b6f0 422 reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
6baef150
CC
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
013f230c
DPJ
433 /* switch back to default page 0 */
434 switch_page(dev, asic, 0);
6baef150
CC
435 }
436}
437
6baef150 438#ifdef notused
da91b269 439static void lock_port(struct comedi_device *dev, int asic, int port)
6baef150 440{
9a1a6cf8
HS
441 struct pcmmio_private *devpriv = dev->private;
442
16339125 443 if (asic < 0 || asic >= 1)
6baef150
CC
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,
0a85b6f0 451 devpriv->asics[asic].iobase + REG_PAGELOCK);
6baef150
CC
452 return;
453}
454
da91b269 455static void unlock_port(struct comedi_device *dev, int asic, int port)
6baef150 456{
9a1a6cf8
HS
457 struct pcmmio_private *devpriv = dev->private;
458
16339125 459 if (asic < 0 || asic >= 1)
6baef150
CC
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,
0a85b6f0 466 devpriv->asics[asic].iobase + REG_PAGELOCK);
6baef150
CC
467}
468#endif /* notused */
469
b2bb98e1
HS
470static void pcmmio_stop_intr(struct comedi_device *dev,
471 struct comedi_subdevice *s)
472{
9a1a6cf8 473 struct pcmmio_private *devpriv = dev->private;
b2bb98e1
HS
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;
76728a93 482 s->async->inttrig = NULL;
b2bb98e1
HS
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
70265d24 492static irqreturn_t interrupt_pcmmio(int irq, void *d)
6baef150
CC
493{
494 int asic, got1 = 0;
0a85b6f0 495 struct comedi_device *dev = (struct comedi_device *)d;
9a1a6cf8 496 struct pcmmio_private *devpriv = dev->private;
33e101ad 497 int i;
6baef150
CC
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
0a85b6f0
MT
507 spin_lock_irqsave(&devpriv->asics[asic].spinlock,
508 flags);
6baef150
CC
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;
0a85b6f0 515 ++port) {
6baef150
CC
516 if (int_pend & (0x1 << port)) {
517 unsigned char
0a85b6f0 518 io_lines_with_edges = 0;
6baef150 519 switch_page(dev, asic,
0a85b6f0 520 PAGE_INT_ID);
6baef150 521 io_lines_with_edges =
0a85b6f0 522 inb(iobase +
6baef150
CC
523 REG_INT_ID0 + port);
524
525 if (io_lines_with_edges)
013f230c
DPJ
526 /*
527 * clear pending
528 * interrupt
529 */
6baef150 530 outb(0, iobase +
0a85b6f0
MT
531 REG_INT_ID0 +
532 port);
6baef150
CC
533
534 triggered |=
0a85b6f0
MT
535 io_lines_with_edges <<
536 port * 8;
6baef150
CC
537 }
538 }
539
540 ++got1;
541 }
542
0a85b6f0
MT
543 spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
544 flags);
6baef150
CC
545
546 if (triggered) {
34c43922 547 struct comedi_subdevice *s;
013f230c
DPJ
548 /*
549 * TODO here: dispatch io lines to subdevs
550 * with commands..
551 */
0a85b6f0 552 printk
bcd9a1e9 553 (KERN_DEBUG "got edge detect interrupt %d asic %d which_chans: %06x\n",
0a85b6f0 554 irq, asic, triggered);
33e101ad
HS
555 for (i = 2; i < dev->n_subdevices; i++) {
556 s = &dev->subdevices[i];
013f230c
DPJ
557 /*
558 * this is an interrupt subdev,
559 * and it matches this asic!
560 */
561 if (subpriv->dio.intr.asic == asic) {
6baef150
CC
562 unsigned long flags;
563 unsigned oldevents;
564
0a85b6f0
MT
565 spin_lock_irqsave(&subpriv->dio.
566 intr.spinlock,
567 flags);
6baef150
CC
568
569 oldevents = s->async->events;
570
571 if (subpriv->dio.intr.active) {
572 unsigned mytrig =
0a85b6f0
MT
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;
6baef150 586 unsigned int n,
0a85b6f0 587 ch, len;
6baef150 588
0a85b6f0
MT
589 len =
590 s->
591 async->cmd.chanlist_len;
6baef150 592 for (n = 0;
0a85b6f0
MT
593 n < len;
594 n++) {
6baef150 595 ch = CR_CHAN(s->async->cmd.chanlist[n]);
013f230c 596 if (mytrig & (1U << ch))
6baef150 597 val |= (1U << n);
6baef150
CC
598 }
599 /* Write the scan to the buffer. */
0a85b6f0
MT
600 if (comedi_buf_put(s->async, ((short *)&val)[0])
601 &&
602 comedi_buf_put
603 (s->async,
604 ((short *)
013f230c 605 &val)[1])) {
6baef150
CC
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
0a85b6f0
MT
611 (dev,
612 s);
6baef150
CC
613 }
614
615 /* Check for end of acquisition. */
0a85b6f0 616 if (!subpriv->dio.intr.continuous) {
6baef150
CC
617 /* stop_src == TRIG_COUNT */
618 if (subpriv->dio.intr.stop_count > 0) {
0a85b6f0 619 subpriv->dio.intr.stop_count--;
6baef150
CC
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
0a85b6f0
MT
624 (dev,
625 s);
6baef150
CC
626 }
627 }
628 }
629 }
630 }
631
0a85b6f0
MT
632 spin_unlock_irqrestore
633 (&subpriv->dio.intr.
634 spinlock, flags);
6baef150
CC
635
636 if (oldevents !=
0a85b6f0 637 s->async->events) {
6baef150
CC
638 comedi_event(dev, s);
639 }
640
641 }
642
b2bb98e1
HS
643 }
644 }
645
646 }
6baef150 647 }
b2bb98e1
HS
648 if (!got1)
649 return IRQ_NONE; /* interrupt from other source */
650 return IRQ_HANDLED;
6baef150
CC
651}
652
0a85b6f0
MT
653static int pcmmio_start_intr(struct comedi_device *dev,
654 struct comedi_subdevice *s)
6baef150 655{
9a1a6cf8
HS
656 struct pcmmio_private *devpriv = dev->private;
657
6baef150
CC
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;
ea6d0d4c 666 struct comedi_cmd *cmd = &s->async->cmd;
6baef150 667
c3744138 668 asic = subpriv->dio.intr.asic;
0a85b6f0 669 if (asic < 0)
6baef150
CC
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])
0a85b6f0
MT
680 || CR_RANGE(cmd->
681 chanlist[n]) ? 1U : 0U)
682 << CR_CHAN(cmd->chanlist[n]);
6baef150
CC
683 }
684 }
685 bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
0a85b6f0 686 1) << subpriv->dio.intr.first_chan;
6baef150
CC
687 subpriv->dio.intr.enabled_mask = bits;
688
013f230c
DPJ
689 {
690 /*
691 * the below code configures the board
692 * to use a specific IRQ from 0-15.
693 */
6baef150 694 unsigned char b;
013f230c
DPJ
695 /*
696 * set resource enable register
697 * to enable IRQ operation
698 */
6baef150
CC
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 =
0a85b6f0
MT
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;
6baef150
CC
714 /* set enab intrs for this subdev.. */
715 outb(enab,
0a85b6f0 716 devpriv->asics[asic].iobase + REG_ENAB0 + port);
6baef150
CC
717 switch_page(dev, asic, PAGE_POL);
718 outb(pol,
0a85b6f0 719 devpriv->asics[asic].iobase + REG_ENAB0 + port);
6baef150
CC
720 }
721 }
722 return 0;
723}
724
da91b269 725static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
6baef150
CC
726{
727 unsigned long flags;
728
5f74ea14 729 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
6baef150
CC
730 if (subpriv->dio.intr.active)
731 pcmmio_stop_intr(dev, s);
5f74ea14 732 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
6baef150
CC
733
734 return 0;
735}
736
737/*
738 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
739 */
740static int
da91b269 741pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 742 unsigned int trignum)
6baef150
CC
743{
744 unsigned long flags;
745 int event = 0;
746
747 if (trignum != 0)
748 return -EINVAL;
749
5f74ea14 750 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
76728a93 751 s->async->inttrig = NULL;
013f230c 752 if (subpriv->dio.intr.active)
6baef150 753 event = pcmmio_start_intr(dev, s);
5f74ea14 754 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
6baef150 755
013f230c 756 if (event)
6baef150 757 comedi_event(dev, s);
6baef150
CC
758
759 return 1;
760}
761
762/*
763 * 'do_cmd' function for an 'INTERRUPT' subdevice.
764 */
da91b269 765static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
6baef150 766{
ea6d0d4c 767 struct comedi_cmd *cmd = &s->async->cmd;
6baef150
CC
768 unsigned long flags;
769 int event = 0;
770
5f74ea14 771 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
6baef150
CC
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 }
5f74ea14 797 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
6baef150 798
013f230c 799 if (event)
6baef150 800 comedi_event(dev, s);
6baef150
CC
801
802 return 0;
803}
804
6baef150 805static int
0a85b6f0
MT
806pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
807 struct comedi_cmd *cmd)
6baef150 808{
0b8f754a 809 return comedi_pcm_cmdtest(dev, s, cmd);
6baef150
CC
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 */
da91b269 822static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 823 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
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 =
0a85b6f0 842 CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
6baef150
CC
843 unsigned char command_byte = 0;
844 unsigned iooffset = 0;
790c5541 845 short sample, adc_adjust = 0;
6baef150
CC
846
847 if (chan > 7)
013f230c
DPJ
848 chan -= 8, iooffset = 4; /*
849 * use the second dword
850 * for channels > 7
851 */
6baef150
CC
852
853 if (aref != AREF_DIFF) {
854 aref = AREF_GROUND;
013f230c
DPJ
855 command_byte |= 1 << 7; /*
856 * set bit 7 to indicate
857 * single-ended
858 */
6baef150
CC
859 }
860 if (range < 2)
013f230c
DPJ
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 */
6baef150
CC
868
869 if (chan % 2) {
013f230c
DPJ
870 command_byte |= 1 << 6; /*
871 * odd-numbered channels
872 * have bit 6 set
873 */
6baef150
CC
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 */
013f230c
DPJ
883 /* chan/range/aref select */
884 outb(command_byte, iobase + iooffset + 2);
6baef150 885
013f230c
DPJ
886 /* wait for the adc to say it finised the conversion */
887 adc_wait_ready(iobase + iooffset);
6baef150 888
013f230c
DPJ
889 /* select the chan/range/aref AGAIN */
890 outb(command_byte, iobase + iooffset + 2);
6baef150
CC
891
892 adc_wait_ready(iobase + iooffset);
893
013f230c
DPJ
894 /* read data lo byte */
895 sample = inb(iobase + iooffset + 0);
896
897 /* read data hi byte */
898 sample |= inb(iobase + iooffset + 1) << 8;
6baef150
CC
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
da91b269 906static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 907 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
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
25985edc 926 non-existent hardware. */
6baef150
CC
927
928 while (retry--) {
929 if (inb(iobase + 3) & 0x80)
930 return 0;
931
932 }
933 return 1;
934}
935
da91b269 936static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 937 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
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 =
0a85b6f0 944 CR_RANGE(insn->chanspec);
6baef150
CC
945 if (chan < s->n_chan) {
946 unsigned char command_byte = 0, range_byte =
0a85b6f0 947 range & ((1 << 4) - 1);
6baef150
CC
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
013f230c
DPJ
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);
6baef150
CC
971 /* trigger converion */
972 outb(command_byte, iobase + iooffset + 2);
973
974 wait_dac_ready(iobase + iooffset);
975
013f230c
DPJ
976 /* save to shadow register for ao_rinsn */
977 subpriv->ao.shadow_samples[chan] = data[n];
6baef150
CC
978 }
979 }
980 return n;
981}
982
b2bb98e1
HS
983static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
984{
9a1a6cf8 985 struct pcmmio_private *devpriv;
b2bb98e1
HS
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];
8b6c5694 991 int ret;
b2bb98e1 992
16339125
HS
993 dev->board_name = dev->driver->driver_name;
994
b2bb98e1
HS
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,
16339125 999 dev->board_name, iobase);
b2bb98e1
HS
1000
1001 dev->iobase = iobase;
1002
16339125 1003 if (!iobase || !request_region(iobase, 32, dev->board_name)) {
b2bb98e1
HS
1004 printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
1005 return -EIO;
1006 }
1007
c34fa261
HS
1008 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1009 if (!devpriv)
1010 return -ENOMEM;
1011 dev->private = devpriv;
b2bb98e1
HS
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
16339125 1025 chans_left = CHANS_PER_ASIC * 1;
b2bb98e1
HS
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 }
eea6838b 1036
8b6c5694
HS
1037 ret = comedi_alloc_subdevices(dev, n_subdevs);
1038 if (ret)
1039 return ret;
b2bb98e1
HS
1040
1041 /* First, AI */
33e101ad
HS
1042 s = &dev->subdevices[0];
1043 s->private = &devpriv->sprivs[0];
16339125
HS
1044 s->maxdata = 0xffff;
1045 s->range_table = &ranges_ai;
b2bb98e1
HS
1046 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
1047 s->type = COMEDI_SUBD_AI;
16339125 1048 s->n_chan = 16;
b2bb98e1 1049 s->len_chanlist = s->n_chan;
16339125 1050 s->insn_read = ai_rinsn;
b2bb98e1
HS
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 */
33e101ad
HS
1057 s = &dev->subdevices[1];
1058 s->private = &devpriv->sprivs[1];
16339125
HS
1059 s->maxdata = 0xffff;
1060 s->range_table = &ranges_ao;
b2bb98e1
HS
1061 s->subdev_flags = SDF_READABLE;
1062 s->type = COMEDI_SUBD_AO;
16339125 1063 s->n_chan = 8;
b2bb98e1 1064 s->len_chanlist = s->n_chan;
16339125
HS
1065 s->insn_read = ao_rinsn;
1066 s->insn_write = ao_winsn;
b2bb98e1
HS
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
b2bb98e1
HS
1072 port = 0;
1073 asic = 0;
33e101ad 1074 for (sdev_no = 2; sdev_no < dev->n_subdevices; ++sdev_no) {
b2bb98e1
HS
1075 int byte_no;
1076
33e101ad
HS
1077 s = &dev->subdevices[sdev_no];
1078 s->private = &devpriv->sprivs[sdev_no];
b2bb98e1
HS
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,
16339125 1146 IRQF_SHARED, dev->board_name, dev)) {
b2bb98e1
HS
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
b2bb98e1
HS
1163 printk(KERN_INFO "comedi%d: attached\n", dev->minor);
1164
1165 return 1;
1166}
1167
484ecc95 1168static void pcmmio_detach(struct comedi_device *dev)
b2bb98e1 1169{
9a1a6cf8 1170 struct pcmmio_private *devpriv = dev->private;
b2bb98e1
HS
1171 int i;
1172
b2bb98e1 1173 if (dev->iobase)
16339125 1174 release_region(dev->iobase, 32);
b2bb98e1
HS
1175 for (i = 0; i < MAX_ASICS; ++i) {
1176 if (devpriv && devpriv->asics[i].irq)
1177 free_irq(devpriv->asics[i].irq, dev);
1178 }
b2bb98e1
HS
1179 if (devpriv && devpriv->sprivs)
1180 kfree(devpriv->sprivs);
b2bb98e1
HS
1181}
1182
294f930d 1183static struct comedi_driver pcmmio_driver = {
b2bb98e1
HS
1184 .driver_name = "pcmmio",
1185 .module = THIS_MODULE,
1186 .attach = pcmmio_attach,
1187 .detach = pcmmio_detach,
b2bb98e1 1188};
294f930d 1189module_comedi_driver(pcmmio_driver);
90f703d3
AT
1190
1191MODULE_AUTHOR("Comedi http://www.comedi.org");
1192MODULE_DESCRIPTION("Comedi low-level driver");
1193MODULE_LICENSE("GPL");
This page took 0.52193 seconds and 5 git commands to generate.