pcl724.c revision b3c1e463b76a338f164ec5e5d3b8a55aeeb8c076
1/*
2    comedi/drivers/pcl724.c
3
4    Michal Dobes <dobes@tesnet.cz>
5
6    hardware driver for Advantech cards:
7     card:   PCL-724, PCL-722, PCL-731
8     driver: pcl724,  pcl722,  pcl731
9    and ADLink cards:
10     card:   ACL-7122, ACL-7124, PET-48DIO
11     driver: acl7122,  acl7124,  pet48dio
12
13    Options for PCL-724, PCL-731, ACL-7124 and PET-48DIO:
14     [0] - IO Base
15
16    Options for PCL-722 and ACL-7122:
17     [0] - IO Base
18     [1] - IRQ (0=disable IRQ) IRQ isn't supported at this time!
19     [2] -number of DIO:
20              0, 144: 144 DIO configuration
21	      1,  96:  96 DIO configuration
22*/
23/*
24Driver: pcl724
25Description: Advantech PCL-724, PCL-722, PCL-731 ADLink ACL-7122, ACL-7124,
26  PET-48DIO
27Author: Michal Dobes <dobes@tesnet.cz>
28Devices: [Advantech] PCL-724 (pcl724), PCL-722 (pcl722), PCL-731 (pcl731),
29  [ADLink] ACL-7122 (acl7122), ACL-7124 (acl7124), PET-48DIO (pet48dio)
30Status: untested
31
32This is driver for digital I/O boards PCL-722/724/731 with 144/24/48 DIO
33and for digital I/O boards ACL-7122/7124/PET-48DIO with 144/24/48 DIO.
34It need 8255.o for operations and only immediate mode is supported.
35See the source for configuration details.
36*/
37/*
38 * check_driver overrides:
39 *   comedi_insn
40 */
41
42#include "../comedidev.h"
43
44#include <linux/ioport.h>
45#include <linux/delay.h>
46
47#include "8255.h"
48
49#define PCL722_SIZE    32
50#define PCL722_96_SIZE 16
51#define PCL724_SIZE     4
52#define PCL731_SIZE     8
53#define PET48_SIZE      2
54
55#define SIZE_8255	4
56
57// #define PCL724_IRQ   1  /* no IRQ support now */
58
59static int pcl724_attach(comedi_device * dev, comedi_devconfig * it);
60static int pcl724_detach(comedi_device * dev);
61
62typedef struct {
63	const char *name;	// board name
64	int dio;		// num of DIO
65	int numofports;		// num of 8255 subdevices
66	unsigned int IRQbits;	// allowed interrupts
67	unsigned int io_range;	// len of IO space
68	char can_have96;
69	char is_pet48;
70} boardtype;
71
72static const boardtype boardtypes[] = {
73	{"pcl724", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,},
74	{"pcl722", 144, 6, 0x00fc, PCL722_SIZE, 1, 0,},
75	{"pcl731", 48, 2, 0x9cfc, PCL731_SIZE, 0, 0,},
76	{"acl7122", 144, 6, 0x9ee8, PCL722_SIZE, 1, 0,},
77	{"acl7124", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,},
78	{"pet48dio", 48, 2, 0x9eb8, PET48_SIZE, 0, 1,},
79};
80
81#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
82#define this_board ((const boardtype *)dev->board_ptr)
83
84static comedi_driver driver_pcl724 = {
85      driver_name:"pcl724",
86      module:THIS_MODULE,
87      attach:pcl724_attach,
88      detach:pcl724_detach,
89      board_name:&boardtypes[0].name,
90      num_names:n_boardtypes,
91      offset:sizeof(boardtype),
92};
93
94COMEDI_INITCLEANUP(driver_pcl724);
95
96static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
97{
98	unsigned long iobase = arg;
99
100	if (dir) {
101		outb(data, iobase + port);
102		return 0;
103	} else {
104		return inb(iobase + port);
105	}
106}
107
108static int subdev_8255mapped_cb(int dir, int port, int data,
109	unsigned long iobase)
110{
111	int movport = SIZE_8255 * (iobase >> 12);
112
113	iobase &= 0x0fff;
114
115	if (dir) {
116		outb(port + movport, iobase);
117		outb(data, iobase + 1);
118		return 0;
119	} else {
120		outb(port + movport, iobase);
121		return inb(iobase + 1);
122	}
123}
124
125static int pcl724_attach(comedi_device * dev, comedi_devconfig * it)
126{
127	unsigned long iobase;
128	unsigned int iorange;
129	int ret, i, n_subdevices;
130#ifdef PCL724_IRQ
131	unsigned int irq;
132#endif
133
134	iobase = it->options[0];
135	iorange = this_board->io_range;
136	if ((this_board->can_have96) && ((it->options[1] == 1)
137			|| (it->options[1] == 96)))
138		iorange = PCL722_96_SIZE;	// PCL-724 in 96 DIO configuration
139	printk("comedi%d: pcl724: board=%s, 0x%03lx ", dev->minor,
140		this_board->name, iobase);
141	if (!request_region(iobase, iorange, "pcl724")) {
142		printk("I/O port conflict\n");
143		return -EIO;
144	}
145
146	dev->iobase = iobase;
147
148	dev->board_name = this_board->name;
149
150#ifdef PCL724_IRQ
151	irq = 0;
152	if (this_board->IRQbits != 0) {	/* board support IRQ */
153		irq = it->options[1];
154		if (irq) {	/* we want to use IRQ */
155			if (((1 << irq) & this_board->IRQbits) == 0) {
156				rt_printk
157					(", IRQ %u is out of allowed range, DISABLING IT",
158					irq);
159				irq = 0;	/* Bad IRQ */
160			} else {
161				if (comedi_request_irq(irq, interrupt_pcl724, 0,
162						"pcl724", dev)) {
163					rt_printk
164						(", unable to allocate IRQ %u, DISABLING IT",
165						irq);
166					irq = 0;	/* Can't use IRQ */
167				} else {
168					rt_printk(", irq=%u", irq);
169				}
170			}
171		}
172	}
173
174	dev->irq = irq;
175#endif
176
177	printk("\n");
178
179	n_subdevices = this_board->numofports;
180	if ((this_board->can_have96) && ((it->options[1] == 1)
181			|| (it->options[1] == 96)))
182		n_subdevices = 4;	// PCL-724 in 96 DIO configuration
183
184	if ((ret = alloc_subdevices(dev, n_subdevices)) < 0)
185		return ret;
186
187	for (i = 0; i < dev->n_subdevices; i++) {
188		if (this_board->is_pet48) {
189			subdev_8255_init(dev, dev->subdevices + i,
190				subdev_8255mapped_cb,
191				(unsigned long)(dev->iobase + i * 0x1000));
192		} else
193			subdev_8255_init(dev, dev->subdevices + i,
194				subdev_8255_cb,
195				(unsigned long)(dev->iobase + SIZE_8255 * i));
196	};
197
198	return 0;
199}
200
201static int pcl724_detach(comedi_device * dev)
202{
203	int i;
204
205//      printk("comedi%d: pcl724: remove\n",dev->minor);
206
207	for (i = 0; i < dev->n_subdevices; i++) {
208		subdev_8255_cleanup(dev, dev->subdevices + i);
209	}
210
211#ifdef PCL724_IRQ
212	if (dev->irq) {
213		comedi_free_irq(dev->irq, dev);
214	}
215#endif
216
217	release_region(dev->iobase, this_board->io_range);
218
219	return 0;
220}
221