2 * comedi/drivers/8255.c
5 * COMEDI - Linux Control and Measurement Device Interface
6 * Copyright (C) 1998 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.
21 * Description: generic 8255 support
22 * Devices: [standard] 8255 (8255)
25 * Updated: Fri, 7 Jun 2002 12:56:45 -0700
27 * The classic in digital I/O. The 8255 appears in Comedi as a single
28 * digital I/O subdevice with 24 channels. The channel 0 corresponds
29 * to the 8255's port A, bit 0; channel 23 corresponds to port C, bit
30 * 7. Direction configuration is done in blocks, with channels 0-7,
31 * 8-15, 16-19, and 20-23 making up the 4 blocks. The only 8255 mode
32 * supported is mode 0.
34 * You should enable compilation this driver if you plan to use a board
35 * that has an 8255 chip. For multifunction boards, the main driver will
36 * configure the 8255 subdevice automatically.
38 * This driver also works independently with ISA and PCI cards that
39 * directly map the 8255 registers to I/O ports, including cards with
40 * multiple 8255 chips. To configure the driver for such a card, the
41 * option list should be a list of the I/O port bases for each of the
42 * 8255 chips. For example,
44 * comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c
46 * Note that most PCI 8255 boards do NOT work with this driver, and
47 * need a separate driver as a wrapper. For those that do work, the
48 * I/O port base address can be found in the output of 'lspci -v'.
52 This file contains an exported subdevice for driving an 8255.
54 To use this subdevice as part of another driver, you need to
55 set up the subdevice in the attach function of the driver by
58 subdev_8255_init(device, subdevice, io_function, iobase)
60 device and subdevice are pointers to the device and subdevice
61 structures. io_function will be called to provide the
62 low-level input/output to the device, i.e., actual register
63 access. io_function will be called with the value of iobase
64 as the last parameter. If the 8255 device is mapped as 4
65 consecutive I/O ports, you can use NULL for io_function
66 and the I/O port base for iobase, and an internal function will
67 handle the register access.
69 In addition, if the main driver handles interrupts, you can
70 enable commands on the subdevice by calling subdev_8255_init_irq()
71 instead. Then, when you get an interrupt that is likely to be
72 from the 8255, you should call subdev_8255_interrupt(), which
73 will copy the latched value to a Comedi buffer.
76 #include <linux/module.h>
77 #include "../comedidev.h"
79 #include "comedi_fc.h"
82 struct subdev_8255_private
{
83 unsigned long regbase
;
84 int (*io
)(struct comedi_device
*, int, int, int, unsigned long);
87 static int subdev_8255_io(struct comedi_device
*dev
,
88 int dir
, int port
, int data
, unsigned long regbase
)
91 outb(data
, dev
->iobase
+ regbase
+ port
);
94 return inb(dev
->iobase
+ regbase
+ port
);
97 static int subdev_8255_mmio(struct comedi_device
*dev
,
98 int dir
, int port
, int data
, unsigned long regbase
)
101 writeb(data
, dev
->mmio
+ regbase
+ port
);
104 return readb(dev
->mmio
+ regbase
+ port
);
107 static int subdev_8255_insn(struct comedi_device
*dev
,
108 struct comedi_subdevice
*s
,
109 struct comedi_insn
*insn
,
112 struct subdev_8255_private
*spriv
= s
->private;
113 unsigned long regbase
= spriv
->regbase
;
117 mask
= comedi_dio_update_state(s
, data
);
120 spriv
->io(dev
, 1, I8255_DATA_A_REG
,
121 s
->state
& 0xff, regbase
);
123 spriv
->io(dev
, 1, I8255_DATA_B_REG
,
124 (s
->state
>> 8) & 0xff, regbase
);
126 spriv
->io(dev
, 1, I8255_DATA_C_REG
,
127 (s
->state
>> 16) & 0xff, regbase
);
130 v
= spriv
->io(dev
, 0, I8255_DATA_A_REG
, 0, regbase
);
131 v
|= (spriv
->io(dev
, 0, I8255_DATA_B_REG
, 0, regbase
) << 8);
132 v
|= (spriv
->io(dev
, 0, I8255_DATA_C_REG
, 0, regbase
) << 16);
139 static void subdev_8255_do_config(struct comedi_device
*dev
,
140 struct comedi_subdevice
*s
)
142 struct subdev_8255_private
*spriv
= s
->private;
143 unsigned long regbase
= spriv
->regbase
;
146 config
= I8255_CTRL_CW
;
147 /* 1 in io_bits indicates output, 1 in config indicates input */
148 if (!(s
->io_bits
& 0x0000ff))
149 config
|= I8255_CTRL_A_IO
;
150 if (!(s
->io_bits
& 0x00ff00))
151 config
|= I8255_CTRL_B_IO
;
152 if (!(s
->io_bits
& 0x0f0000))
153 config
|= I8255_CTRL_C_LO_IO
;
154 if (!(s
->io_bits
& 0xf00000))
155 config
|= I8255_CTRL_C_HI_IO
;
157 spriv
->io(dev
, 1, I8255_CTRL_REG
, config
, regbase
);
160 static int subdev_8255_insn_config(struct comedi_device
*dev
,
161 struct comedi_subdevice
*s
,
162 struct comedi_insn
*insn
,
165 unsigned int chan
= CR_CHAN(insn
->chanspec
);
178 ret
= comedi_dio_insn_config(dev
, s
, insn
, data
, mask
);
182 subdev_8255_do_config(dev
, s
);
187 static int __subdev_8255_init(struct comedi_device
*dev
,
188 struct comedi_subdevice
*s
,
189 int (*io
)(struct comedi_device
*,
190 int, int, int, unsigned long),
191 unsigned long regbase
,
194 struct subdev_8255_private
*spriv
;
196 spriv
= comedi_alloc_spriv(s
, sizeof(*spriv
));
203 spriv
->io
= subdev_8255_mmio
;
205 spriv
->io
= subdev_8255_io
;
206 spriv
->regbase
= regbase
;
208 s
->type
= COMEDI_SUBD_DIO
;
209 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
211 s
->range_table
= &range_digital
;
213 s
->insn_bits
= subdev_8255_insn
;
214 s
->insn_config
= subdev_8255_insn_config
;
216 subdev_8255_do_config(dev
, s
);
221 int subdev_8255_init(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
222 int (*io
)(struct comedi_device
*,
223 int, int, int, unsigned long),
224 unsigned long regbase
)
226 return __subdev_8255_init(dev
, s
, io
, regbase
, false);
228 EXPORT_SYMBOL_GPL(subdev_8255_init
);
230 int subdev_8255_mm_init(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
231 int (*io
)(struct comedi_device
*,
232 int, int, int, unsigned long),
233 unsigned long regbase
)
235 return __subdev_8255_init(dev
, s
, io
, regbase
, true);
237 EXPORT_SYMBOL_GPL(subdev_8255_mm_init
);
240 Start of the 8255 standalone device
244 static int dev_8255_attach(struct comedi_device
*dev
,
245 struct comedi_devconfig
*it
)
247 struct comedi_subdevice
*s
;
248 unsigned long iobase
;
252 for (i
= 0; i
< COMEDI_NDEVCONFOPTS
; i
++) {
253 iobase
= it
->options
[i
];
258 dev_warn(dev
->class_dev
, "no devices specified\n");
262 ret
= comedi_alloc_subdevices(dev
, i
);
266 for (i
= 0; i
< dev
->n_subdevices
; i
++) {
267 s
= &dev
->subdevices
[i
];
268 iobase
= it
->options
[i
];
271 * __comedi_request_region() does not set dev->iobase.
273 * For 8255 devices that are manually attached using
274 * comedi_config, the 'iobase' is the actual I/O port
275 * base address of the chip.
277 ret
= __comedi_request_region(dev
, iobase
, I8255_SIZE
);
279 s
->type
= COMEDI_SUBD_UNUSED
;
281 ret
= subdev_8255_init(dev
, s
, NULL
, iobase
);
290 static void dev_8255_detach(struct comedi_device
*dev
)
292 struct comedi_subdevice
*s
;
293 struct subdev_8255_private
*spriv
;
296 for (i
= 0; i
< dev
->n_subdevices
; i
++) {
297 s
= &dev
->subdevices
[i
];
298 if (s
->type
!= COMEDI_SUBD_UNUSED
) {
300 release_region(spriv
->regbase
, I8255_SIZE
);
305 static struct comedi_driver dev_8255_driver
= {
306 .driver_name
= "8255",
307 .module
= THIS_MODULE
,
308 .attach
= dev_8255_attach
,
309 .detach
= dev_8255_detach
,
311 module_comedi_driver(dev_8255_driver
);
313 MODULE_AUTHOR("Comedi http://www.comedi.org");
314 MODULE_DESCRIPTION("Comedi low-level driver");
315 MODULE_LICENSE("GPL");