Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6-block.git] / drivers / staging / comedi / drivers / das08_cs.c
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 /*
27 Driver: das08_cs
28 Description: DAS-08 PCMCIA boards
29 Author: Warren Jasper, ds, Frank Hess
30 Devices: [ComputerBoards] PCM-DAS08 (pcm-das08)
31 Status: works
32
33 This is the PCMCIA-specific support split off from the
34 das08 driver.
35
36 Options (for pcm-das08):
37         NONE
38
39 Command 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
47 #include "das08.h"
48
49 /* pcmcia includes */
50 #include <pcmcia/cs_types.h>
51 #include <pcmcia/cs.h>
52 #include <pcmcia/cistpl.h>
53 #include <pcmcia/ds.h>
54
55 static struct pcmcia_device *cur_dev;
56
57 #define thisboard ((const struct das08_board_struct *)dev->board_ptr)
58
59 static int das08_cs_attach(struct comedi_device *dev,
60                            struct comedi_devconfig *it);
61
62 static struct 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 = ARRAY_SIZE(das08_cs_boards),
69         .offset = sizeof(struct das08_board_struct),
70 };
71
72 static int das08_cs_attach(struct comedi_device *dev,
73                            struct comedi_devconfig *it)
74 {
75         int ret;
76         unsigned long iobase;
77         struct pcmcia_device *link = cur_dev;   /*  XXX hack */
78
79         ret = alloc_private(dev, sizeof(struct das08_private_struct));
80         if (ret < 0)
81                 return ret;
82
83         printk("comedi%d: das08_cs: ", dev->minor);
84         /*  deal with a pci board */
85
86         if (thisboard->bustype == pcmcia) {
87                 if (link == NULL) {
88                         printk(" no pcmcia cards found\n");
89                         return -EIO;
90                 }
91                 iobase = link->io.BasePort1;
92         } else {
93                 printk(" bug! board does not have PCMCIA bustype\n");
94                 return -EINVAL;
95         }
96
97         printk("\n");
98
99         return das08_common_attach(dev, iobase);
100 }
101
102 /*======================================================================
103
104     The following pcmcia code for the pcm-das08 is adapted from the
105     dummy_cs.c driver of the Linux PCMCIA Card Services package.
106
107     The initial developer of the original code is David A. Hinds
108     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
109     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
110
111 ======================================================================*/
112
113 static void das08_pcmcia_config(struct pcmcia_device *link);
114 static void das08_pcmcia_release(struct pcmcia_device *link);
115 static int das08_pcmcia_suspend(struct pcmcia_device *p_dev);
116 static int das08_pcmcia_resume(struct pcmcia_device *p_dev);
117
118 /*
119    The attach() and detach() entry points are used to create and destroy
120    "instances" of the driver, where each instance represents everything
121    needed to manage one actual PCMCIA card.
122 */
123
124 static int das08_pcmcia_attach(struct pcmcia_device *);
125 static void das08_pcmcia_detach(struct pcmcia_device *);
126
127 /*
128    You'll also need to prototype all the functions that will actually
129    be used to talk to your device.  See 'memory_cs' for a good example
130    of a fully self-sufficient driver; the other drivers rely more or
131    less on other parts of the kernel.
132 */
133
134 /*
135    The dev_info variable is the "key" that is used to match up this
136    device driver with appropriate cards, through the card configuration
137    database.
138 */
139
140 static const dev_info_t dev_info = "pcm-das08";
141
142 struct local_info_t {
143         struct pcmcia_device *link;
144         dev_node_t node;
145         int stop;
146         struct bus_operations *bus;
147 };
148
149 /*======================================================================
150
151     das08_pcmcia_attach() creates an "instance" of the driver, allocating
152     local data structures for one device.  The device is registered
153     with Card Services.
154
155     The dev_link structure is initialized, but we don't actually
156     configure the card at this point -- we wait until we receive a
157     card insertion event.
158
159 ======================================================================*/
160
161 static int das08_pcmcia_attach(struct pcmcia_device *link)
162 {
163         struct local_info_t *local;
164
165         dev_dbg(&link->dev, "das08_pcmcia_attach()\n");
166
167         /* Allocate space for private device-specific data */
168         local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
169         if (!local)
170                 return -ENOMEM;
171         local->link = link;
172         link->priv = local;
173
174         /* Interrupt setup */
175         link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
176         link->irq.Handler = NULL;
177
178         /*
179            General socket configuration defaults can go here.  In this
180            client, we assume very little, and rely on the CIS for almost
181            everything.  In most clients, many details (i.e., number, sizes,
182            and attributes of IO windows) are fixed by the nature of the
183            device, and can be hard-wired here.
184          */
185         link->conf.Attributes = 0;
186         link->conf.IntType = INT_MEMORY_AND_IO;
187
188         cur_dev = link;
189
190         das08_pcmcia_config(link);
191
192         return 0;
193 }                               /* das08_pcmcia_attach */
194
195 /*======================================================================
196
197     This deletes a driver "instance".  The device is de-registered
198     with Card Services.  If it has been released, all local data
199     structures are freed.  Otherwise, the structures will be freed
200     when the device is released.
201
202 ======================================================================*/
203
204 static void das08_pcmcia_detach(struct pcmcia_device *link)
205 {
206
207         dev_dbg(&link->dev, "das08_pcmcia_detach\n");
208
209         if (link->dev_node) {
210                 ((struct local_info_t *)link->priv)->stop = 1;
211                 das08_pcmcia_release(link);
212         }
213
214         /* This points to the parent struct local_info_t struct */
215         if (link->priv)
216                 kfree(link->priv);
217
218 }                               /* das08_pcmcia_detach */
219
220
221 static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev,
222                                 cistpl_cftable_entry_t *cfg,
223                                 cistpl_cftable_entry_t *dflt,
224                                 unsigned int vcc,
225                                 void *priv_data)
226 {
227         if (cfg->index == 0)
228                 return -ENODEV;
229
230         /* Do we need to allocate an interrupt? */
231         if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
232                 p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
233
234         /* IO window settings */
235         p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
236         if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
237                 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
238                 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
239                 if (!(io->flags & CISTPL_IO_8BIT))
240                         p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
241                 if (!(io->flags & CISTPL_IO_16BIT))
242                         p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
243                 p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
244                 p_dev->io.BasePort1 = io->win[0].base;
245                 p_dev->io.NumPorts1 = io->win[0].len;
246                 if (io->nwin > 1) {
247                         p_dev->io.Attributes2 = p_dev->io.Attributes1;
248                         p_dev->io.BasePort2 = io->win[1].base;
249                         p_dev->io.NumPorts2 = io->win[1].len;
250                 }
251                 /* This reserves IO space but doesn't actually enable it */
252                 return pcmcia_request_io(p_dev, &p_dev->io);
253         }
254         return 0;
255 }
256
257
258 /*======================================================================
259
260     das08_pcmcia_config() is scheduled to run after a CARD_INSERTION event
261     is received, to configure the PCMCIA socket, and to make the
262     device available to the system.
263
264 ======================================================================*/
265
266 static void das08_pcmcia_config(struct pcmcia_device *link)
267 {
268         struct local_info_t *dev = link->priv;
269         int ret;
270
271         dev_dbg(&link->dev, "das08_pcmcia_config\n");
272
273         ret = pcmcia_loop_config(link, das08_pcmcia_config_loop, NULL);
274         if (ret) {
275                 dev_warn(&link->dev, "no configuration found\n");
276                 goto failed;
277         }
278
279         if (link->conf.Attributes & CONF_ENABLE_IRQ) {
280                 ret = pcmcia_request_irq(link, &link->irq);
281                 if (ret)
282                         goto failed;
283         }
284
285         /*
286            This actually configures the PCMCIA socket -- setting up
287            the I/O windows and the interrupt mapping, and putting the
288            card and host interface into "Memory and IO" mode.
289          */
290         ret = pcmcia_request_configuration(link, &link->conf);
291         if (ret)
292                 goto failed;
293
294         /*
295            At this point, the dev_node_t structure(s) need to be
296            initialized and arranged in a linked list at link->dev.
297          */
298         sprintf(dev->node.dev_name, "pcm-das08");
299         dev->node.major = dev->node.minor = 0;
300         link->dev_node = &dev->node;
301
302         /* Finally, report what we've done */
303         printk(KERN_INFO "%s: index 0x%02x",
304                dev->node.dev_name, link->conf.ConfigIndex);
305         if (link->conf.Attributes & CONF_ENABLE_IRQ)
306                 printk(", irq %u", link->irq.AssignedIRQ);
307         if (link->io.NumPorts1)
308                 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
309                        link->io.BasePort1 + link->io.NumPorts1 - 1);
310         if (link->io.NumPorts2)
311                 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
312                        link->io.BasePort2 + link->io.NumPorts2 - 1);
313         printk("\n");
314
315         return;
316
317 failed:
318         das08_pcmcia_release(link);
319
320 }                               /* das08_pcmcia_config */
321
322 /*======================================================================
323
324     After a card is removed, das08_pcmcia_release() will unregister the
325     device, and release the PCMCIA configuration.  If the device is
326     still open, this will be postponed until it is closed.
327
328 ======================================================================*/
329
330 static void das08_pcmcia_release(struct pcmcia_device *link)
331 {
332         dev_dbg(&link->dev, "das08_pcmcia_release\n");
333         pcmcia_disable_device(link);
334 }                               /* das08_pcmcia_release */
335
336 /*======================================================================
337
338     The card status event handler.  Mostly, this schedules other
339     stuff to run after an event is received.
340
341     When a CARD_REMOVAL event is received, we immediately set a
342     private flag to block future accesses to this device.  All the
343     functions that actually access the device should check this flag
344     to make sure the card is still present.
345
346 ======================================================================*/
347
348 static int das08_pcmcia_suspend(struct pcmcia_device *link)
349 {
350         struct local_info_t *local = link->priv;
351         /* Mark the device as stopped, to block IO until later */
352         local->stop = 1;
353
354         return 0;
355 }                               /* das08_pcmcia_suspend */
356
357 static int das08_pcmcia_resume(struct pcmcia_device *link)
358 {
359         struct local_info_t *local = link->priv;
360
361         local->stop = 0;
362         return 0;
363 }                               /* das08_pcmcia_resume */
364
365 /*====================================================================*/
366
367 static struct pcmcia_device_id das08_cs_id_table[] = {
368         PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4001),
369         PCMCIA_DEVICE_NULL
370 };
371
372 MODULE_DEVICE_TABLE(pcmcia, das08_cs_id_table);
373
374 struct pcmcia_driver das08_cs_driver = {
375         .probe = das08_pcmcia_attach,
376         .remove = das08_pcmcia_detach,
377         .suspend = das08_pcmcia_suspend,
378         .resume = das08_pcmcia_resume,
379         .id_table = das08_cs_id_table,
380         .owner = THIS_MODULE,
381         .drv = {
382                 .name = dev_info,
383                 },
384 };
385
386 static int __init init_das08_pcmcia_cs(void)
387 {
388         pcmcia_register_driver(&das08_cs_driver);
389         return 0;
390 }
391
392 static void __exit exit_das08_pcmcia_cs(void)
393 {
394         pr_debug("das08_pcmcia_cs: unloading\n");
395         pcmcia_unregister_driver(&das08_cs_driver);
396 }
397
398 static int __init das08_cs_init_module(void)
399 {
400         int ret;
401
402         ret = init_das08_pcmcia_cs();
403         if (ret < 0)
404                 return ret;
405
406         return comedi_driver_register(&driver_das08_cs);
407 }
408
409 static void __exit das08_cs_exit_module(void)
410 {
411         exit_das08_pcmcia_cs();
412         comedi_driver_unregister(&driver_das08_cs);
413 }
414
415 MODULE_LICENSE("GPL");
416 module_init(das08_cs_init_module);
417 module_exit(das08_cs_exit_module);