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