das08_cs.c revision 10022a0675a8f8722068d956a798f1fddb02e71c
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	link->conf.IntType = INT_MEMORY_AND_IO;
174
175	cur_dev = link;
176
177	das08_pcmcia_config(link);
178
179	return 0;
180}				/* das08_pcmcia_attach */
181
182/*======================================================================
183
184    This deletes a driver "instance".  The device is de-registered
185    with Card Services.  If it has been released, all local data
186    structures are freed.  Otherwise, the structures will be freed
187    when the device is released.
188
189======================================================================*/
190
191static void das08_pcmcia_detach(struct pcmcia_device *link)
192{
193
194	dev_dbg(&link->dev, "das08_pcmcia_detach\n");
195
196	((struct local_info_t *)link->priv)->stop = 1;
197	das08_pcmcia_release(link);
198
199	/* This points to the parent struct local_info_t struct */
200	kfree(link->priv);
201
202}				/* das08_pcmcia_detach */
203
204
205static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev,
206				cistpl_cftable_entry_t *cfg,
207				cistpl_cftable_entry_t *dflt,
208				unsigned int vcc,
209				void *priv_data)
210{
211	if (cfg->index == 0)
212		return -ENODEV;
213
214	/* Do we need to allocate an interrupt? */
215	p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
216
217	/* IO window settings */
218	p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
219	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
220		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
221		p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
222		p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
223		p_dev->resource[0]->flags |=
224			pcmcia_io_cfg_data_width(io->flags);
225		p_dev->resource[0]->start = io->win[0].base;
226		p_dev->resource[0]->end = io->win[0].len;
227		if (io->nwin > 1) {
228			p_dev->resource[1]->flags = p_dev->resource[0]->flags;
229			p_dev->resource[1]->start = io->win[1].base;
230			p_dev->resource[1]->end = io->win[1].len;
231		}
232		/* This reserves IO space but doesn't actually enable it */
233		return pcmcia_request_io(p_dev);
234	}
235	return 0;
236}
237
238
239/*======================================================================
240
241    das08_pcmcia_config() is scheduled to run after a CARD_INSERTION event
242    is received, to configure the PCMCIA socket, and to make the
243    device available to the system.
244
245======================================================================*/
246
247static void das08_pcmcia_config(struct pcmcia_device *link)
248{
249	int ret;
250
251	dev_dbg(&link->dev, "das08_pcmcia_config\n");
252
253	ret = pcmcia_loop_config(link, das08_pcmcia_config_loop, NULL);
254	if (ret) {
255		dev_warn(&link->dev, "no configuration found\n");
256		goto failed;
257	}
258
259	if (!link->irq)
260		goto failed;
261
262	/*
263	   This actually configures the PCMCIA socket -- setting up
264	   the I/O windows and the interrupt mapping, and putting the
265	   card and host interface into "Memory and IO" mode.
266	 */
267	ret = pcmcia_request_configuration(link, &link->conf);
268	if (ret)
269		goto failed;
270
271	/* Finally, report what we've done */
272	dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
273	if (link->conf.Attributes & CONF_ENABLE_IRQ)
274		printk(", irq %u", link->irq);
275	if (link->resource[0])
276		printk(", io %pR", link->resource[0]);
277	if (link->resource[1])
278		printk(" & %pR", link->resource[1]);
279	printk("\n");
280
281	return;
282
283failed:
284	das08_pcmcia_release(link);
285
286}				/* das08_pcmcia_config */
287
288/*======================================================================
289
290    After a card is removed, das08_pcmcia_release() will unregister the
291    device, and release the PCMCIA configuration.  If the device is
292    still open, this will be postponed until it is closed.
293
294======================================================================*/
295
296static void das08_pcmcia_release(struct pcmcia_device *link)
297{
298	dev_dbg(&link->dev, "das08_pcmcia_release\n");
299	pcmcia_disable_device(link);
300}				/* das08_pcmcia_release */
301
302/*======================================================================
303
304    The card status event handler.  Mostly, this schedules other
305    stuff to run after an event is received.
306
307    When a CARD_REMOVAL event is received, we immediately set a
308    private flag to block future accesses to this device.  All the
309    functions that actually access the device should check this flag
310    to make sure the card is still present.
311
312======================================================================*/
313
314static int das08_pcmcia_suspend(struct pcmcia_device *link)
315{
316	struct local_info_t *local = link->priv;
317	/* Mark the device as stopped, to block IO until later */
318	local->stop = 1;
319
320	return 0;
321}				/* das08_pcmcia_suspend */
322
323static int das08_pcmcia_resume(struct pcmcia_device *link)
324{
325	struct local_info_t *local = link->priv;
326
327	local->stop = 0;
328	return 0;
329}				/* das08_pcmcia_resume */
330
331/*====================================================================*/
332
333static struct pcmcia_device_id das08_cs_id_table[] = {
334	PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4001),
335	PCMCIA_DEVICE_NULL
336};
337
338MODULE_DEVICE_TABLE(pcmcia, das08_cs_id_table);
339MODULE_AUTHOR("David A. Schleef <ds@schleef.org>, "
340	      "Frank Mori Hess <fmhess@users.sourceforge.net>");
341MODULE_DESCRIPTION("Comedi driver for ComputerBoards DAS-08 PCMCIA boards");
342MODULE_LICENSE("GPL");
343
344struct pcmcia_driver das08_cs_driver = {
345	.probe = das08_pcmcia_attach,
346	.remove = das08_pcmcia_detach,
347	.suspend = das08_pcmcia_suspend,
348	.resume = das08_pcmcia_resume,
349	.id_table = das08_cs_id_table,
350	.owner = THIS_MODULE,
351	.drv = {
352		.name = "pcm-das08",
353		},
354};
355
356static int __init init_das08_pcmcia_cs(void)
357{
358	pcmcia_register_driver(&das08_cs_driver);
359	return 0;
360}
361
362static void __exit exit_das08_pcmcia_cs(void)
363{
364	pr_debug("das08_pcmcia_cs: unloading\n");
365	pcmcia_unregister_driver(&das08_cs_driver);
366}
367
368static int __init das08_cs_init_module(void)
369{
370	int ret;
371
372	ret = init_das08_pcmcia_cs();
373	if (ret < 0)
374		return ret;
375
376	return comedi_driver_register(&driver_das08_cs);
377}
378
379static void __exit das08_cs_exit_module(void)
380{
381	exit_das08_pcmcia_cs();
382	comedi_driver_unregister(&driver_das08_cs);
383}
384
385module_init(das08_cs_init_module);
386module_exit(das08_cs_exit_module);
387