3 Hardware driver for Winsystems PCM-A/D12 and PCM-A/D16
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2000,2001 David A. Schleef <ds@schleef.org>
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.
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.
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.
25 Description: Winsystems PCM-A/D12, PCM-A/D16
27 Devices: [Winsystems] PCM-A/D12 (pcmad12), PCM-A/D16 (pcmad16)
30 This driver was written on a bet that I couldn't write a driver
31 in less than 2 hours. I won the bet, but never got paid. =(
33 Configuration options:
36 [2] - Analog input reference
39 [3] - Analog input encoding (must match jumpers)
44 #include <linux/interrupt.h>
45 #include "../comedidev.h"
47 #include <linux/ioport.h>
51 #define PCMAD_STATUS 0
54 #define PCMAD_CONVERT 1
56 struct pcmad_board_struct
{
60 static const struct pcmad_board_struct pcmad_boards
[] = {
71 #define this_board ((const struct pcmad_board_struct *)(dev->board_ptr))
72 #define n_pcmad_boards (sizeof(pcmad_boards)/sizeof(pcmad_boards[0]))
74 struct pcmad_priv_struct
{
78 #define devpriv ((struct pcmad_priv_struct *)dev->private)
80 static int pcmad_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
);
81 static int pcmad_detach(struct comedi_device
*dev
);
82 static struct comedi_driver driver_pcmad
= {
83 .driver_name
= "pcmad",
84 .module
= THIS_MODULE
,
85 .attach
= pcmad_attach
,
86 .detach
= pcmad_detach
,
87 .board_name
= &pcmad_boards
[0].name
,
88 .num_names
= n_pcmad_boards
,
89 .offset
= sizeof(pcmad_boards
[0]),
92 COMEDI_INITCLEANUP(driver_pcmad
);
96 static int pcmad_ai_insn_read(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
97 struct comedi_insn
*insn
, unsigned int *data
)
103 chan
= CR_CHAN(insn
->chanspec
);
105 for (n
= 0; n
< insn
->n
; n
++) {
106 outb(chan
, dev
->iobase
+ PCMAD_CONVERT
);
108 for (i
= 0; i
< TIMEOUT
; i
++) {
109 if ((inb(dev
->iobase
+ PCMAD_STATUS
) & 0x3) == 0x3)
112 data
[n
] = inb(dev
->iobase
+ PCMAD_LSB
);
113 data
[n
] |= (inb(dev
->iobase
+ PCMAD_MSB
) << 8);
115 if (devpriv
->twos_comp
) {
116 data
[n
] ^= (1 << (this_board
->n_ai_bits
- 1));
127 * 2 0=single ended 1=differential
128 * 3 0=straight binary 1=two's comp
130 static int pcmad_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
133 struct comedi_subdevice
*s
;
134 unsigned long iobase
;
136 iobase
= it
->options
[0];
137 printk("comedi%d: pcmad: 0x%04lx ", dev
->minor
, iobase
);
138 if (!request_region(iobase
, PCMAD_SIZE
, "pcmad")) {
139 printk("I/O port conflict\n");
142 dev
->iobase
= iobase
;
144 ret
= alloc_subdevices(dev
, 1);
148 ret
= alloc_private(dev
, sizeof(struct pcmad_priv_struct
));
152 dev
->board_name
= this_board
->name
;
154 s
= dev
->subdevices
+ 0;
155 s
->type
= COMEDI_SUBD_AI
;
156 s
->subdev_flags
= SDF_READABLE
| AREF_GROUND
;
157 s
->n_chan
= 16; /* XXX */
159 s
->insn_read
= pcmad_ai_insn_read
;
160 s
->maxdata
= (1 << this_board
->n_ai_bits
) - 1;
161 s
->range_table
= &range_unknown
;
166 static int pcmad_detach(struct comedi_device
*dev
)
168 printk("comedi%d: pcmad: remove\n", dev
->minor
);
171 free_irq(dev
->irq
, dev
);
174 release_region(dev
->iobase
, PCMAD_SIZE
);