Merge branches 'core-fixes-for-linus' and 'irq-fixes-for-linus' of git://git.kernel...
[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/cistpl.h>
52 #include <pcmcia/ds.h>
53
54 static struct pcmcia_device *cur_dev;
55
56 #define thisboard ((const struct das08_board_struct *)dev->board_ptr)
57
58 static int das08_cs_attach(struct comedi_device *dev,
59                            struct comedi_devconfig *it);
60
61 static struct comedi_driver driver_das08_cs = {
62         .driver_name = "das08_cs",
63         .module = THIS_MODULE,
64         .attach = das08_cs_attach,
65         .detach = das08_common_detach,
66         .board_name = &das08_cs_boards[0].name,
67         .num_names = ARRAY_SIZE(das08_cs_boards),
68         .offset = sizeof(struct das08_board_struct),
69 };
70
71 static int das08_cs_attach(struct comedi_device *dev,
72                            struct comedi_devconfig *it)
73 {
74         int ret;
75         unsigned long iobase;
76         struct pcmcia_device *link = cur_dev;   /*  XXX hack */
77
78         ret = alloc_private(dev, sizeof(struct das08_private_struct));
79         if (ret < 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->resource[0]->start;
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 static void das08_pcmcia_config(struct pcmcia_device *link);
113 static void das08_pcmcia_release(struct pcmcia_device *link);
114 static int das08_pcmcia_suspend(struct pcmcia_device *p_dev);
115 static int das08_pcmcia_resume(struct pcmcia_device *p_dev);
116
117 static int das08_pcmcia_attach(struct pcmcia_device *);
118 static void das08_pcmcia_detach(struct pcmcia_device *);
119
120 struct local_info_t {
121         struct pcmcia_device *link;
122         int stop;
123         struct bus_operations *bus;
124 };
125
126 static int das08_pcmcia_attach(struct pcmcia_device *link)
127 {
128         struct local_info_t *local;
129
130         dev_dbg(&link->dev, "das08_pcmcia_attach()\n");
131
132         /* Allocate space for private device-specific data */
133         local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
134         if (!local)
135                 return -ENOMEM;
136         local->link = link;
137         link->priv = local;
138
139         cur_dev = link;
140
141         das08_pcmcia_config(link);
142
143         return 0;
144 }                               /* das08_pcmcia_attach */
145
146 static void das08_pcmcia_detach(struct pcmcia_device *link)
147 {
148
149         dev_dbg(&link->dev, "das08_pcmcia_detach\n");
150
151         ((struct local_info_t *)link->priv)->stop = 1;
152         das08_pcmcia_release(link);
153
154         /* This points to the parent struct local_info_t struct */
155         kfree(link->priv);
156
157 }                               /* das08_pcmcia_detach */
158
159
160 static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev,
161                                 void *priv_data)
162 {
163         if (p_dev->config_index == 0)
164                 return -EINVAL;
165
166         return pcmcia_request_io(p_dev);
167 }
168
169 static void das08_pcmcia_config(struct pcmcia_device *link)
170 {
171         int ret;
172
173         dev_dbg(&link->dev, "das08_pcmcia_config\n");
174
175         link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
176
177         ret = pcmcia_loop_config(link, das08_pcmcia_config_loop, NULL);
178         if (ret) {
179                 dev_warn(&link->dev, "no configuration found\n");
180                 goto failed;
181         }
182
183         if (!link->irq)
184                 goto failed;
185
186         ret = pcmcia_enable_device(link);
187         if (ret)
188                 goto failed;
189
190         return;
191
192 failed:
193         das08_pcmcia_release(link);
194
195 }                               /* das08_pcmcia_config */
196
197 static void das08_pcmcia_release(struct pcmcia_device *link)
198 {
199         dev_dbg(&link->dev, "das08_pcmcia_release\n");
200         pcmcia_disable_device(link);
201 }                               /* das08_pcmcia_release */
202
203 static int das08_pcmcia_suspend(struct pcmcia_device *link)
204 {
205         struct local_info_t *local = link->priv;
206         /* Mark the device as stopped, to block IO until later */
207         local->stop = 1;
208
209         return 0;
210 }                               /* das08_pcmcia_suspend */
211
212 static int das08_pcmcia_resume(struct pcmcia_device *link)
213 {
214         struct local_info_t *local = link->priv;
215
216         local->stop = 0;
217         return 0;
218 }                               /* das08_pcmcia_resume */
219
220 /*====================================================================*/
221
222 static const struct pcmcia_device_id das08_cs_id_table[] = {
223         PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4001),
224         PCMCIA_DEVICE_NULL
225 };
226
227 MODULE_DEVICE_TABLE(pcmcia, das08_cs_id_table);
228 MODULE_AUTHOR("David A. Schleef <ds@schleef.org>, "
229               "Frank Mori Hess <fmhess@users.sourceforge.net>");
230 MODULE_DESCRIPTION("Comedi driver for ComputerBoards DAS-08 PCMCIA boards");
231 MODULE_LICENSE("GPL");
232
233 struct pcmcia_driver das08_cs_driver = {
234         .probe = das08_pcmcia_attach,
235         .remove = das08_pcmcia_detach,
236         .suspend = das08_pcmcia_suspend,
237         .resume = das08_pcmcia_resume,
238         .id_table = das08_cs_id_table,
239         .owner = THIS_MODULE,
240         .name = "pcm-das08",
241 };
242
243 static int __init init_das08_pcmcia_cs(void)
244 {
245         pcmcia_register_driver(&das08_cs_driver);
246         return 0;
247 }
248
249 static void __exit exit_das08_pcmcia_cs(void)
250 {
251         pr_debug("das08_pcmcia_cs: unloading\n");
252         pcmcia_unregister_driver(&das08_cs_driver);
253 }
254
255 static int __init das08_cs_init_module(void)
256 {
257         int ret;
258
259         ret = init_das08_pcmcia_cs();
260         if (ret < 0)
261                 return ret;
262
263         return comedi_driver_register(&driver_das08_cs);
264 }
265
266 static void __exit das08_cs_exit_module(void)
267 {
268         exit_das08_pcmcia_cs();
269         comedi_driver_unregister(&driver_das08_cs);
270 }
271
272 module_init(das08_cs_init_module);
273 module_exit(das08_cs_exit_module);