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