das08_cs.c revision 61a8d9550e620ab777ce25c2878e57f4e1a6acd3
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/slab.h>
47
48#include "das08.h"
49
50/* pcmcia includes */
51#include <pcmcia/cistpl.h>
52#include <pcmcia/ds.h>
53
54static struct pcmcia_device *cur_dev;
55
56#define thisboard ((const struct das08_board_struct *)dev->board_ptr)
57
58static int das08_cs_attach(struct comedi_device *dev,
59			   struct comedi_devconfig *it);
60
61static 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
71static 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
110static void das08_pcmcia_config(struct pcmcia_device *link);
111static void das08_pcmcia_release(struct pcmcia_device *link);
112static int das08_pcmcia_suspend(struct pcmcia_device *p_dev);
113static int das08_pcmcia_resume(struct pcmcia_device *p_dev);
114
115static int das08_pcmcia_attach(struct pcmcia_device *);
116static void das08_pcmcia_detach(struct pcmcia_device *);
117
118struct local_info_t {
119	struct pcmcia_device *link;
120	int stop;
121	struct bus_operations *bus;
122};
123
124static 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
144static 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
158static 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
167static 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
190failed:
191	das08_pcmcia_release(link);
192
193}				/* das08_pcmcia_config */
194
195static 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
201static 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
210static 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
220static const struct pcmcia_device_id das08_cs_id_table[] = {
221	PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4001),
222	PCMCIA_DEVICE_NULL
223};
224
225MODULE_DEVICE_TABLE(pcmcia, das08_cs_id_table);
226MODULE_AUTHOR("David A. Schleef <ds@schleef.org>, "
227	      "Frank Mori Hess <fmhess@users.sourceforge.net>");
228MODULE_DESCRIPTION("Comedi driver for ComputerBoards DAS-08 PCMCIA boards");
229MODULE_LICENSE("GPL");
230
231struct 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
241static int __init init_das08_pcmcia_cs(void)
242{
243	pcmcia_register_driver(&das08_cs_driver);
244	return 0;
245}
246
247static 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
253static 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
264static void __exit das08_cs_exit_module(void)
265{
266	exit_das08_pcmcia_cs();
267	comedi_driver_unregister(&driver_das08_cs);
268}
269
270module_init(das08_cs_init_module);
271module_exit(das08_cs_exit_module);
272