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
{
61 struct pcmad_priv_struct
{
68 static int pcmad_ai_insn_read(struct comedi_device
*dev
,
69 struct comedi_subdevice
*s
,
70 struct comedi_insn
*insn
, unsigned int *data
)
72 const struct pcmad_board_struct
*board
= comedi_board(dev
);
73 struct pcmad_priv_struct
*devpriv
= dev
->private;
78 chan
= CR_CHAN(insn
->chanspec
);
80 for (n
= 0; n
< insn
->n
; n
++) {
81 outb(chan
, dev
->iobase
+ PCMAD_CONVERT
);
83 for (i
= 0; i
< TIMEOUT
; i
++) {
84 if ((inb(dev
->iobase
+ PCMAD_STATUS
) & 0x3) == 0x3)
87 data
[n
] = inb(dev
->iobase
+ PCMAD_LSB
);
88 data
[n
] |= (inb(dev
->iobase
+ PCMAD_MSB
) << 8);
90 if (devpriv
->twos_comp
)
91 data
[n
] ^= (1 << (board
->n_ai_bits
- 1));
101 * 2 0=single ended 1=differential
102 * 3 0=straight binary 1=two's comp
104 static int pcmad_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
106 const struct pcmad_board_struct
*board
= comedi_board(dev
);
107 struct pcmad_priv_struct
*devpriv
;
109 struct comedi_subdevice
*s
;
110 unsigned long iobase
;
112 iobase
= it
->options
[0];
113 printk(KERN_INFO
"comedi%d: pcmad: 0x%04lx ", dev
->minor
, iobase
);
114 if (!request_region(iobase
, PCMAD_SIZE
, "pcmad")) {
115 printk(KERN_CONT
"I/O port conflict\n");
118 printk(KERN_CONT
"\n");
119 dev
->iobase
= iobase
;
121 ret
= comedi_alloc_subdevices(dev
, 1);
125 devpriv
= kzalloc(sizeof(*devpriv
), GFP_KERNEL
);
128 dev
->private = devpriv
;
130 dev
->board_name
= board
->name
;
132 s
= &dev
->subdevices
[0];
133 s
->type
= COMEDI_SUBD_AI
;
134 s
->subdev_flags
= SDF_READABLE
| AREF_GROUND
;
135 s
->n_chan
= 16; /* XXX */
137 s
->insn_read
= pcmad_ai_insn_read
;
138 s
->maxdata
= (1 << board
->n_ai_bits
) - 1;
139 s
->range_table
= &range_unknown
;
144 static void pcmad_detach(struct comedi_device
*dev
)
147 free_irq(dev
->irq
, dev
);
149 release_region(dev
->iobase
, PCMAD_SIZE
);
152 static const struct pcmad_board_struct pcmad_boards
[] = {
161 static struct comedi_driver pcmad_driver
= {
162 .driver_name
= "pcmad",
163 .module
= THIS_MODULE
,
164 .attach
= pcmad_attach
,
165 .detach
= pcmad_detach
,
166 .board_name
= &pcmad_boards
[0].name
,
167 .num_names
= ARRAY_SIZE(pcmad_boards
),
168 .offset
= sizeof(pcmad_boards
[0]),
170 module_comedi_driver(pcmad_driver
);
172 MODULE_AUTHOR("Comedi http://www.comedi.org");
173 MODULE_DESCRIPTION("Comedi low-level driver");
174 MODULE_LICENSE("GPL");