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