Staging: comedi: add das08 drivers
[deliverable/linux.git] / drivers / staging / comedi / drivers / das08_cs.c
CommitLineData
0882eaa6
DS
1/*
2 comedi/drivers/das08_cs.c
3 DAS08 driver
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
7 Copyright (C) 2001,2002,2003 Frank Mori Hess <fmhess@users.sourceforge.net>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23*****************************************************************
24
25*/
26/*
27Driver: das08_cs
28Description: DAS-08 PCMCIA boards
29Author: Warren Jasper, ds, Frank Hess
30Devices: [ComputerBoards] PCM-DAS08 (pcm-das08)
31Status: works
32
33This is the PCMCIA-specific support split off from the
34das08 driver.
35
36Options (for pcm-das08):
37 NONE
38
39Command support does not exist, but could be added for this board.
40*/
41
42#include "../comedidev.h"
43
44#include <linux/delay.h>
45#include <linux/pci.h>
46#include <linux/version.h>
47
48#include "das08.h"
49
50// pcmcia includes
51#include <pcmcia/cs_types.h>
52#include <pcmcia/cs.h>
53#include <pcmcia/cistpl.h>
54#include <pcmcia/ds.h>
55
56static struct pcmcia_device *cur_dev = NULL;
57
58#define thisboard ((const struct das08_board_struct *)dev->board_ptr)
59
60static int das08_cs_attach(comedi_device * dev, comedi_devconfig * it);
61
62static comedi_driver driver_das08_cs = {
63 driver_name:"das08_cs",
64 module:THIS_MODULE,
65 attach:das08_cs_attach,
66 detach:das08_common_detach,
67 board_name:&das08_cs_boards[0].name,
68 num_names:sizeof(das08_cs_boards) /
69 sizeof(struct das08_board_struct),
70 offset:sizeof(struct das08_board_struct),
71};
72
73static int das08_cs_attach(comedi_device * dev, comedi_devconfig * it)
74{
75 int ret;
76 unsigned long iobase;
77 struct pcmcia_device *link = cur_dev; // XXX hack
78
79 if ((ret = alloc_private(dev, sizeof(struct das08_private_struct))) < 0)
80 return ret;
81
82 printk("comedi%d: das08_cs: ", dev->minor);
83 // deal with a pci board
84
85 if (thisboard->bustype == pcmcia) {
86 if (link == NULL) {
87 printk(" no pcmcia cards found\n");
88 return -EIO;
89 }
90 iobase = link->io.BasePort1;
91 } else {
92 printk(" bug! board does not have PCMCIA bustype\n");
93 return -EINVAL;
94 }
95
96 printk("\n");
97
98 return das08_common_attach(dev, iobase);
99}
100
101/*======================================================================
102
103 The following pcmcia code for the pcm-das08 is adapted from the
104 dummy_cs.c driver of the Linux PCMCIA Card Services package.
105
106 The initial developer of the original code is David A. Hinds
107 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
108 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
109
110======================================================================*/
111
112/*
113 All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If
114 you do not define PCMCIA_DEBUG at all, all the debug code will be
115 left out. If you compile with PCMCIA_DEBUG=0, the debug code will
116 be present but disabled -- but it can then be enabled for specific
117 modules at load time with a 'pc_debug=#' option to insmod.
118*/
119
120#ifdef PCMCIA_DEBUG
121static int pc_debug = PCMCIA_DEBUG;
122module_param(pc_debug, int, 0644);
123#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
124static const char *version =
125 "das08.c pcmcia code (Frank Hess), modified from dummy_cs.c 1.31 2001/08/24 12:13:13 (David Hinds)";
126#else
127#define DEBUG(n, args...)
128#endif
129
130/*====================================================================*/
131static void das08_pcmcia_config(struct pcmcia_device *link);
132static void das08_pcmcia_release(struct pcmcia_device *link);
133static int das08_pcmcia_suspend(struct pcmcia_device *p_dev);
134static int das08_pcmcia_resume(struct pcmcia_device *p_dev);
135
136/*
137 The attach() and detach() entry points are used to create and destroy
138 "instances" of the driver, where each instance represents everything
139 needed to manage one actual PCMCIA card.
140*/
141
142static int das08_pcmcia_attach(struct pcmcia_device *);
143static void das08_pcmcia_detach(struct pcmcia_device *);
144
145/*
146 You'll also need to prototype all the functions that will actually
147 be used to talk to your device. See 'memory_cs' for a good example
148 of a fully self-sufficient driver; the other drivers rely more or
149 less on other parts of the kernel.
150*/
151
152/*
153 The dev_info variable is the "key" that is used to match up this
154 device driver with appropriate cards, through the card configuration
155 database.
156*/
157
158static const dev_info_t dev_info = "pcm-das08";
159
160typedef struct local_info_t {
161 struct pcmcia_device *link;
162 dev_node_t node;
163 int stop;
164 struct bus_operations *bus;
165} local_info_t;
166
167/*======================================================================
168
169 das08_pcmcia_attach() creates an "instance" of the driver, allocating
170 local data structures for one device. The device is registered
171 with Card Services.
172
173 The dev_link structure is initialized, but we don't actually
174 configure the card at this point -- we wait until we receive a
175 card insertion event.
176
177======================================================================*/
178
179static int das08_pcmcia_attach(struct pcmcia_device *link)
180{
181 local_info_t *local;
182
183 DEBUG(0, "das08_pcmcia_attach()\n");
184
185 /* Allocate space for private device-specific data */
186 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
187 if (!local)
188 return -ENOMEM;
189 local->link = link;
190 link->priv = local;
191
192 /* Interrupt setup */
193 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
194 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
195 link->irq.Handler = NULL;
196
197 /*
198 General socket configuration defaults can go here. In this
199 client, we assume very little, and rely on the CIS for almost
200 everything. In most clients, many details (i.e., number, sizes,
201 and attributes of IO windows) are fixed by the nature of the
202 device, and can be hard-wired here.
203 */
204 link->conf.Attributes = 0;
205 link->conf.IntType = INT_MEMORY_AND_IO;
206
207 cur_dev = link;
208
209 das08_pcmcia_config(link);
210
211 return 0;
212} /* das08_pcmcia_attach */
213
214/*======================================================================
215
216 This deletes a driver "instance". The device is de-registered
217 with Card Services. If it has been released, all local data
218 structures are freed. Otherwise, the structures will be freed
219 when the device is released.
220
221======================================================================*/
222
223static void das08_pcmcia_detach(struct pcmcia_device *link)
224{
225
226 DEBUG(0, "das08_pcmcia_detach(0x%p)\n", link);
227
228 if (link->dev_node) {
229 ((local_info_t *) link->priv)->stop = 1;
230 das08_pcmcia_release(link);
231 }
232
233 /* This points to the parent local_info_t struct */
234 if (link->priv)
235 kfree(link->priv);
236
237} /* das08_pcmcia_detach */
238
239/*======================================================================
240
241 das08_pcmcia_config() is scheduled to run after a CARD_INSERTION event
242 is received, to configure the PCMCIA socket, and to make the
243 device available to the system.
244
245======================================================================*/
246
247static void das08_pcmcia_config(struct pcmcia_device *link)
248{
249 local_info_t *dev = link->priv;
250 tuple_t tuple;
251 cisparse_t parse;
252 int last_fn, last_ret;
253 u_char buf[64];
254 cistpl_cftable_entry_t dflt = { 0 };
255
256 DEBUG(0, "das08_pcmcia_config(0x%p)\n", link);
257
258 /*
259 This reads the card's CONFIG tuple to find its configuration
260 registers.
261 */
262 tuple.DesiredTuple = CISTPL_CONFIG;
263 tuple.Attributes = 0;
264 tuple.TupleData = buf;
265 tuple.TupleDataMax = sizeof(buf);
266 tuple.TupleOffset = 0;
267 last_fn = GetFirstTuple;
268 if ((last_ret = pcmcia_get_first_tuple(link, &tuple)) != 0)
269 goto cs_failed;
270 last_fn = GetTupleData;
271 if ((last_ret = pcmcia_get_tuple_data(link, &tuple)) != 0)
272 goto cs_failed;
273 last_fn = ParseTuple;
274 if ((last_ret = pcmcia_parse_tuple(&tuple, &parse)) != 0)
275 goto cs_failed;
276 link->conf.ConfigBase = parse.config.base;
277 link->conf.Present = parse.config.rmask[0];
278
279 /*
280 In this loop, we scan the CIS for configuration table entries,
281 each of which describes a valid card configuration, including
282 voltage, IO window, memory window, and interrupt settings.
283
284 We make no assumptions about the card to be configured: we use
285 just the information available in the CIS. In an ideal world,
286 this would work for any PCMCIA card, but it requires a complete
287 and accurate CIS. In practice, a driver usually "knows" most of
288 these things without consulting the CIS, and most client drivers
289 will only use the CIS to fill in implementation-defined details.
290 */
291 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
292 last_fn = GetFirstTuple;
293 if ((last_ret = pcmcia_get_first_tuple(link, &tuple)) != 0)
294 goto cs_failed;
295 while (1) {
296 cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
297 if ((last_ret = pcmcia_get_tuple_data(link, &tuple)) != 0)
298 goto next_entry;
299 if ((last_ret = pcmcia_parse_tuple(&tuple, &parse)) != 0)
300 goto next_entry;
301
302 if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
303 dflt = *cfg;
304 if (cfg->index == 0)
305 goto next_entry;
306 link->conf.ConfigIndex = cfg->index;
307
308 /* Does this card need audio output? */
309/* if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
310 link->conf.Attributes |= CONF_ENABLE_SPKR;
311 link->conf.Status = CCSR_AUDIO_ENA;
312 }
313*/
314 /* Do we need to allocate an interrupt? */
315 if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
316 link->conf.Attributes |= CONF_ENABLE_IRQ;
317
318 /* IO window settings */
319 link->io.NumPorts1 = link->io.NumPorts2 = 0;
320 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
321 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
322 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
323 if (!(io->flags & CISTPL_IO_8BIT))
324 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
325 if (!(io->flags & CISTPL_IO_16BIT))
326 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
327 link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
328 link->io.BasePort1 = io->win[0].base;
329 link->io.NumPorts1 = io->win[0].len;
330 if (io->nwin > 1) {
331 link->io.Attributes2 = link->io.Attributes1;
332 link->io.BasePort2 = io->win[1].base;
333 link->io.NumPorts2 = io->win[1].len;
334 }
335 /* This reserves IO space but doesn't actually enable it */
336 if (pcmcia_request_io(link, &link->io) != 0)
337 goto next_entry;
338 }
339
340 /* If we got this far, we're cool! */
341 break;
342
343 next_entry:
344 last_fn = GetNextTuple;
345 if ((last_ret = pcmcia_get_next_tuple(link, &tuple)) != 0)
346 goto cs_failed;
347 }
348
349 if (link->conf.Attributes & CONF_ENABLE_IRQ) {
350 last_fn = RequestIRQ;
351 if ((last_ret = pcmcia_request_irq(link, &link->irq)) != 0)
352 goto cs_failed;
353 }
354
355 /*
356 This actually configures the PCMCIA socket -- setting up
357 the I/O windows and the interrupt mapping, and putting the
358 card and host interface into "Memory and IO" mode.
359 */
360 last_fn = RequestConfiguration;
361 if ((last_ret = pcmcia_request_configuration(link, &link->conf)) != 0)
362 goto cs_failed;
363
364 /*
365 At this point, the dev_node_t structure(s) need to be
366 initialized and arranged in a linked list at link->dev.
367 */
368 sprintf(dev->node.dev_name, "pcm-das08");
369 dev->node.major = dev->node.minor = 0;
370 link->dev_node = &dev->node;
371
372 /* Finally, report what we've done */
373 printk(KERN_INFO "%s: index 0x%02x",
374 dev->node.dev_name, link->conf.ConfigIndex);
375 if (link->conf.Attributes & CONF_ENABLE_IRQ)
376 printk(", irq %u", link->irq.AssignedIRQ);
377 if (link->io.NumPorts1)
378 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
379 link->io.BasePort1 + link->io.NumPorts1 - 1);
380 if (link->io.NumPorts2)
381 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
382 link->io.BasePort2 + link->io.NumPorts2 - 1);
383 printk("\n");
384
385 return;
386
387 cs_failed:
388 cs_error(link, last_fn, last_ret);
389 das08_pcmcia_release(link);
390
391} /* das08_pcmcia_config */
392
393/*======================================================================
394
395 After a card is removed, das08_pcmcia_release() will unregister the
396 device, and release the PCMCIA configuration. If the device is
397 still open, this will be postponed until it is closed.
398
399======================================================================*/
400
401static void das08_pcmcia_release(struct pcmcia_device *link)
402{
403 DEBUG(0, "das08_pcmcia_release(0x%p)\n", link);
404 pcmcia_disable_device(link);
405} /* das08_pcmcia_release */
406
407/*======================================================================
408
409 The card status event handler. Mostly, this schedules other
410 stuff to run after an event is received.
411
412 When a CARD_REMOVAL event is received, we immediately set a
413 private flag to block future accesses to this device. All the
414 functions that actually access the device should check this flag
415 to make sure the card is still present.
416
417======================================================================*/
418
419static int das08_pcmcia_suspend(struct pcmcia_device *link)
420{
421 local_info_t *local = link->priv;
422 /* Mark the device as stopped, to block IO until later */
423 local->stop = 1;
424
425 return 0;
426} /* das08_pcmcia_suspend */
427
428static int das08_pcmcia_resume(struct pcmcia_device *link)
429{
430 local_info_t *local = link->priv;
431
432 local->stop = 0;
433 return 0;
434} /* das08_pcmcia_resume */
435
436/*====================================================================*/
437
438static struct pcmcia_device_id das08_cs_id_table[] = {
439 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4001),
440 PCMCIA_DEVICE_NULL
441};
442
443MODULE_DEVICE_TABLE(pcmcia, das08_cs_id_table);
444
445struct pcmcia_driver das08_cs_driver = {
446 .probe = das08_pcmcia_attach,
447 .remove = das08_pcmcia_detach,
448 .suspend = das08_pcmcia_suspend,
449 .resume = das08_pcmcia_resume,
450 .id_table = das08_cs_id_table,
451 .owner = THIS_MODULE,
452 .drv = {
453 .name = dev_info,
454 },
455};
456
457static int __init init_das08_pcmcia_cs(void)
458{
459 DEBUG(0, "%s\n", version);
460 pcmcia_register_driver(&das08_cs_driver);
461 return 0;
462}
463
464static void __exit exit_das08_pcmcia_cs(void)
465{
466 DEBUG(0, "das08_pcmcia_cs: unloading\n");
467 pcmcia_unregister_driver(&das08_cs_driver);
468}
469
470static int __init das08_cs_init_module(void)
471{
472 int ret;
473
474 ret = init_das08_pcmcia_cs();
475 if (ret < 0)
476 return ret;
477
478 return comedi_driver_register(&driver_das08_cs);
479}
480
481static void __exit das08_cs_exit_module(void)
482{
483 exit_das08_pcmcia_cs();
484 comedi_driver_unregister(&driver_das08_cs);
485}
486
487MODULE_LICENSE("GPL");
488module_init(das08_cs_init_module);
489module_exit(das08_cs_exit_module);
This page took 0.053555 seconds and 5 git commands to generate.