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