2 comedi/drivers/pcm724.c
4 Drew Csillag <drew_csillag@yahoo.com>
6 hardware driver for Advantech card:
15 Description: Advantech PCM-3724
16 Author: Drew Csillag <drew_csillag@yahoo.com>
17 Devices: [Advantech] PCM-3724 (pcm724)
20 This is driver for digital I/O boards PCM-3724 with 48 DIO.
21 It needs 8255.o for operations and only immediate mode is supported.
22 See the source for configuration details.
24 Copy/pasted/hacked from pcm724.c
27 * check_driver overrides:
31 #include "../comedidev.h"
33 #include <linux/ioport.h>
34 #include <linux/delay.h>
38 #define PCM3724_SIZE 16
59 #define CR_B_MODE 0x04
62 #define CR_A_MODE(a) ((a)<<5)
65 static int pcm3724_attach(struct comedi_device
*dev
,
66 struct comedi_devconfig
*it
);
67 static int pcm3724_detach(struct comedi_device
*dev
);
69 struct pcm3724_board
{
70 const char *name
; /* driver name */
71 int dio
; /* num of DIO */
72 int numofports
; /* num of 8255 subdevices */
73 unsigned int IRQbits
; /* allowed interrupts */
74 unsigned int io_range
; /* len of IO space */
77 /* used to track configured dios */
83 static const struct pcm3724_board boardtypes
[] = {
84 {"pcm3724", 48, 2, 0x00fc, PCM3724_SIZE
,},
87 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcm3724_board))
88 #define this_board ((const struct pcm3724_board *)dev->board_ptr)
90 static struct comedi_driver driver_pcm3724
= {
91 .driver_name
= "pcm3724",
92 .module
= THIS_MODULE
,
93 .attach
= pcm3724_attach
,
94 .detach
= pcm3724_detach
,
95 .board_name
= &boardtypes
[0].name
,
96 .num_names
= n_boardtypes
,
97 .offset
= sizeof(struct pcm3724_board
),
100 static int __init
driver_pcm3724_init_module(void)
102 return comedi_driver_register(&driver_pcm3724
);
105 static void __exit
driver_pcm3724_cleanup_module(void)
107 comedi_driver_unregister(&driver_pcm3724
);
110 module_init(driver_pcm3724_init_module
);
111 module_exit(driver_pcm3724_cleanup_module
);
113 /* (setq c-basic-offset 8) */
115 static int subdev_8255_cb(int dir
, int port
, int data
, unsigned long arg
)
117 unsigned long iobase
= arg
;
118 unsigned char inbres
;
119 /* printk("8255cb %d %d %d %lx\n", dir,port,data,arg); */
121 /* printk("8255 cb outb(%x, %lx)\n", data, iobase+port); */
122 outb(data
, iobase
+ port
);
125 inbres
= inb(iobase
+ port
);
126 /* printk("8255 cb inb(%lx) = %x\n", iobase+port, inbres); */
131 static int compute_buffer(int config
, int devno
, struct comedi_subdevice
*s
)
133 /* 1 in io_bits indicates output */
134 if (s
->io_bits
& 0x0000ff) {
140 if (s
->io_bits
& 0x00ff00) {
146 if (s
->io_bits
& 0xff0000) {
155 static void do_3724_config(struct comedi_device
*dev
,
156 struct comedi_subdevice
*s
, int chanspec
)
160 unsigned long port_8255_cfg
;
165 /* 1 in io_bits indicates output, 1 in config indicates input */
166 if (!(s
->io_bits
& 0x0000ff))
169 if (!(s
->io_bits
& 0x00ff00))
172 if (!(s
->io_bits
& 0xff0000))
175 buffer_config
= compute_buffer(0, 0, dev
->subdevices
);
176 buffer_config
= compute_buffer(buffer_config
, 1, (dev
->subdevices
) + 1);
178 if (s
== dev
->subdevices
)
179 port_8255_cfg
= dev
->iobase
+ _8255_CR
;
181 port_8255_cfg
= dev
->iobase
+ SIZE_8255
+ _8255_CR
;
183 outb(buffer_config
, dev
->iobase
+ 8); /* update buffer register */
184 /* printk("pcm3724 buffer_config (%lx) %d, %x\n",
185 dev->iobase + _8255_CR, chanspec, buffer_config); */
187 outb(config
, port_8255_cfg
);
190 static void enable_chan(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
195 struct priv_pcm3724
*priv
;
200 mask
= 1 << CR_CHAN(chanspec
);
201 if (s
== dev
->subdevices
) /* subdev 0 */
206 if (priv
->dio_1
& 0xff0000)
209 if (priv
->dio_1
& 0xff00)
212 if (priv
->dio_1
& 0xff)
215 if (priv
->dio_2
& 0xff0000)
218 if (priv
->dio_2
& 0xff00)
221 if (priv
->dio_2
& 0xff)
224 /* printk("gate control %x\n", gatecfg); */
225 outb(gatecfg
, dev
->iobase
+ 9);
228 /* overriding the 8255 insn config */
229 static int subdev_3724_insn_config(struct comedi_device
*dev
,
230 struct comedi_subdevice
*s
,
231 struct comedi_insn
*insn
, unsigned int *data
)
236 mask
= 1 << CR_CHAN(insn
->chanspec
);
239 else if (mask
& 0x00ff00)
241 else if (mask
& 0x0f0000)
247 case INSN_CONFIG_DIO_INPUT
:
250 case INSN_CONFIG_DIO_OUTPUT
:
253 case INSN_CONFIG_DIO_QUERY
:
254 data
[1] = (s
->io_bits
& bits
) ? COMEDI_OUTPUT
: COMEDI_INPUT
;
261 do_3724_config(dev
, s
, insn
->chanspec
);
262 enable_chan(dev
, s
, insn
->chanspec
);
266 static int pcm3724_attach(struct comedi_device
*dev
,
267 struct comedi_devconfig
*it
)
269 unsigned long iobase
;
270 unsigned int iorange
;
271 int ret
, i
, n_subdevices
;
273 iobase
= it
->options
[0];
274 iorange
= this_board
->io_range
;
276 ret
= alloc_private(dev
, sizeof(struct priv_pcm3724
));
280 ((struct priv_pcm3724
*)(dev
->private))->dio_1
= 0;
281 ((struct priv_pcm3724
*)(dev
->private))->dio_2
= 0;
283 printk(KERN_INFO
"comedi%d: pcm3724: board=%s, 0x%03lx ", dev
->minor
,
284 this_board
->name
, iobase
);
285 if (!iobase
|| !request_region(iobase
, iorange
, "pcm3724")) {
286 printk("I/O port conflict\n");
290 dev
->iobase
= iobase
;
291 dev
->board_name
= this_board
->name
;
292 printk(KERN_INFO
"\n");
294 n_subdevices
= this_board
->numofports
;
296 ret
= alloc_subdevices(dev
, n_subdevices
);
300 for (i
= 0; i
< dev
->n_subdevices
; i
++) {
301 subdev_8255_init(dev
, dev
->subdevices
+ i
, subdev_8255_cb
,
302 (unsigned long)(dev
->iobase
+ SIZE_8255
* i
));
303 ((dev
->subdevices
) + i
)->insn_config
= subdev_3724_insn_config
;
308 static int pcm3724_detach(struct comedi_device
*dev
)
312 if (dev
->subdevices
) {
313 for (i
= 0; i
< dev
->n_subdevices
; i
++)
314 subdev_8255_cleanup(dev
, dev
->subdevices
+ i
);
317 release_region(dev
->iobase
, this_board
->io_range
);
322 MODULE_AUTHOR("Comedi http://www.comedi.org");
323 MODULE_DESCRIPTION("Comedi low-level driver");
324 MODULE_LICENSE("GPL");