Staging: otus: Drop an unnecessary NULL test
[deliverable/linux.git] / drivers / staging / comedi / drivers / pcmuio.c
CommitLineData
6baef150
CC
1/*
2 comedi/drivers/pcmuio.c
3 Driver for Winsystems PC-104 based 48-channel and 96-channel DIO boards.
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2006 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: pcmuio
24Description: A driver for the PCM-UIO48A and PCM-UIO96A boards from Winsystems.
25Devices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A (pcmuio96)
26Author: Calin Culianu <calin@ajvar.org>
27Updated: Fri, 13 Jan 2006 12:01:01 -0500
28Status: works
29
30A driver for the relatively straightforward-to-program PCM-UIO48A and
31PCM-UIO96A boards from Winsystems. These boards use either one or two
32(in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO).
33This chip is interesting in that each I/O line is individually
34programmable for INPUT or OUTPUT (thus comedi_dio_config can be done
35on a per-channel basis). Also, each chip supports edge-triggered
36interrupts for the first 24 I/O lines. Of course, since the
3796-channel version of the board has two ASICs, it can detect polarity
38changes on up to 48 I/O lines. Since this is essentially an (non-PnP)
39ISA board, I/O Address and IRQ selection are done through jumpers on
40the board. You need to pass that information to this driver as the
41first and second comedi_config option, respectively. Note that the
4248-channel version uses 16 bytes of IO memory and the 96-channel
43version uses 32-bytes (in case you are worried about conflicts). The
4448-channel board is split into two 24-channel comedi subdevices.
45The 96-channel board is split into 4 24-channel DIO subdevices.
46
47Note that IRQ support has been added, but it is untested.
48
49To use edge-detection IRQ support, pass the IRQs of both ASICS
50(for the 96 channel version) or just 1 ASIC (for 48-channel version).
51Then, use use comedi_commands with TRIG_NOW.
52Your callback will be called each time an edge is triggered, and the data
53values will be two sample_t's, which should be concatenated to form one
5432-bit unsigned int. This value is the mask of channels that had
55edges detected from your channel list. Note that the bits positions
56in the mask correspond to positions in your chanlist when you specified
57the command and *not* channel id's!
58
59To set the polarity of the edge-detection interrupts pass a nonzero value for
60either CR_RANGE or CR_AREF for edge-up polarity, or a zero value for both
61CR_RANGE and CR_AREF if you want edge-down polarity.
62
63In the 48-channel version:
64
65On subdev 0, the first 24 channels channels are edge-detect channels.
66
67In the 96-channel board you have the collowing channels that can do edge detection:
68
69subdev 0, channels 0-24 (first 24 channels of 1st ASIC)
70subdev 2, channels 0-24 (first 24 channels of 2nd ASIC)
71
72Configuration Options:
73 [0] - I/O port base address
74 [1] - IRQ (for first ASIC, or first 24 channels)
75 [2] - IRQ for second ASIC (pcmuio96 only - IRQ for chans 48-72 .. can be the same as first irq!)
76*/
77
25436dc9 78#include <linux/interrupt.h>
6baef150 79#include "../comedidev.h"
0b8f754a 80#include "pcm_common.h"
6baef150
CC
81
82#include <linux/pci.h> /* for PCI devices */
83
6baef150
CC
84#define CHANS_PER_PORT 8
85#define PORTS_PER_ASIC 6
86#define INTR_PORTS_PER_ASIC 3
87#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */
88#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
89#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
90#define INTR_CHANS_PER_ASIC 24
91#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
92#define MAX_DIO_CHANS (PORTS_PER_ASIC*2*CHANS_PER_PORT)
93#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC)
94#define SDEV_NO ((int)(s - dev->subdevices))
95#define CALC_N_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
96/* IO Memory sizes */
97#define ASIC_IOSIZE (0x10)
98#define PCMUIO48_IOSIZE ASIC_IOSIZE
99#define PCMUIO96_IOSIZE (ASIC_IOSIZE*2)
100
101/* Some offsets - these are all in the 16byte IO memory offset from
102 the base address. Note that there is a paging scheme to swap out
103 offsets 0x8-0xA using the PAGELOCK register. See the table below.
104
105 Register(s) Pages R/W? Description
106 --------------------------------------------------------------
107 REG_PORTx All R/W Read/Write/Configure IO
108 REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int.
109 REG_PAGELOCK All WriteOnly Select a page
110 REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity
111 REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int.
112 REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints.
113 */
114#define REG_PORT0 0x0
115#define REG_PORT1 0x1
116#define REG_PORT2 0x2
117#define REG_PORT3 0x3
118#define REG_PORT4 0x4
119#define REG_PORT5 0x5
120#define REG_INT_PENDING 0x6
121#define REG_PAGELOCK 0x7 /* page selector register, upper 2 bits select a page
122 and bits 0-5 are used to 'lock down' a particular
123 port above to make it readonly. */
124#define REG_POL0 0x8
125#define REG_POL1 0x9
126#define REG_POL2 0xA
127#define REG_ENAB0 0x8
128#define REG_ENAB1 0x9
129#define REG_ENAB2 0xA
130#define REG_INT_ID0 0x8
131#define REG_INT_ID1 0x9
132#define REG_INT_ID2 0xA
133
134#define NUM_PAGED_REGS 3
135#define NUM_PAGES 4
136#define FIRST_PAGED_REG 0x8
137#define REG_PAGE_BITOFFSET 6
138#define REG_LOCK_BITOFFSET 0
139#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
140#define REG_LOCK_MASK ~(REG_PAGE_MASK)
141#define PAGE_POL 1
142#define PAGE_ENAB 2
143#define PAGE_INT_ID 3
144
145/*
146 * Board descriptions for two imaginary boards. Describing the
147 * boards in this way is optional, and completely driver-dependent.
148 * Some drivers use arrays such as this, other do not.
149 */
70a6001a 150struct pcmuio_board {
6baef150
CC
151 const char *name;
152 const int num_asics;
153 const int num_channels_per_port;
154 const int num_ports;
70a6001a 155};
6baef150 156
70a6001a 157static const struct pcmuio_board pcmuio_boards[] = {
6baef150 158 {
68c3dbff
BP
159 .name = "pcmuio48",
160 .num_asics = 1,
161 .num_ports = 6,
6baef150
CC
162 },
163 {
68c3dbff
BP
164 .name = "pcmuio96",
165 .num_asics = 2,
166 .num_ports = 12,
6baef150
CC
167 },
168};
169
170/*
171 * Useful for shorthand access to the particular board structure
172 */
70a6001a 173#define thisboard ((const struct pcmuio_board *)dev->board_ptr)
6baef150
CC
174
175/* this structure is for data unique to this subdevice. */
e15849e5 176struct pcmuio_subdev_private {
6baef150
CC
177 /* mapping of halfwords (bytes) in port/chanarray to iobase */
178 unsigned long iobases[PORTS_PER_SUBDEV];
179
180 /* The below is only used for intr subdevices */
181 struct {
182 int asic; /* if non-negative, this subdev has an interrupt asic */
183 int first_chan; /* if nonnegative, the first channel id for
184 interrupts. */
185 int num_asic_chans; /* the number of asic channels in this subdev
186 that have interrutps */
187 int asic_chan; /* if nonnegative, the first channel id with
188 respect to the asic that has interrupts */
189 int enabled_mask; /* subdev-relative channel mask for channels
190 we are interested in */
191 int active;
192 int stop_count;
193 int continuous;
194 spinlock_t spinlock;
195 } intr;
e15849e5 196};
6baef150
CC
197
198/* this structure is for data unique to this hardware driver. If
199 several hardware drivers keep similar information in this structure,
71b5f4f1 200 feel free to suggest moving the variable to the struct comedi_device struct. */
055f6636 201struct pcmuio_private {
6baef150
CC
202 struct {
203 unsigned char pagelock; /* current page and lock */
204 unsigned char pol[NUM_PAGED_REGS]; /* shadow of POLx registers */
205 unsigned char enab[NUM_PAGED_REGS]; /* shadow of ENABx registers */
206 int num;
207 unsigned long iobase;
208 unsigned int irq;
209 spinlock_t spinlock;
210 } asics[MAX_ASICS];
e15849e5 211 struct pcmuio_subdev_private *sprivs;
055f6636 212};
6baef150
CC
213
214/*
215 * most drivers define the following macro to make it easy to
216 * access the private structure.
217 */
055f6636 218#define devpriv ((struct pcmuio_private *)dev->private)
e15849e5 219#define subpriv ((struct pcmuio_subdev_private *)s->private)
6baef150 220/*
139dfbdf 221 * The struct comedi_driver structure tells the Comedi core module
6baef150
CC
222 * which functions to call to configure/deconfigure (attach/detach)
223 * the board, and also about the kernel module that contains
224 * the device code.
225 */
da91b269
BP
226static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it);
227static int pcmuio_detach(struct comedi_device *dev);
6baef150 228
139dfbdf 229static struct comedi_driver driver = {
68c3dbff
BP
230 .driver_name = "pcmuio",
231 .module = THIS_MODULE,
232 .attach = pcmuio_attach,
233 .detach = pcmuio_detach,
6baef150
CC
234/* It is not necessary to implement the following members if you are
235 * writing a driver for a ISA PnP or PCI card */
236 /* Most drivers will support multiple types of boards by
237 * having an array of board structures. These were defined
238 * in pcmuio_boards[] above. Note that the element 'name'
239 * was first in the structure -- Comedi uses this fact to
240 * extract the name of the board without knowing any details
241 * about the structure except for its length.
242 * When a device is attached (by comedi_config), the name
243 * of the device is given to Comedi, and Comedi tries to
244 * match it by going through the list of board names. If
245 * there is a match, the address of the pointer is put
246 * into dev->board_ptr and driver->attach() is called.
247 *
248 * Note that these are not necessary if you can determine
249 * the type of board in software. ISA PnP, PCI, and PCMCIA
250 * devices are such boards.
251 */
68c3dbff
BP
252 .board_name = &pcmuio_boards[0].name,
253 .offset = sizeof(struct pcmuio_board),
8629efa4 254 .num_names = ARRAY_SIZE(pcmuio_boards),
6baef150
CC
255};
256
814900c9
BP
257static int pcmuio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
258 struct comedi_insn *insn, unsigned int *data);
259static int pcmuio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
260 struct comedi_insn *insn, unsigned int *data);
6baef150 261
70265d24 262static irqreturn_t interrupt_pcmuio(int irq, void *d);
34c43922 263static void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
814900c9
BP
264static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
265static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
266static int pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
267 struct comedi_cmd *cmd);
6baef150
CC
268
269/* some helper functions to deal with specifics of this device's registers */
814900c9
BP
270static void init_asics(struct comedi_device *dev); /* sets up/clears ASIC chips to defaults */
271static void switch_page(struct comedi_device *dev, int asic, int page);
6baef150 272#ifdef notused
814900c9
BP
273static void lock_port(struct comedi_device *dev, int asic, int port);
274static void unlock_port(struct comedi_device *dev, int asic, int port);
6baef150
CC
275#endif
276
277/*
278 * Attach is called by the Comedi core to configure the driver
279 * for a particular board. If you specified a board_name array
280 * in the driver structure, dev->board_ptr contains that
281 * address.
282 */
da91b269 283static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
6baef150 284{
34c43922 285 struct comedi_subdevice *s;
6baef150
CC
286 int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
287 unsigned long iobase;
288 unsigned int irq[MAX_ASICS];
289
290 iobase = it->options[0];
291 irq[0] = it->options[1];
292 irq[1] = it->options[2];
293
294 printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name,
295 iobase);
296
297 dev->iobase = iobase;
298
299 if (!iobase || !request_region(iobase,
300 thisboard->num_asics * ASIC_IOSIZE,
301 driver.driver_name)) {
302 printk("I/O port conflict\n");
303 return -EIO;
304 }
305
306/*
307 * Initialize dev->board_name. Note that we can use the "thisboard"
308 * macro now, since we just initialized it in the last line.
309 */
310 dev->board_name = thisboard->name;
311
312/*
313 * Allocate the private structure area. alloc_private() is a
314 * convenient macro defined in comedidev.h.
315 */
055f6636 316 if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
6baef150
CC
317 printk("cannot allocate private data structure\n");
318 return -ENOMEM;
319 }
320
321 for (asic = 0; asic < MAX_ASICS; ++asic) {
322 devpriv->asics[asic].num = asic;
323 devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
324 devpriv->asics[asic].irq = 0; /* this gets actually set at the end of
325 this function when we
5f74ea14 326 request_irqs */
6baef150
CC
327 spin_lock_init(&devpriv->asics[asic].spinlock);
328 }
329
330 chans_left = CHANS_PER_ASIC * thisboard->num_asics;
331 n_subdevs = CALC_N_SUBDEVS(chans_left);
332 devpriv->sprivs =
e15849e5 333 kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private), GFP_KERNEL);
6baef150
CC
334 if (!devpriv->sprivs) {
335 printk("cannot allocate subdevice private data structures\n");
336 return -ENOMEM;
337 }
338 /*
339 * Allocate the subdevice structures. alloc_subdevice() is a
340 * convenient macro defined in comedidev.h.
341 *
342 * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
343 * 96-channel version of the board.
344 */
345 if (alloc_subdevices(dev, n_subdevs) < 0) {
346 printk("cannot allocate subdevice data structures\n");
347 return -ENOMEM;
348 }
349
350 port = 0;
351 asic = 0;
352 for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
353 int byte_no;
354
355 s = dev->subdevices + sdev_no;
356 s->private = devpriv->sprivs + sdev_no;
357 s->maxdata = 1;
358 s->range_table = &range_digital;
359 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
360 s->type = COMEDI_SUBD_DIO;
361 s->insn_bits = pcmuio_dio_insn_bits;
362 s->insn_config = pcmuio_dio_insn_config;
214e7b5c 363 s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
6baef150
CC
364 subpriv->intr.asic = -1;
365 subpriv->intr.first_chan = -1;
366 subpriv->intr.asic_chan = -1;
367 subpriv->intr.num_asic_chans = -1;
368 subpriv->intr.active = 0;
369 s->len_chanlist = 1;
370
371 /* save the ioport address for each 'port' of 8 channels in the
372 subdevice */
373 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
374 if (port >= PORTS_PER_ASIC) {
375 port = 0;
376 ++asic;
377 thisasic_chanct = 0;
378 }
379 subpriv->iobases[byte_no] =
380 devpriv->asics[asic].iobase + port;
381
382 if (thisasic_chanct <
383 CHANS_PER_PORT * INTR_PORTS_PER_ASIC
384 && subpriv->intr.asic < 0) {
385 /* this is an interrupt subdevice, so setup the struct */
386 subpriv->intr.asic = asic;
387 subpriv->intr.active = 0;
388 subpriv->intr.stop_count = 0;
389 subpriv->intr.first_chan = byte_no * 8;
390 subpriv->intr.asic_chan = thisasic_chanct;
391 subpriv->intr.num_asic_chans =
392 s->n_chan - subpriv->intr.first_chan;
393 dev->read_subdev = s;
394 s->subdev_flags |= SDF_CMD_READ;
395 s->cancel = pcmuio_cancel;
396 s->do_cmd = pcmuio_cmd;
397 s->do_cmdtest = pcmuio_cmdtest;
398 s->len_chanlist = subpriv->intr.num_asic_chans;
399 }
400 thisasic_chanct += CHANS_PER_PORT;
401 }
402 spin_lock_init(&subpriv->intr.spinlock);
403
404 chans_left -= s->n_chan;
405
406 if (!chans_left) {
407 asic = 0; /* reset the asic to our first asic, to do intr subdevs */
408 port = 0;
409 }
410
411 }
412
413 init_asics(dev); /* clear out all the registers, basically */
414
415 for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
416 if (irq[asic]
5f74ea14 417 && request_irq(irq[asic], interrupt_pcmuio,
6baef150
CC
418 IRQF_SHARED, thisboard->name, dev)) {
419 int i;
420 /* unroll the allocated irqs.. */
421 for (i = asic - 1; i >= 0; --i) {
5f74ea14 422 free_irq(irq[i], dev);
6baef150
CC
423 devpriv->asics[i].irq = irq[i] = 0;
424 }
425 irq[asic] = 0;
426 }
427 devpriv->asics[asic].irq = irq[asic];
428 }
429
430 dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple
431 irqs.. */
432
433 if (irq[0]) {
434 printk("irq: %u ", irq[0]);
435 if (irq[1] && thisboard->num_asics == 2)
436 printk("second ASIC irq: %u ", irq[1]);
437 } else {
438 printk("(IRQ mode disabled) ");
439 }
440
441 printk("attached\n");
442
443 return 1;
444}
445
446/*
447 * _detach is called to deconfigure a device. It should deallocate
448 * resources.
449 * This function is also called when _attach() fails, so it should be
450 * careful not to release resources that were not necessarily
451 * allocated by _attach(). dev->private and dev->subdevices are
452 * deallocated automatically by the core.
453 */
da91b269 454static int pcmuio_detach(struct comedi_device *dev)
6baef150
CC
455{
456 int i;
457
458 printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
459 if (dev->iobase)
460 release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
461
462 for (i = 0; i < MAX_ASICS; ++i) {
463 if (devpriv->asics[i].irq)
5f74ea14 464 free_irq(devpriv->asics[i].irq, dev);
6baef150
CC
465 }
466
467 if (devpriv && devpriv->sprivs)
468 kfree(devpriv->sprivs);
469
470 return 0;
471}
472
473/* DIO devices are slightly special. Although it is possible to
474 * implement the insn_read/insn_write interface, it is much more
475 * useful to applications if you implement the insn_bits interface.
476 * This allows packed reading/writing of the DIO channels. The
477 * comedi core can convert between insn_bits and insn_read/write */
da91b269
BP
478static int pcmuio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
479 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
480{
481 int byte_no;
482 if (insn->n != 2)
483 return -EINVAL;
484
485 /* NOTE:
486 reading a 0 means this channel was high
487 writine a 0 sets the channel high
488 reading a 1 means this channel was low
489 writing a 1 means set this channel low
490
491 Therefore everything is always inverted. */
492
493 /* The insn data is a mask in data[0] and the new data
494 * in data[1], each channel cooresponding to a bit. */
495
496#ifdef DAMMIT_ITS_BROKEN
497 /* DEBUG */
498 printk("write mask: %08x data: %08x\n", data[0], data[1]);
499#endif
500
501 s->state = 0;
502
503 for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
504 /* address of 8-bit port */
505 unsigned long ioaddr = subpriv->iobases[byte_no],
506 /* bit offset of port in 32-bit doubleword */
507 offset = byte_no * 8;
508 /* this 8-bit port's data */
509 unsigned char byte = 0,
510 /* The write mask for this port (if any) */
511 write_mask_byte = (data[0] >> offset) & 0xff,
512 /* The data byte for this port */
513 data_byte = (data[1] >> offset) & 0xff;
514
515 byte = inb(ioaddr); /* read all 8-bits for this port */
516
517#ifdef DAMMIT_ITS_BROKEN
518 /* DEBUG */
519 printk("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ", byte_no, (unsigned)write_mask_byte, (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
520#endif
521
522 if (write_mask_byte) {
523 /* this byte has some write_bits -- so set the output lines */
524 byte &= ~write_mask_byte; /* clear bits for write mask */
525 byte |= ~data_byte & write_mask_byte; /* set to inverted data_byte */
526 /* Write out the new digital output state */
527 outb(byte, ioaddr);
528 }
529#ifdef DAMMIT_ITS_BROKEN
530 /* DEBUG */
531 printk("data_out_byte %02x\n", (unsigned)byte);
532#endif
533 /* save the digital input lines for this byte.. */
534 s->state |= ((unsigned int)byte) << offset;
535 }
536
537 /* now return the DIO lines to data[1] - note they came inverted! */
538 data[1] = ~s->state;
539
540#ifdef DAMMIT_ITS_BROKEN
541 /* DEBUG */
542 printk("s->state %08x data_out %08x\n", s->state, data[1]);
543#endif
544
545 return 2;
546}
547
548/* The input or output configuration of each digital line is
549 * configured by a special insn_config instruction. chanspec
550 * contains the channel to be changed, and data[0] contains the
551 * value COMEDI_INPUT or COMEDI_OUTPUT. */
da91b269
BP
552static int pcmuio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
553 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
554{
555 int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
556 chan % 8;
557 unsigned long ioaddr;
558 unsigned char byte;
559
560 /* Compute ioaddr for this channel */
561 ioaddr = subpriv->iobases[byte_no];
562
563 /* NOTE:
564 writing a 0 an IO channel's bit sets the channel to INPUT
565 and pulls the line high as well
566
567 writing a 1 to an IO channel's bit pulls the line low
568
569 All channels are implicitly always in OUTPUT mode -- but when
570 they are high they can be considered to be in INPUT mode..
571
572 Thus, we only force channels low if the config request was INPUT,
573 otherwise we do nothing to the hardware. */
574
575 switch (data[0]) {
576 case INSN_CONFIG_DIO_OUTPUT:
577 /* save to io_bits -- don't actually do anything since
578 all input channels are also output channels... */
579 s->io_bits |= 1 << chan;
580 break;
581 case INSN_CONFIG_DIO_INPUT:
582 /* write a 0 to the actual register representing the channel
583 to set it to 'input'. 0 means "float high". */
584 byte = inb(ioaddr);
585 byte &= ~(1 << bit_no);
586 /**< set input channel to '0' */
587
588 /* write out byte -- this is the only time we actually affect the
589 hardware as all channels are implicitly output -- but input
590 channels are set to float-high */
591 outb(byte, ioaddr);
592
593 /* save to io_bits */
594 s->io_bits &= ~(1 << chan);
595 break;
596
597 case INSN_CONFIG_DIO_QUERY:
598 /* retreive from shadow register */
599 data[1] =
600 (s->
601 io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
602 return insn->n;
603 break;
604
605 default:
606 return -EINVAL;
607 break;
608 }
609
610 return insn->n;
611}
612
da91b269 613static void init_asics(struct comedi_device *dev)
6baef150
CC
614{ /* sets up an
615 ASIC chip to defaults */
616 int asic;
617
618 for (asic = 0; asic < thisboard->num_asics; ++asic) {
619 int port, page;
620 unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE;
621
622 switch_page(dev, asic, 0); /* switch back to page 0 */
623
624 /* first, clear all the DIO port bits */
625 for (port = 0; port < PORTS_PER_ASIC; ++port)
626 outb(0, baseaddr + REG_PORT0 + port);
627
628 /* Next, clear all the paged registers for each page */
629 for (page = 1; page < NUM_PAGES; ++page) {
630 int reg;
631 /* now clear all the paged registers */
632 switch_page(dev, asic, page);
633 for (reg = FIRST_PAGED_REG;
634 reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
635 outb(0, baseaddr + reg);
636 }
637
638 /* DEBUG set rising edge interrupts on port0 of both asics */
639 /*switch_page(dev, asic, PAGE_POL);
640 outb(0xff, baseaddr + REG_POL0);
641 switch_page(dev, asic, PAGE_ENAB);
642 outb(0xff, baseaddr + REG_ENAB0); */
643 /* END DEBUG */
644
645 switch_page(dev, asic, 0); /* switch back to default page 0 */
646
647 }
648}
649
da91b269 650static void switch_page(struct comedi_device *dev, int asic, int page)
6baef150
CC
651{
652 if (asic < 0 || asic >= thisboard->num_asics)
653 return; /* paranoia */
654 if (page < 0 || page >= NUM_PAGES)
655 return; /* more paranoia */
656
657 devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
658 devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
659
660 /* now write out the shadow register */
661 outb(devpriv->asics[asic].pagelock,
662 dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
663}
664
665#ifdef notused
da91b269 666static void lock_port(struct comedi_device *dev, int asic, int port)
6baef150
CC
667{
668 if (asic < 0 || asic >= thisboard->num_asics)
669 return; /* paranoia */
670 if (port < 0 || port >= PORTS_PER_ASIC)
671 return; /* more paranoia */
672
673 devpriv->asics[asic].pagelock |= 0x1 << port;
674 /* now write out the shadow register */
675 outb(devpriv->asics[asic].pagelock,
676 dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
677}
678
da91b269 679static void unlock_port(struct comedi_device *dev, int asic, int port)
6baef150
CC
680{
681 if (asic < 0 || asic >= thisboard->num_asics)
682 return; /* paranoia */
683 if (port < 0 || port >= PORTS_PER_ASIC)
684 return; /* more paranoia */
685 devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
686 /* now write out the shadow register */
687 outb(devpriv->asics[asic].pagelock,
688 dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
689}
690#endif /* notused */
691
70265d24 692static irqreturn_t interrupt_pcmuio(int irq, void *d)
6baef150
CC
693{
694 int asic, got1 = 0;
71b5f4f1 695 struct comedi_device *dev = (struct comedi_device *) d;
6baef150
CC
696
697 for (asic = 0; asic < MAX_ASICS; ++asic) {
698 if (irq == devpriv->asics[asic].irq) {
699 unsigned long flags;
700 unsigned triggered = 0;
701 unsigned long iobase = devpriv->asics[asic].iobase;
702 /* it is an interrupt for ASIC #asic */
703 unsigned char int_pend;
704
5f74ea14 705 spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags);
6baef150
CC
706
707 int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
708
709 if (int_pend) {
710 int port;
711 for (port = 0; port < INTR_PORTS_PER_ASIC;
712 ++port) {
713 if (int_pend & (0x1 << port)) {
714 unsigned char
715 io_lines_with_edges = 0;
716 switch_page(dev, asic,
717 PAGE_INT_ID);
718 io_lines_with_edges =
719 inb(iobase +
720 REG_INT_ID0 + port);
721
722 if (io_lines_with_edges)
723 /* clear pending interrupt */
724 outb(0, iobase +
725 REG_INT_ID0 +
726 port);
727
728 triggered |=
729 io_lines_with_edges <<
730 port * 8;
731 }
732 }
733
734 ++got1;
735 }
736
5f74ea14 737 spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags);
6baef150
CC
738
739 if (triggered) {
34c43922 740 struct comedi_subdevice *s;
6baef150
CC
741 /* TODO here: dispatch io lines to subdevs with commands.. */
742 printk("PCMUIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", irq, asic, triggered);
743 for (s = dev->subdevices;
744 s < dev->subdevices + dev->n_subdevices;
745 ++s) {
746 if (subpriv->intr.asic == asic) { /* this is an interrupt subdev, and it matches this asic! */
747 unsigned long flags;
748 unsigned oldevents;
749
5f74ea14 750 spin_lock_irqsave (&subpriv->intr.spinlock, flags);
6baef150
CC
751
752 oldevents = s->async->events;
753
754 if (subpriv->intr.active) {
755 unsigned mytrig =
756 ((triggered >>
757 subpriv->
758 intr.
759 asic_chan)
760 & ((0x1 << subpriv->intr.num_asic_chans) - 1)) << subpriv->intr.first_chan;
761 if (mytrig & subpriv->
762 intr.
763 enabled_mask) {
790c5541 764 unsigned int val =
6baef150
CC
765 0;
766 unsigned int n,
767 ch, len;
768
769 len = s->async->
770 cmd.
771 chanlist_len;
772 for (n = 0;
773 n < len;
774 n++) {
775 ch = CR_CHAN(s->async->cmd.chanlist[n]);
776 if (mytrig & (1U << ch)) {
777 val |= (1U << n);
778 }
779 }
780 /* Write the scan to the buffer. */
9b9bcba0 781 if (comedi_buf_put(s->async, ((short *) &val)[0])
6baef150
CC
782 &&
783 comedi_buf_put
9b9bcba0 784 (s->async, ((short *) &val)[1])) {
6baef150
CC
785 s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
786 } else {
787 /* Overflow! Stop acquisition!! */
788 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
789 pcmuio_stop_intr
790 (dev,
791 s);
792 }
793
794 /* Check for end of acquisition. */
795 if (!subpriv->
796 intr.
797 continuous)
798 {
799 /* stop_src == TRIG_COUNT */
800 if (subpriv->intr.stop_count > 0) {
801 subpriv->
802 intr.
803 stop_count--;
804 if (subpriv->intr.stop_count == 0) {
805 s->async->events |= COMEDI_CB_EOA;
806 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
807 pcmuio_stop_intr
808 (dev,
809 s);
810 }
811 }
812 }
813 }
814 }
815
5f74ea14 816 spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
6baef150
CC
817
818 if (oldevents !=
819 s->async->events) {
820 comedi_event(dev, s);
821 }
822
823 }
824
825 }
826 }
827
828 }
829 }
830 if (!got1)
831 return IRQ_NONE; /* interrupt from other source */
832 return IRQ_HANDLED;
833}
834
da91b269 835static void pcmuio_stop_intr(struct comedi_device *dev, struct comedi_subdevice *s)
6baef150
CC
836{
837 int nports, firstport, asic, port;
838
c3744138
BP
839 asic = subpriv->intr.asic;
840 if (asic < 0)
6baef150
CC
841 return; /* not an interrupt subdev */
842
843 subpriv->intr.enabled_mask = 0;
844 subpriv->intr.active = 0;
845 s->async->inttrig = 0;
846 nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
847 firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
848 switch_page(dev, asic, PAGE_ENAB);
849 for (port = firstport; port < firstport + nports; ++port) {
850 /* disable all intrs for this subdev.. */
851 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
852 }
853}
854
da91b269 855static int pcmuio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s)
6baef150
CC
856{
857 if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) {
858 /* An empty acquisition! */
859 s->async->events |= COMEDI_CB_EOA;
860 subpriv->intr.active = 0;
861 return 1;
862 } else {
863 unsigned bits = 0, pol_bits = 0, n;
864 int nports, firstport, asic, port;
ea6d0d4c 865 struct comedi_cmd *cmd = &s->async->cmd;
6baef150 866
c3744138
BP
867 asic = subpriv->intr.asic;
868 if (asic < 0)
6baef150
CC
869 return 1; /* not an interrupt
870 subdev */
871 subpriv->intr.enabled_mask = 0;
872 subpriv->intr.active = 1;
873 nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
874 firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
875 if (cmd->chanlist) {
876 for (n = 0; n < cmd->chanlist_len; n++) {
877 bits |= (1U << CR_CHAN(cmd->chanlist[n]));
878 pol_bits |= (CR_AREF(cmd->chanlist[n])
879 || CR_RANGE(cmd->chanlist[n]) ? 1U : 0U)
880 << CR_CHAN(cmd->chanlist[n]);
881 }
882 }
883 bits &= ((0x1 << subpriv->intr.num_asic_chans) -
884 1) << subpriv->intr.first_chan;
885 subpriv->intr.enabled_mask = bits;
886
887 switch_page(dev, asic, PAGE_ENAB);
888 for (port = firstport; port < firstport + nports; ++port) {
889 unsigned enab =
890 bits >> (subpriv->intr.first_chan + (port -
891 firstport) * 8) & 0xff, pol =
892 pol_bits >> (subpriv->intr.first_chan + (port -
893 firstport) * 8) & 0xff;
894 /* set enab intrs for this subdev.. */
895 outb(enab,
896 devpriv->asics[asic].iobase + REG_ENAB0 + port);
897 switch_page(dev, asic, PAGE_POL);
898 outb(pol,
899 devpriv->asics[asic].iobase + REG_ENAB0 + port);
900 }
901 }
902 return 0;
903}
904
da91b269 905static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
6baef150
CC
906{
907 unsigned long flags;
908
5f74ea14 909 spin_lock_irqsave(&subpriv->intr.spinlock, flags);
6baef150
CC
910 if (subpriv->intr.active)
911 pcmuio_stop_intr(dev, s);
5f74ea14 912 spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
6baef150
CC
913
914 return 0;
915}
916
917/*
918 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
919 */
920static int
da91b269 921pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
6baef150
CC
922 unsigned int trignum)
923{
924 unsigned long flags;
925 int event = 0;
926
927 if (trignum != 0)
928 return -EINVAL;
929
5f74ea14 930 spin_lock_irqsave(&subpriv->intr.spinlock, flags);
6baef150
CC
931 s->async->inttrig = 0;
932 if (subpriv->intr.active) {
933 event = pcmuio_start_intr(dev, s);
934 }
5f74ea14 935 spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
6baef150
CC
936
937 if (event) {
938 comedi_event(dev, s);
939 }
940
941 return 1;
942}
943
944/*
945 * 'do_cmd' function for an 'INTERRUPT' subdevice.
946 */
da91b269 947static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
6baef150 948{
ea6d0d4c 949 struct comedi_cmd *cmd = &s->async->cmd;
6baef150
CC
950 unsigned long flags;
951 int event = 0;
952
5f74ea14 953 spin_lock_irqsave(&subpriv->intr.spinlock, flags);
6baef150
CC
954 subpriv->intr.active = 1;
955
956 /* Set up end of acquisition. */
957 switch (cmd->stop_src) {
958 case TRIG_COUNT:
959 subpriv->intr.continuous = 0;
960 subpriv->intr.stop_count = cmd->stop_arg;
961 break;
962 default:
963 /* TRIG_NONE */
964 subpriv->intr.continuous = 1;
965 subpriv->intr.stop_count = 0;
966 break;
967 }
968
969 /* Set up start of acquisition. */
970 switch (cmd->start_src) {
971 case TRIG_INT:
972 s->async->inttrig = pcmuio_inttrig_start_intr;
973 break;
974 default:
975 /* TRIG_NOW */
976 event = pcmuio_start_intr(dev, s);
977 break;
978 }
5f74ea14 979 spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
6baef150
CC
980
981 if (event) {
982 comedi_event(dev, s);
983 }
984
985 return 0;
986}
987
6baef150 988static int
da91b269 989pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd)
6baef150 990{
0b8f754a 991 return comedi_pcm_cmdtest(dev, s, cmd);
6baef150
CC
992}
993
994/*
995 * A convenient macro that defines init_module() and cleanup_module(),
996 * as necessary.
997 */
998COMEDI_INITCLEANUP(driver);
This page took 0.116525 seconds and 5 git commands to generate.