Commit | Line | Data |
---|---|---|
d1d3cb32 DVC |
1 | /* |
2 | comedi/drivers/ni_daq_dio24.c | |
3 | Driver for National Instruments PCMCIA DAQ-Card DIO-24 | |
4 | Copyright (C) 2002 Daniel Vecino Castel <dvecino@able.es> | |
5 | ||
6 | PCMCIA crap at end of file is adapted from dummy_cs.c 1.31 2001/08/24 12:13:13 | |
7 | from the pcmcia package. | |
8 | The initial developer of the pcmcia dummy_cs.c code is David A. Hinds | |
9 | <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | |
10 | are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | |
11 | ||
12 | This program is free software; you can redistribute it and/or modify | |
13 | it under the terms of the GNU General Public License as published by | |
14 | the Free Software Foundation; either version 2 of the License, or | |
15 | (at your option) any later version. | |
16 | ||
17 | This program is distributed in the hope that it will be useful, | |
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | GNU General Public License for more details. | |
21 | ||
22 | You should have received a copy of the GNU General Public License | |
23 | along with this program; if not, write to the Free Software | |
24 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
25 | ||
26 | ************************************************************************ | |
27 | */ | |
28 | /* | |
29 | Driver: ni_daq_dio24 | |
30 | Description: National Instruments PCMCIA DAQ-Card DIO-24 | |
31 | Author: Daniel Vecino Castel <dvecino@able.es> | |
32 | Devices: [National Instruments] PCMCIA DAQ-Card DIO-24 (ni_daq_dio24) | |
33 | Status: ? | |
34 | Updated: Thu, 07 Nov 2002 21:53:06 -0800 | |
35 | ||
36 | This is just a wrapper around the 8255.o driver to properly handle | |
37 | the PCMCIA interface. | |
38 | */ | |
39 | ||
0a85b6f0 | 40 | /* #define LABPC_DEBUG *//* enable debugging messages */ |
d1d3cb32 DVC |
41 | #undef LABPC_DEBUG |
42 | ||
25436dc9 | 43 | #include <linux/interrupt.h> |
5a0e3ad6 | 44 | #include <linux/slab.h> |
d1d3cb32 DVC |
45 | #include "../comedidev.h" |
46 | ||
47 | #include <linux/ioport.h> | |
d1d3cb32 DVC |
48 | |
49 | #include "8255.h" | |
50 | ||
d1d3cb32 DVC |
51 | #include <pcmcia/cistpl.h> |
52 | #include <pcmcia/cisreg.h> | |
53 | #include <pcmcia/ds.h> | |
54 | ||
73b12a5b | 55 | static struct pcmcia_device *pcmcia_cur_dev; |
d1d3cb32 | 56 | |
2696fb57 | 57 | #define DIO24_SIZE 4 /* size of io region used by board */ |
d1d3cb32 | 58 | |
da91b269 | 59 | static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it); |
484ecc95 | 60 | static void dio24_detach(struct comedi_device *dev); |
d1d3cb32 DVC |
61 | |
62 | enum dio24_bustype { pcmcia_bustype }; | |
63 | ||
cf4c8d1b | 64 | struct dio24_board_struct { |
d1d3cb32 | 65 | const char *name; |
2696fb57 BP |
66 | int device_id; /* device id for pcmcia board */ |
67 | enum dio24_bustype bustype; /* PCMCIA */ | |
68 | int have_dio; /* have 8255 chip */ | |
69 | /* function pointers so we can use inb/outb or readb/writeb as appropriate */ | |
d1d3cb32 DVC |
70 | unsigned int (*read_byte) (unsigned int address); |
71 | void (*write_byte) (unsigned int byte, unsigned int address); | |
cf4c8d1b | 72 | }; |
d1d3cb32 | 73 | |
cf4c8d1b | 74 | static const struct dio24_board_struct dio24_boards[] = { |
d1d3cb32 | 75 | { |
0a85b6f0 MT |
76 | .name = "daqcard-dio24", |
77 | .device_id = 0x475c, /* 0x10b is manufacturer id, 0x475c is device id */ | |
78 | .bustype = pcmcia_bustype, | |
79 | .have_dio = 1, | |
80 | }, | |
d1d3cb32 | 81 | { |
0a85b6f0 MT |
82 | .name = "ni_daq_dio24", |
83 | .device_id = 0x475c, /* 0x10b is manufacturer id, 0x475c is device id */ | |
84 | .bustype = pcmcia_bustype, | |
85 | .have_dio = 1, | |
86 | }, | |
d1d3cb32 DVC |
87 | }; |
88 | ||
89 | /* | |
90 | * Useful for shorthand access to the particular board structure | |
91 | */ | |
cf4c8d1b | 92 | #define thisboard ((const struct dio24_board_struct *)dev->board_ptr) |
d1d3cb32 | 93 | |
344d23e9 BP |
94 | struct dio24_private { |
95 | ||
d1d3cb32 | 96 | int data; /* number of data points left to be taken */ |
344d23e9 BP |
97 | }; |
98 | ||
139dfbdf | 99 | static struct comedi_driver driver_dio24 = { |
68c3dbff BP |
100 | .driver_name = "ni_daq_dio24", |
101 | .module = THIS_MODULE, | |
102 | .attach = dio24_attach, | |
103 | .detach = dio24_detach, | |
8629efa4 | 104 | .num_names = ARRAY_SIZE(dio24_boards), |
68c3dbff BP |
105 | .board_name = &dio24_boards[0].name, |
106 | .offset = sizeof(struct dio24_board_struct), | |
d1d3cb32 DVC |
107 | }; |
108 | ||
da91b269 | 109 | static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it) |
d1d3cb32 | 110 | { |
9a1a6cf8 | 111 | struct dio24_private *devpriv; |
34c43922 | 112 | struct comedi_subdevice *s; |
d1d3cb32 DVC |
113 | unsigned long iobase = 0; |
114 | #ifdef incomplete | |
115 | unsigned int irq = 0; | |
116 | #endif | |
117 | struct pcmcia_device *link; | |
8b6c5694 | 118 | int ret; |
d1d3cb32 | 119 | |
c34fa261 HS |
120 | devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); |
121 | if (!devpriv) | |
122 | return -ENOMEM; | |
123 | dev->private = devpriv; | |
d1d3cb32 | 124 | |
2696fb57 | 125 | /* get base address, irq etc. based on bustype */ |
d1d3cb32 DVC |
126 | switch (thisboard->bustype) { |
127 | case pcmcia_bustype: | |
128 | link = pcmcia_cur_dev; /* XXX hack */ | |
129 | if (!link) | |
130 | return -EIO; | |
9a017a91 | 131 | iobase = link->resource[0]->start; |
d1d3cb32 | 132 | #ifdef incomplete |
eb14120f | 133 | irq = link->irq; |
d1d3cb32 DVC |
134 | #endif |
135 | break; | |
136 | default: | |
1aa301e8 | 137 | pr_err("bug! couldn't determine board type\n"); |
d1d3cb32 DVC |
138 | return -EINVAL; |
139 | break; | |
140 | } | |
1aa301e8 RM |
141 | pr_debug("comedi%d: ni_daq_dio24: %s, io 0x%lx", dev->minor, |
142 | thisboard->name, iobase); | |
d1d3cb32 | 143 | #ifdef incomplete |
ef7908eb | 144 | if (irq) |
1aa301e8 | 145 | pr_debug("irq %u\n", irq); |
d1d3cb32 DVC |
146 | #endif |
147 | ||
d1d3cb32 | 148 | if (iobase == 0) { |
1aa301e8 | 149 | pr_err("io base address is zero!\n"); |
d1d3cb32 DVC |
150 | return -EINVAL; |
151 | } | |
152 | ||
153 | dev->iobase = iobase; | |
154 | ||
155 | #ifdef incomplete | |
156 | /* grab our IRQ */ | |
157 | dev->irq = irq; | |
158 | #endif | |
159 | ||
160 | dev->board_name = thisboard->name; | |
161 | ||
8b6c5694 HS |
162 | ret = comedi_alloc_subdevices(dev, 1); |
163 | if (ret) | |
164 | return ret; | |
d1d3cb32 DVC |
165 | |
166 | /* 8255 dio */ | |
06e915e2 | 167 | s = &dev->subdevices[0]; |
d1d3cb32 DVC |
168 | subdev_8255_init(dev, s, NULL, dev->iobase); |
169 | ||
170 | return 0; | |
171 | }; | |
172 | ||
484ecc95 | 173 | static void dio24_detach(struct comedi_device *dev) |
d1d3cb32 | 174 | { |
06e915e2 HS |
175 | struct comedi_subdevice *s; |
176 | ||
177 | if (dev->subdevices) { | |
178 | s = &dev->subdevices[0]; | |
179 | subdev_8255_cleanup(dev, s); | |
180 | } | |
d1d3cb32 DVC |
181 | if (thisboard->bustype != pcmcia_bustype && dev->iobase) |
182 | release_region(dev->iobase, DIO24_SIZE); | |
183 | if (dev->irq) | |
5f74ea14 | 184 | free_irq(dev->irq, dev); |
d1d3cb32 DVC |
185 | }; |
186 | ||
d1d3cb32 DVC |
187 | static void dio24_config(struct pcmcia_device *link); |
188 | static void dio24_release(struct pcmcia_device *link); | |
189 | static int dio24_cs_suspend(struct pcmcia_device *p_dev); | |
190 | static int dio24_cs_resume(struct pcmcia_device *p_dev); | |
191 | ||
d1d3cb32 DVC |
192 | static int dio24_cs_attach(struct pcmcia_device *); |
193 | static void dio24_cs_detach(struct pcmcia_device *); | |
194 | ||
2ec9f875 | 195 | struct local_info_t { |
d1d3cb32 | 196 | struct pcmcia_device *link; |
d1d3cb32 DVC |
197 | int stop; |
198 | struct bus_operations *bus; | |
2ec9f875 | 199 | }; |
d1d3cb32 | 200 | |
d1d3cb32 DVC |
201 | static int dio24_cs_attach(struct pcmcia_device *link) |
202 | { | |
2ec9f875 | 203 | struct local_info_t *local; |
d1d3cb32 | 204 | |
351be7c9 | 205 | dev_info(&link->dev, "ni_daq_dio24: HOLA SOY YO - CS-attach!\n"); |
d1d3cb32 | 206 | |
55a19b39 | 207 | dev_dbg(&link->dev, "dio24_cs_attach()\n"); |
d1d3cb32 DVC |
208 | |
209 | /* Allocate space for private device-specific data */ | |
2ec9f875 | 210 | local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); |
d1d3cb32 DVC |
211 | if (!local) |
212 | return -ENOMEM; | |
213 | local->link = link; | |
214 | link->priv = local; | |
215 | ||
d1d3cb32 DVC |
216 | pcmcia_cur_dev = link; |
217 | ||
218 | dio24_config(link); | |
219 | ||
220 | return 0; | |
221 | } /* dio24_cs_attach */ | |
222 | ||
d1d3cb32 DVC |
223 | static void dio24_cs_detach(struct pcmcia_device *link) |
224 | { | |
78950591 JMC |
225 | ((struct local_info_t *)link->priv)->stop = 1; |
226 | dio24_release(link); | |
d1d3cb32 DVC |
227 | |
228 | /* This points to the parent local_info_t struct */ | |
f25bd6bf | 229 | kfree(link->priv); |
484ecc95 | 230 | } |
d1d3cb32 | 231 | |
55a19b39 | 232 | static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev, |
55a19b39 | 233 | void *priv_data) |
d1d3cb32 | 234 | { |
00990e7c DB |
235 | if (p_dev->config_index == 0) |
236 | return -EINVAL; | |
c3744138 | 237 | |
00990e7c | 238 | return pcmcia_request_io(p_dev); |
55a19b39 | 239 | } |
d1d3cb32 | 240 | |
55a19b39 DB |
241 | static void dio24_config(struct pcmcia_device *link) |
242 | { | |
55a19b39 | 243 | int ret; |
d1d3cb32 | 244 | |
351be7c9 | 245 | dev_info(&link->dev, "ni_daq_dio24: HOLA SOY YO! - config\n"); |
d1d3cb32 | 246 | |
55a19b39 | 247 | dev_dbg(&link->dev, "dio24_config\n"); |
c3744138 | 248 | |
00990e7c DB |
249 | link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO | |
250 | CONF_AUTO_SET_IO; | |
440eed43 | 251 | |
0f52e86d | 252 | ret = pcmcia_loop_config(link, dio24_pcmcia_config_loop, NULL); |
55a19b39 DB |
253 | if (ret) { |
254 | dev_warn(&link->dev, "no configuration found\n"); | |
255 | goto failed; | |
d1d3cb32 DVC |
256 | } |
257 | ||
eb14120f DB |
258 | if (!link->irq) |
259 | goto failed; | |
d1d3cb32 | 260 | |
1ac71e5a | 261 | ret = pcmcia_enable_device(link); |
55a19b39 DB |
262 | if (ret) |
263 | goto failed; | |
d1d3cb32 | 264 | |
d1d3cb32 DVC |
265 | return; |
266 | ||
55a19b39 | 267 | failed: |
351be7c9 | 268 | dev_info(&link->dev, "Fallo"); |
d1d3cb32 DVC |
269 | dio24_release(link); |
270 | ||
271 | } /* dio24_config */ | |
272 | ||
273 | static void dio24_release(struct pcmcia_device *link) | |
274 | { | |
55a19b39 | 275 | dev_dbg(&link->dev, "dio24_release\n"); |
d1d3cb32 DVC |
276 | |
277 | pcmcia_disable_device(link); | |
278 | } /* dio24_release */ | |
279 | ||
d1d3cb32 DVC |
280 | static int dio24_cs_suspend(struct pcmcia_device *link) |
281 | { | |
2ec9f875 | 282 | struct local_info_t *local = link->priv; |
d1d3cb32 DVC |
283 | |
284 | /* Mark the device as stopped, to block IO until later */ | |
285 | local->stop = 1; | |
286 | return 0; | |
287 | } /* dio24_cs_suspend */ | |
288 | ||
289 | static int dio24_cs_resume(struct pcmcia_device *link) | |
290 | { | |
2ec9f875 | 291 | struct local_info_t *local = link->priv; |
d1d3cb32 DVC |
292 | |
293 | local->stop = 0; | |
294 | return 0; | |
295 | } /* dio24_cs_resume */ | |
296 | ||
297 | /*====================================================================*/ | |
298 | ||
2202a5a7 | 299 | static const struct pcmcia_device_id dio24_cs_ids[] = { |
d1d3cb32 DVC |
300 | /* N.B. These IDs should match those in dio24_boards */ |
301 | PCMCIA_DEVICE_MANF_CARD(0x010b, 0x475c), /* daqcard-dio24 */ | |
302 | PCMCIA_DEVICE_NULL | |
303 | }; | |
304 | ||
305 | MODULE_DEVICE_TABLE(pcmcia, dio24_cs_ids); | |
6c7f8196 AK |
306 | MODULE_AUTHOR("Daniel Vecino Castel <dvecino@able.es>"); |
307 | MODULE_DESCRIPTION("Comedi driver for National Instruments " | |
308 | "PCMCIA DAQ-Card DIO-24"); | |
309 | MODULE_LICENSE("GPL"); | |
d1d3cb32 | 310 | |
3786d4fb | 311 | static struct pcmcia_driver dio24_cs_driver = { |
d1d3cb32 DVC |
312 | .probe = dio24_cs_attach, |
313 | .remove = dio24_cs_detach, | |
314 | .suspend = dio24_cs_suspend, | |
315 | .resume = dio24_cs_resume, | |
316 | .id_table = dio24_cs_ids, | |
317 | .owner = THIS_MODULE, | |
2e9b981a | 318 | .name = "ni_daq_dio24", |
d1d3cb32 DVC |
319 | }; |
320 | ||
321 | static int __init init_dio24_cs(void) | |
322 | { | |
323 | printk("ni_daq_dio24: HOLA SOY YO!\n"); | |
d1d3cb32 DVC |
324 | pcmcia_register_driver(&dio24_cs_driver); |
325 | return 0; | |
326 | } | |
327 | ||
328 | static void __exit exit_dio24_cs(void) | |
329 | { | |
d1d3cb32 DVC |
330 | pcmcia_unregister_driver(&dio24_cs_driver); |
331 | } | |
332 | ||
333 | int __init init_module(void) | |
334 | { | |
335 | int ret; | |
336 | ||
337 | ret = init_dio24_cs(); | |
338 | if (ret < 0) | |
339 | return ret; | |
340 | ||
341 | return comedi_driver_register(&driver_dio24); | |
342 | } | |
343 | ||
344 | void __exit cleanup_module(void) | |
345 | { | |
346 | exit_dio24_cs(); | |
347 | comedi_driver_unregister(&driver_dio24); | |
348 | } |