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 
das08_cs_attach(struct comedi_device * dev,struct comedi_devconfig * it)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 	dev_info(dev->hw_dev, "comedi%d: das08_cs:\n", dev->minor);
83 	/*  deal with a pci board */
84 
85 	if (thisboard->bustype == pcmcia) {
86 		if (link == NULL) {
87 			dev_err(dev->hw_dev, "no pcmcia cards found\n");
88 			return -EIO;
89 		}
90 		iobase = link->resource[0]->start;
91 	} else {
92 		dev_err(dev->hw_dev, "bug! board does not have PCMCIA bustype\n");
93 		return -EINVAL;
94 	}
95 
96 	return das08_common_attach(dev, iobase);
97 }
98 
99 /*======================================================================
100 
101     The following pcmcia code for the pcm-das08 is adapted from the
102     dummy_cs.c driver of the Linux PCMCIA Card Services package.
103 
104     The initial developer of the original code is David A. Hinds
105     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
106     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
107 
108 ======================================================================*/
109 
110 static void das08_pcmcia_config(struct pcmcia_device *link);
111 static void das08_pcmcia_release(struct pcmcia_device *link);
112 static int das08_pcmcia_suspend(struct pcmcia_device *p_dev);
113 static int das08_pcmcia_resume(struct pcmcia_device *p_dev);
114 
115 static int das08_pcmcia_attach(struct pcmcia_device *);
116 static void das08_pcmcia_detach(struct pcmcia_device *);
117 
118 struct local_info_t {
119 	struct pcmcia_device *link;
120 	int stop;
121 	struct bus_operations *bus;
122 };
123 
das08_pcmcia_attach(struct pcmcia_device * link)124 static int das08_pcmcia_attach(struct pcmcia_device *link)
125 {
126 	struct local_info_t *local;
127 
128 	dev_dbg(&link->dev, "das08_pcmcia_attach()\n");
129 
130 	/* Allocate space for private device-specific data */
131 	local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
132 	if (!local)
133 		return -ENOMEM;
134 	local->link = link;
135 	link->priv = local;
136 
137 	cur_dev = link;
138 
139 	das08_pcmcia_config(link);
140 
141 	return 0;
142 }				/* das08_pcmcia_attach */
143 
das08_pcmcia_detach(struct pcmcia_device * link)144 static void das08_pcmcia_detach(struct pcmcia_device *link)
145 {
146 
147 	dev_dbg(&link->dev, "das08_pcmcia_detach\n");
148 
149 	((struct local_info_t *)link->priv)->stop = 1;
150 	das08_pcmcia_release(link);
151 
152 	/* This points to the parent struct local_info_t struct */
153 	kfree(link->priv);
154 
155 }				/* das08_pcmcia_detach */
156 
157 
das08_pcmcia_config_loop(struct pcmcia_device * p_dev,void * priv_data)158 static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev,
159 				void *priv_data)
160 {
161 	if (p_dev->config_index == 0)
162 		return -EINVAL;
163 
164 	return pcmcia_request_io(p_dev);
165 }
166 
das08_pcmcia_config(struct pcmcia_device * link)167 static void das08_pcmcia_config(struct pcmcia_device *link)
168 {
169 	int ret;
170 
171 	dev_dbg(&link->dev, "das08_pcmcia_config\n");
172 
173 	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
174 
175 	ret = pcmcia_loop_config(link, das08_pcmcia_config_loop, NULL);
176 	if (ret) {
177 		dev_warn(&link->dev, "no configuration found\n");
178 		goto failed;
179 	}
180 
181 	if (!link->irq)
182 		goto failed;
183 
184 	ret = pcmcia_enable_device(link);
185 	if (ret)
186 		goto failed;
187 
188 	return;
189 
190 failed:
191 	das08_pcmcia_release(link);
192 
193 }				/* das08_pcmcia_config */
194 
das08_pcmcia_release(struct pcmcia_device * link)195 static void das08_pcmcia_release(struct pcmcia_device *link)
196 {
197 	dev_dbg(&link->dev, "das08_pcmcia_release\n");
198 	pcmcia_disable_device(link);
199 }				/* das08_pcmcia_release */
200 
das08_pcmcia_suspend(struct pcmcia_device * link)201 static int das08_pcmcia_suspend(struct pcmcia_device *link)
202 {
203 	struct local_info_t *local = link->priv;
204 	/* Mark the device as stopped, to block IO until later */
205 	local->stop = 1;
206 
207 	return 0;
208 }				/* das08_pcmcia_suspend */
209 
das08_pcmcia_resume(struct pcmcia_device * link)210 static int das08_pcmcia_resume(struct pcmcia_device *link)
211 {
212 	struct local_info_t *local = link->priv;
213 
214 	local->stop = 0;
215 	return 0;
216 }				/* das08_pcmcia_resume */
217 
218 /*====================================================================*/
219 
220 static const struct pcmcia_device_id das08_cs_id_table[] = {
221 	PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4001),
222 	PCMCIA_DEVICE_NULL
223 };
224 
225 MODULE_DEVICE_TABLE(pcmcia, das08_cs_id_table);
226 MODULE_AUTHOR("David A. Schleef <ds@schleef.org>, "
227 	      "Frank Mori Hess <fmhess@users.sourceforge.net>");
228 MODULE_DESCRIPTION("Comedi driver for ComputerBoards DAS-08 PCMCIA boards");
229 MODULE_LICENSE("GPL");
230 
231 struct pcmcia_driver das08_cs_driver = {
232 	.probe = das08_pcmcia_attach,
233 	.remove = das08_pcmcia_detach,
234 	.suspend = das08_pcmcia_suspend,
235 	.resume = das08_pcmcia_resume,
236 	.id_table = das08_cs_id_table,
237 	.owner = THIS_MODULE,
238 	.name = "pcm-das08",
239 };
240 
init_das08_pcmcia_cs(void)241 static int __init init_das08_pcmcia_cs(void)
242 {
243 	pcmcia_register_driver(&das08_cs_driver);
244 	return 0;
245 }
246 
exit_das08_pcmcia_cs(void)247 static void __exit exit_das08_pcmcia_cs(void)
248 {
249 	pr_debug("das08_pcmcia_cs: unloading\n");
250 	pcmcia_unregister_driver(&das08_cs_driver);
251 }
252 
das08_cs_init_module(void)253 static int __init das08_cs_init_module(void)
254 {
255 	int ret;
256 
257 	ret = init_das08_pcmcia_cs();
258 	if (ret < 0)
259 		return ret;
260 
261 	return comedi_driver_register(&driver_das08_cs);
262 }
263 
das08_cs_exit_module(void)264 static void __exit das08_cs_exit_module(void)
265 {
266 	exit_das08_pcmcia_cs();
267 	comedi_driver_unregister(&driver_das08_cs);
268 }
269 
270 module_init(das08_cs_init_module);
271 module_exit(das08_cs_exit_module);
272