Commit | Line | Data |
---|---|---|
b3c1e463 MD |
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: | |
18653919 | 20 | 0, 144: 144 DIO configuration |
b3c1e463 MD |
21 | 1, 96: 96 DIO configuration |
22 | */ | |
23 | /* | |
24 | Driver: pcl724 | |
25 | Description: Advantech PCL-724, PCL-722, PCL-731 ADLink ACL-7122, ACL-7124, | |
26 | PET-48DIO | |
27 | Author: Michal Dobes <dobes@tesnet.cz> | |
28 | Devices: [Advantech] PCL-724 (pcl724), PCL-722 (pcl722), PCL-731 (pcl731), | |
29 | [ADLink] ACL-7122 (acl7122), ACL-7124 (acl7124), PET-48DIO (pet48dio) | |
30 | Status: untested | |
31 | ||
32 | This is driver for digital I/O boards PCL-722/724/731 with 144/24/48 DIO | |
33 | and for digital I/O boards ACL-7122/7124/PET-48DIO with 144/24/48 DIO. | |
34 | It need 8255.o for operations and only immediate mode is supported. | |
35 | See the source for configuration details. | |
36 | */ | |
37 | /* | |
38 | * check_driver overrides: | |
90035c08 | 39 | * struct comedi_insn |
b3c1e463 MD |
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 | ||
701a91f1 | 57 | /* #define PCL724_IRQ 1 no IRQ support now */ |
b3c1e463 | 58 | |
0a85b6f0 MT |
59 | static int pcl724_attach(struct comedi_device *dev, |
60 | struct comedi_devconfig *it); | |
da91b269 | 61 | static int pcl724_detach(struct comedi_device *dev); |
b3c1e463 | 62 | |
01820e02 BP |
63 | struct pcl724_board { |
64 | ||
701a91f1 BP |
65 | const char *name; /* board name */ |
66 | int dio; /* num of DIO */ | |
67 | int numofports; /* num of 8255 subdevices */ | |
68 | unsigned int IRQbits; /* allowed interrupts */ | |
69 | unsigned int io_range; /* len of IO space */ | |
b3c1e463 MD |
70 | char can_have96; |
71 | char is_pet48; | |
01820e02 BP |
72 | }; |
73 | ||
01820e02 | 74 | static const struct pcl724_board boardtypes[] = { |
b3c1e463 MD |
75 | {"pcl724", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,}, |
76 | {"pcl722", 144, 6, 0x00fc, PCL722_SIZE, 1, 0,}, | |
77 | {"pcl731", 48, 2, 0x9cfc, PCL731_SIZE, 0, 0,}, | |
78 | {"acl7122", 144, 6, 0x9ee8, PCL722_SIZE, 1, 0,}, | |
79 | {"acl7124", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,}, | |
80 | {"pet48dio", 48, 2, 0x9eb8, PET48_SIZE, 0, 1,}, | |
81 | }; | |
82 | ||
01820e02 BP |
83 | #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl724_board)) |
84 | #define this_board ((const struct pcl724_board *)dev->board_ptr) | |
b3c1e463 | 85 | |
139dfbdf | 86 | static struct comedi_driver driver_pcl724 = { |
68c3dbff BP |
87 | .driver_name = "pcl724", |
88 | .module = THIS_MODULE, | |
89 | .attach = pcl724_attach, | |
90 | .detach = pcl724_detach, | |
91 | .board_name = &boardtypes[0].name, | |
92 | .num_names = n_boardtypes, | |
93 | .offset = sizeof(struct pcl724_board), | |
b3c1e463 MD |
94 | }; |
95 | ||
7114a280 AT |
96 | static int __init driver_pcl724_init_module(void) |
97 | { | |
98 | return comedi_driver_register(&driver_pcl724); | |
99 | } | |
100 | ||
101 | static void __exit driver_pcl724_cleanup_module(void) | |
102 | { | |
103 | comedi_driver_unregister(&driver_pcl724); | |
104 | } | |
105 | ||
106 | module_init(driver_pcl724_init_module); | |
107 | module_exit(driver_pcl724_cleanup_module); | |
b3c1e463 MD |
108 | |
109 | static int subdev_8255_cb(int dir, int port, int data, unsigned long arg) | |
110 | { | |
111 | unsigned long iobase = arg; | |
112 | ||
113 | if (dir) { | |
114 | outb(data, iobase + port); | |
115 | return 0; | |
116 | } else { | |
117 | return inb(iobase + port); | |
118 | } | |
119 | } | |
120 | ||
121 | static int subdev_8255mapped_cb(int dir, int port, int data, | |
0a85b6f0 | 122 | unsigned long iobase) |
b3c1e463 MD |
123 | { |
124 | int movport = SIZE_8255 * (iobase >> 12); | |
125 | ||
126 | iobase &= 0x0fff; | |
127 | ||
128 | if (dir) { | |
129 | outb(port + movport, iobase); | |
130 | outb(data, iobase + 1); | |
131 | return 0; | |
132 | } else { | |
133 | outb(port + movport, iobase); | |
134 | return inb(iobase + 1); | |
135 | } | |
136 | } | |
137 | ||
da91b269 | 138 | static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it) |
b3c1e463 MD |
139 | { |
140 | unsigned long iobase; | |
141 | unsigned int iorange; | |
142 | int ret, i, n_subdevices; | |
143 | #ifdef PCL724_IRQ | |
144 | unsigned int irq; | |
145 | #endif | |
146 | ||
147 | iobase = it->options[0]; | |
148 | iorange = this_board->io_range; | |
149 | if ((this_board->can_have96) && ((it->options[1] == 1) | |
0a85b6f0 | 150 | || (it->options[1] == 96))) |
18653919 BA |
151 | iorange = PCL722_96_SIZE; /* PCL-724 in 96 DIO configuration */ |
152 | printk(KERN_INFO "comedi%d: pcl724: board=%s, 0x%03lx ", dev->minor, | |
0a85b6f0 | 153 | this_board->name, iobase); |
b3c1e463 MD |
154 | if (!request_region(iobase, iorange, "pcl724")) { |
155 | printk("I/O port conflict\n"); | |
156 | return -EIO; | |
157 | } | |
158 | ||
159 | dev->iobase = iobase; | |
160 | ||
161 | dev->board_name = this_board->name; | |
162 | ||
163 | #ifdef PCL724_IRQ | |
164 | irq = 0; | |
165 | if (this_board->IRQbits != 0) { /* board support IRQ */ | |
166 | irq = it->options[1]; | |
167 | if (irq) { /* we want to use IRQ */ | |
168 | if (((1 << irq) & this_board->IRQbits) == 0) { | |
18653919 BA |
169 | printk(KERN_WARNING |
170 | ", IRQ %u is out of allowed range, " | |
171 | "DISABLING IT", irq); | |
b3c1e463 MD |
172 | irq = 0; /* Bad IRQ */ |
173 | } else { | |
0a85b6f0 MT |
174 | if (request_irq |
175 | (irq, interrupt_pcl724, 0, "pcl724", dev)) { | |
18653919 BA |
176 | printk(KERN_WARNING |
177 | ", unable to allocate IRQ %u, " | |
178 | "DISABLING IT", irq); | |
b3c1e463 MD |
179 | irq = 0; /* Can't use IRQ */ |
180 | } else { | |
5f74ea14 | 181 | printk(", irq=%u", irq); |
b3c1e463 MD |
182 | } |
183 | } | |
184 | } | |
185 | } | |
186 | ||
187 | dev->irq = irq; | |
188 | #endif | |
189 | ||
190 | printk("\n"); | |
191 | ||
192 | n_subdevices = this_board->numofports; | |
193 | if ((this_board->can_have96) && ((it->options[1] == 1) | |
0a85b6f0 | 194 | || (it->options[1] == 96))) |
701a91f1 | 195 | n_subdevices = 4; /* PCL-724 in 96 DIO configuration */ |
b3c1e463 | 196 | |
c3744138 BP |
197 | ret = alloc_subdevices(dev, n_subdevices); |
198 | if (ret < 0) | |
b3c1e463 MD |
199 | return ret; |
200 | ||
201 | for (i = 0; i < dev->n_subdevices; i++) { | |
202 | if (this_board->is_pet48) { | |
203 | subdev_8255_init(dev, dev->subdevices + i, | |
0a85b6f0 MT |
204 | subdev_8255mapped_cb, |
205 | (unsigned long)(dev->iobase + | |
206 | i * 0x1000)); | |
b3c1e463 MD |
207 | } else |
208 | subdev_8255_init(dev, dev->subdevices + i, | |
0a85b6f0 MT |
209 | subdev_8255_cb, |
210 | (unsigned long)(dev->iobase + | |
211 | SIZE_8255 * i)); | |
b3c1e463 MD |
212 | }; |
213 | ||
214 | return 0; | |
215 | } | |
216 | ||
da91b269 | 217 | static int pcl724_detach(struct comedi_device *dev) |
b3c1e463 MD |
218 | { |
219 | int i; | |
220 | ||
18653919 | 221 | /* printk("comedi%d: pcl724: remove\n",dev->minor); */ |
b3c1e463 | 222 | |
18653919 | 223 | for (i = 0; i < dev->n_subdevices; i++) |
b3c1e463 | 224 | subdev_8255_cleanup(dev, dev->subdevices + i); |
b3c1e463 MD |
225 | |
226 | #ifdef PCL724_IRQ | |
18653919 | 227 | if (dev->irq) |
5f74ea14 | 228 | free_irq(dev->irq, dev); |
b3c1e463 MD |
229 | #endif |
230 | ||
231 | release_region(dev->iobase, this_board->io_range); | |
232 | ||
233 | return 0; | |
234 | } | |
90f703d3 AT |
235 | |
236 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
237 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
238 | MODULE_LICENSE("GPL"); |