das08_cs.c revision 7feabb6412ea23edd298c0fa90e5aa6733eb4a42
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/cs.h>
52#include <pcmcia/cistpl.h>
53#include <pcmcia/ds.h>
54
55static struct pcmcia_device *cur_dev;
56
57#define thisboard ((const struct das08_board_struct *)dev->board_ptr)
58
59static int das08_cs_attach(struct comedi_device *dev,
60			   struct comedi_devconfig *it);
61
62static 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
72static 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->resource[0]->start;
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
113static void das08_pcmcia_config(struct pcmcia_device *link);
114static void das08_pcmcia_release(struct pcmcia_device *link);
115static int das08_pcmcia_suspend(struct pcmcia_device *p_dev);
116static 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
124static int das08_pcmcia_attach(struct pcmcia_device *);
125static 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
134struct local_info_t {
135	struct pcmcia_device *link;
136	int stop;
137	struct bus_operations *bus;
138};
139
140/*======================================================================
141
142    das08_pcmcia_attach() creates an "instance" of the driver, allocating
143    local data structures for one device.  The device is registered
144    with Card Services.
145
146    The dev_link structure is initialized, but we don't actually
147    configure the card at this point -- we wait until we receive a
148    card insertion event.
149
150======================================================================*/
151
152static int das08_pcmcia_attach(struct pcmcia_device *link)
153{
154	struct local_info_t *local;
155
156	dev_dbg(&link->dev, "das08_pcmcia_attach()\n");
157
158	/* Allocate space for private device-specific data */
159	local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
160	if (!local)
161		return -ENOMEM;
162	local->link = link;
163	link->priv = local;
164
165	/*
166	   General socket configuration defaults can go here.  In this
167	   client, we assume very little, and rely on the CIS for almost
168	   everything.  In most clients, many details (i.e., number, sizes,
169	   and attributes of IO windows) are fixed by the nature of the
170	   device, and can be hard-wired here.
171	 */
172	link->conf.Attributes = 0;
173
174	cur_dev = link;
175
176	das08_pcmcia_config(link);
177
178	return 0;
179}				/* das08_pcmcia_attach */
180
181/*======================================================================
182
183    This deletes a driver "instance".  The device is de-registered
184    with Card Services.  If it has been released, all local data
185    structures are freed.  Otherwise, the structures will be freed
186    when the device is released.
187
188======================================================================*/
189
190static void das08_pcmcia_detach(struct pcmcia_device *link)
191{
192
193	dev_dbg(&link->dev, "das08_pcmcia_detach\n");
194
195	((struct local_info_t *)link->priv)->stop = 1;
196	das08_pcmcia_release(link);
197
198	/* This points to the parent struct local_info_t struct */
199	kfree(link->priv);
200
201}				/* das08_pcmcia_detach */
202
203
204static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev,
205				cistpl_cftable_entry_t *cfg,
206				cistpl_cftable_entry_t *dflt,
207				unsigned int vcc,
208				void *priv_data)
209{
210	if (cfg->index == 0)
211		return -ENODEV;
212
213	/* Do we need to allocate an interrupt? */
214	p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
215
216	/* IO window settings */
217	p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
218	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
219		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
220		p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
221		p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
222		p_dev->resource[0]->flags |=
223			pcmcia_io_cfg_data_width(io->flags);
224		p_dev->resource[0]->start = io->win[0].base;
225		p_dev->resource[0]->end = io->win[0].len;
226		if (io->nwin > 1) {
227			p_dev->resource[1]->flags = p_dev->resource[0]->flags;
228			p_dev->resource[1]->start = io->win[1].base;
229			p_dev->resource[1]->end = io->win[1].len;
230		}
231		/* This reserves IO space but doesn't actually enable it */
232		return pcmcia_request_io(p_dev);
233	}
234	return 0;
235}
236
237
238/*======================================================================
239
240    das08_pcmcia_config() is scheduled to run after a CARD_INSERTION event
241    is received, to configure the PCMCIA socket, and to make the
242    device available to the system.
243
244======================================================================*/
245
246static void das08_pcmcia_config(struct pcmcia_device *link)
247{
248	int ret;
249
250	dev_dbg(&link->dev, "das08_pcmcia_config\n");
251
252	ret = pcmcia_loop_config(link, das08_pcmcia_config_loop, NULL);
253	if (ret) {
254		dev_warn(&link->dev, "no configuration found\n");
255		goto failed;
256	}
257
258	if (!link->irq)
259		goto failed;
260
261	/*
262	   This actually configures the PCMCIA socket -- setting up
263	   the I/O windows and the interrupt mapping, and putting the
264	   card and host interface into "Memory and IO" mode.
265	 */
266	ret = pcmcia_request_configuration(link, &link->conf);
267	if (ret)
268		goto failed;
269
270	/* Finally, report what we've done */
271	dev_info(&link->dev, "index 0x%02x", link->config_index);
272	if (link->conf.Attributes & CONF_ENABLE_IRQ)
273		printk(", irq %u", link->irq);
274	if (link->resource[0])
275		printk(", io %pR", link->resource[0]);
276	if (link->resource[1])
277		printk(" & %pR", link->resource[1]);
278	printk("\n");
279
280	return;
281
282failed:
283	das08_pcmcia_release(link);
284
285}				/* das08_pcmcia_config */
286
287/*======================================================================
288
289    After a card is removed, das08_pcmcia_release() will unregister the
290    device, and release the PCMCIA configuration.  If the device is
291    still open, this will be postponed until it is closed.
292
293======================================================================*/
294
295static void das08_pcmcia_release(struct pcmcia_device *link)
296{
297	dev_dbg(&link->dev, "das08_pcmcia_release\n");
298	pcmcia_disable_device(link);
299}				/* das08_pcmcia_release */
300
301/*======================================================================
302
303    The card status event handler.  Mostly, this schedules other
304    stuff to run after an event is received.
305
306    When a CARD_REMOVAL event is received, we immediately set a
307    private flag to block future accesses to this device.  All the
308    functions that actually access the device should check this flag
309    to make sure the card is still present.
310
311======================================================================*/
312
313static int das08_pcmcia_suspend(struct pcmcia_device *link)
314{
315	struct local_info_t *local = link->priv;
316	/* Mark the device as stopped, to block IO until later */
317	local->stop = 1;
318
319	return 0;
320}				/* das08_pcmcia_suspend */
321
322static int das08_pcmcia_resume(struct pcmcia_device *link)
323{
324	struct local_info_t *local = link->priv;
325
326	local->stop = 0;
327	return 0;
328}				/* das08_pcmcia_resume */
329
330/*====================================================================*/
331
332static struct pcmcia_device_id das08_cs_id_table[] = {
333	PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4001),
334	PCMCIA_DEVICE_NULL
335};
336
337MODULE_DEVICE_TABLE(pcmcia, das08_cs_id_table);
338MODULE_AUTHOR("David A. Schleef <ds@schleef.org>, "
339	      "Frank Mori Hess <fmhess@users.sourceforge.net>");
340MODULE_DESCRIPTION("Comedi driver for ComputerBoards DAS-08 PCMCIA boards");
341MODULE_LICENSE("GPL");
342
343struct pcmcia_driver das08_cs_driver = {
344	.probe = das08_pcmcia_attach,
345	.remove = das08_pcmcia_detach,
346	.suspend = das08_pcmcia_suspend,
347	.resume = das08_pcmcia_resume,
348	.id_table = das08_cs_id_table,
349	.owner = THIS_MODULE,
350	.drv = {
351		.name = "pcm-das08",
352		},
353};
354
355static int __init init_das08_pcmcia_cs(void)
356{
357	pcmcia_register_driver(&das08_cs_driver);
358	return 0;
359}
360
361static void __exit exit_das08_pcmcia_cs(void)
362{
363	pr_debug("das08_pcmcia_cs: unloading\n");
364	pcmcia_unregister_driver(&das08_cs_driver);
365}
366
367static int __init das08_cs_init_module(void)
368{
369	int ret;
370
371	ret = init_das08_pcmcia_cs();
372	if (ret < 0)
373		return ret;
374
375	return comedi_driver_register(&driver_das08_cs);
376}
377
378static void __exit das08_cs_exit_module(void)
379{
380	exit_das08_pcmcia_cs();
381	comedi_driver_unregister(&driver_das08_cs);
382}
383
384module_init(das08_cs_init_module);
385module_exit(das08_cs_exit_module);
386