cb_das16_cs.c revision 25436dc9d84f1be60ff549c9ab712bba2835f284
1/*
2    comedi/drivers/das16cs.c
3    Driver for Computer Boards PC-CARD DAS16/16.
4
5    COMEDI - Linux Control and Measurement Device Interface
6    Copyright (C) 2000, 2001, 2002 David A. Schleef <ds@schleef.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22*/
23/*
24Driver: cb_das16_cs
25Description: Computer Boards PC-CARD DAS16/16
26Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), PC-CARD DAS16/16-AO
27Author: ds
28Updated: Mon, 04 Nov 2002 20:04:21 -0800
29Status: experimental
30
31
32*/
33
34#include <linux/interrupt.h>
35#include "../comedidev.h"
36#include <linux/delay.h>
37#include <linux/pci.h>
38
39#include <pcmcia/cs_types.h>
40#include <pcmcia/cs.h>
41#include <pcmcia/cistpl.h>
42#include <pcmcia/ds.h>
43
44#include "8253.h"
45
46#define DAS16CS_SIZE			18
47
48#define DAS16CS_ADC_DATA		0
49#define DAS16CS_DIO_MUX			2
50#define DAS16CS_MISC1			4
51#define DAS16CS_MISC2			6
52#define DAS16CS_CTR0			8
53#define DAS16CS_CTR1			10
54#define DAS16CS_CTR2			12
55#define DAS16CS_CTR_CONTROL		14
56#define DAS16CS_DIO			16
57
58struct das16cs_board {
59	const char *name;
60	int device_id;
61	int n_ao_chans;
62};
63static const struct das16cs_board das16cs_boards[] = {
64	{
65	.device_id = 0x0000,/* unknown */
66	.name = "PC-CARD DAS16/16",
67	.n_ao_chans = 0,
68		},
69	{
70	.device_id = 0x0039,
71	.name = "PC-CARD DAS16/16-AO",
72	.n_ao_chans = 2,
73		},
74	{
75	.device_id = 0x4009,
76	.name = "PCM-DAS16s/16",
77	.n_ao_chans = 0,
78		},
79};
80
81#define n_boards (sizeof(das16cs_boards)/sizeof(das16cs_boards[0]))
82#define thisboard ((const struct das16cs_board *)dev->board_ptr)
83
84struct das16cs_private {
85	struct pcmcia_device *link;
86
87	unsigned int ao_readback[2];
88	unsigned short status1;
89	unsigned short status2;
90};
91#define devpriv ((struct das16cs_private *)dev->private)
92
93static int das16cs_attach(struct comedi_device *dev, struct comedi_devconfig *it);
94static int das16cs_detach(struct comedi_device *dev);
95static struct comedi_driver driver_das16cs = {
96	.driver_name = "cb_das16_cs",
97	.module = THIS_MODULE,
98	.attach = das16cs_attach,
99	.detach = das16cs_detach,
100};
101
102static struct pcmcia_device *cur_dev = NULL;
103
104static const struct comedi_lrange das16cs_ai_range = { 4, {
105			RANGE(-10, 10),
106			RANGE(-5, 5),
107			RANGE(-2.5, 2.5),
108			RANGE(-1.25, 1.25),
109	}
110};
111
112static irqreturn_t das16cs_interrupt(int irq, void *d);
113static int das16cs_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
114	struct comedi_insn *insn, unsigned int *data);
115static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
116static int das16cs_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
117	struct comedi_cmd *cmd);
118static int das16cs_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
119	struct comedi_insn *insn, unsigned int *data);
120static int das16cs_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
121	struct comedi_insn *insn, unsigned int *data);
122static int das16cs_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
123	struct comedi_insn *insn, unsigned int *data);
124static int das16cs_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
125	struct comedi_insn *insn, unsigned int *data);
126static int das16cs_timer_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
127	struct comedi_insn *insn, unsigned int *data);
128static int das16cs_timer_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
129	struct comedi_insn *insn, unsigned int *data);
130
131static int get_prodid(struct comedi_device *dev, struct pcmcia_device *link)
132{
133	tuple_t tuple;
134	u_short buf[128];
135	int prodid = 0;
136
137	tuple.TupleData = (cisdata_t *) buf;
138	tuple.TupleOffset = 0;
139	tuple.TupleDataMax = 255;
140	tuple.DesiredTuple = CISTPL_MANFID;
141	tuple.Attributes = TUPLE_RETURN_COMMON;
142	if ((pcmcia_get_first_tuple(link, &tuple) == 0) &&
143		(pcmcia_get_tuple_data(link, &tuple) == 0)) {
144		prodid = le16_to_cpu(buf[1]);
145	}
146
147	return prodid;
148}
149
150static const struct das16cs_board *das16cs_probe(struct comedi_device * dev,
151	struct pcmcia_device *link)
152{
153	int id;
154	int i;
155
156	id = get_prodid(dev, link);
157
158	for (i = 0; i < n_boards; i++) {
159		if (das16cs_boards[i].device_id == id) {
160			return das16cs_boards + i;
161		}
162	}
163
164	printk("unknown board!\n");
165
166	return NULL;
167}
168
169static int das16cs_attach(struct comedi_device *dev, struct comedi_devconfig *it)
170{
171	struct pcmcia_device *link;
172	struct comedi_subdevice *s;
173	int ret;
174	int i;
175
176	printk("comedi%d: cb_das16_cs: ", dev->minor);
177
178	link = cur_dev;		/* XXX hack */
179	if (!link)
180		return -EIO;
181
182	dev->iobase = link->io.BasePort1;
183	printk("I/O base=0x%04lx ", dev->iobase);
184
185	printk("fingerprint:\n");
186	for (i = 0; i < 48; i += 2) {
187		printk("%04x ", inw(dev->iobase + i));
188	}
189	printk("\n");
190
191	ret = request_irq(link->irq.AssignedIRQ, das16cs_interrupt,
192			  IRQF_SHARED, "cb_das16_cs", dev);
193	if (ret < 0) {
194		return ret;
195	}
196	dev->irq = link->irq.AssignedIRQ;
197	printk("irq=%u ", dev->irq);
198
199	dev->board_ptr = das16cs_probe(dev, link);
200	if (!dev->board_ptr)
201		return -EIO;
202
203	dev->board_name = thisboard->name;
204
205	if (alloc_private(dev, sizeof(struct das16cs_private)) < 0)
206		return -ENOMEM;
207
208	if (alloc_subdevices(dev, 4) < 0)
209		return -ENOMEM;
210
211	s = dev->subdevices + 0;
212	dev->read_subdev = s;
213	/* analog input subdevice */
214	s->type = COMEDI_SUBD_AI;
215	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
216	s->n_chan = 16;
217	s->maxdata = 0xffff;
218	s->range_table = &das16cs_ai_range;
219	s->len_chanlist = 16;
220	s->insn_read = das16cs_ai_rinsn;
221	s->do_cmd = das16cs_ai_cmd;
222	s->do_cmdtest = das16cs_ai_cmdtest;
223
224	s = dev->subdevices + 1;
225	/* analog output subdevice */
226	if (thisboard->n_ao_chans) {
227		s->type = COMEDI_SUBD_AO;
228		s->subdev_flags = SDF_WRITABLE;
229		s->n_chan = thisboard->n_ao_chans;
230		s->maxdata = 0xffff;
231		s->range_table = &range_bipolar10;
232		s->insn_write = &das16cs_ao_winsn;
233		s->insn_read = &das16cs_ao_rinsn;
234	}
235
236	s = dev->subdevices + 2;
237	/* digital i/o subdevice */
238	if (1) {
239		s->type = COMEDI_SUBD_DIO;
240		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
241		s->n_chan = 8;
242		s->maxdata = 1;
243		s->range_table = &range_digital;
244		s->insn_bits = das16cs_dio_insn_bits;
245		s->insn_config = das16cs_dio_insn_config;
246	} else {
247		s->type = COMEDI_SUBD_UNUSED;
248	}
249
250	s = dev->subdevices + 3;
251	/* timer subdevice */
252	if (0) {
253		s->type = COMEDI_SUBD_TIMER;
254		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
255		s->n_chan = 1;
256		s->maxdata = 0xff;
257		s->range_table = &range_unknown;
258		s->insn_read = das16cs_timer_insn_read;
259		s->insn_config = das16cs_timer_insn_config;
260	} else {
261		s->type = COMEDI_SUBD_UNUSED;
262	}
263
264	printk("attached\n");
265
266	return 1;
267}
268
269static int das16cs_detach(struct comedi_device *dev)
270{
271	printk("comedi%d: das16cs: remove\n", dev->minor);
272
273	if (dev->irq) {
274		free_irq(dev->irq, dev);
275	}
276
277	return 0;
278}
279
280static irqreturn_t das16cs_interrupt(int irq, void *d)
281{
282	/* struct comedi_device *dev = d; */
283	return IRQ_HANDLED;
284}
285
286/*
287 * "instructions" read/write data in "one-shot" or "software-triggered"
288 * mode.
289 */
290static int das16cs_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
291	struct comedi_insn *insn, unsigned int *data)
292{
293	int i;
294	int to;
295	int aref;
296	int range;
297	int chan;
298	static int range_bits[] = { 0x800, 0x000, 0x100, 0x200 };
299
300	chan = CR_CHAN(insn->chanspec);
301	aref = CR_AREF(insn->chanspec);
302	range = CR_RANGE(insn->chanspec);
303
304	outw(chan, dev->iobase + 2);
305
306	devpriv->status1 &= ~0xf320;
307	devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020;
308	outw(devpriv->status1, dev->iobase + 4);
309
310	devpriv->status2 &= ~0xff00;
311	devpriv->status2 |= range_bits[range];
312	outw(devpriv->status2, dev->iobase + 6);
313
314	for (i = 0; i < insn->n; i++) {
315		outw(0, dev->iobase);
316
317#define TIMEOUT 1000
318		for (to = 0; to < TIMEOUT; to++) {
319			if (inw(dev->iobase + 4) & 0x0080)
320				break;
321		}
322		if (to == TIMEOUT) {
323			printk("cb_das16_cs: ai timeout\n");
324			return -ETIME;
325		}
326		data[i] = (unsigned short)inw(dev->iobase + 0);
327	}
328
329	return i;
330}
331
332static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
333{
334	return -EINVAL;
335}
336
337static int das16cs_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
338	struct comedi_cmd *cmd)
339{
340	int err = 0;
341	int tmp;
342
343	/* cmdtest tests a particular command to see if it is valid.
344	 * Using the cmdtest ioctl, a user can create a valid cmd
345	 * and then have it executes by the cmd ioctl.
346	 *
347	 * cmdtest returns 1,2,3,4 or 0, depending on which tests
348	 * the command passes. */
349
350	/* step 1: make sure trigger sources are trivially valid */
351
352	tmp = cmd->start_src;
353	cmd->start_src &= TRIG_NOW;
354	if (!cmd->start_src || tmp != cmd->start_src)
355		err++;
356
357	tmp = cmd->scan_begin_src;
358	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
359	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
360		err++;
361
362	tmp = cmd->convert_src;
363	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
364	if (!cmd->convert_src || tmp != cmd->convert_src)
365		err++;
366
367	tmp = cmd->scan_end_src;
368	cmd->scan_end_src &= TRIG_COUNT;
369	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
370		err++;
371
372	tmp = cmd->stop_src;
373	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
374	if (!cmd->stop_src || tmp != cmd->stop_src)
375		err++;
376
377	if (err)
378		return 1;
379
380	/* step 2: make sure trigger sources are unique and mutually compatible */
381
382	/* note that mutual compatiblity is not an issue here */
383	if (cmd->scan_begin_src != TRIG_TIMER &&
384		cmd->scan_begin_src != TRIG_EXT)
385		err++;
386	if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
387		err++;
388	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
389		err++;
390
391	if (err)
392		return 2;
393
394	/* step 3: make sure arguments are trivially compatible */
395
396	if (cmd->start_arg != 0) {
397		cmd->start_arg = 0;
398		err++;
399	}
400#define MAX_SPEED	10000	/* in nanoseconds */
401#define MIN_SPEED	1000000000	/* in nanoseconds */
402
403	if (cmd->scan_begin_src == TRIG_TIMER) {
404		if (cmd->scan_begin_arg < MAX_SPEED) {
405			cmd->scan_begin_arg = MAX_SPEED;
406			err++;
407		}
408		if (cmd->scan_begin_arg > MIN_SPEED) {
409			cmd->scan_begin_arg = MIN_SPEED;
410			err++;
411		}
412	} else {
413		/* external trigger */
414		/* should be level/edge, hi/lo specification here */
415		/* should specify multiple external triggers */
416		if (cmd->scan_begin_arg > 9) {
417			cmd->scan_begin_arg = 9;
418			err++;
419		}
420	}
421	if (cmd->convert_src == TRIG_TIMER) {
422		if (cmd->convert_arg < MAX_SPEED) {
423			cmd->convert_arg = MAX_SPEED;
424			err++;
425		}
426		if (cmd->convert_arg > MIN_SPEED) {
427			cmd->convert_arg = MIN_SPEED;
428			err++;
429		}
430	} else {
431		/* external trigger */
432		/* see above */
433		if (cmd->convert_arg > 9) {
434			cmd->convert_arg = 9;
435			err++;
436		}
437	}
438
439	if (cmd->scan_end_arg != cmd->chanlist_len) {
440		cmd->scan_end_arg = cmd->chanlist_len;
441		err++;
442	}
443	if (cmd->stop_src == TRIG_COUNT) {
444		if (cmd->stop_arg > 0x00ffffff) {
445			cmd->stop_arg = 0x00ffffff;
446			err++;
447		}
448	} else {
449		/* TRIG_NONE */
450		if (cmd->stop_arg != 0) {
451			cmd->stop_arg = 0;
452			err++;
453		}
454	}
455
456	if (err)
457		return 3;
458
459	/* step 4: fix up any arguments */
460
461	if (cmd->scan_begin_src == TRIG_TIMER) {
462		unsigned int div1, div2;
463
464		tmp = cmd->scan_begin_arg;
465		i8253_cascade_ns_to_timer(100, &div1, &div2,
466			&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
467		if (tmp != cmd->scan_begin_arg)
468			err++;
469	}
470	if (cmd->convert_src == TRIG_TIMER) {
471		unsigned int div1, div2;
472
473		tmp = cmd->convert_arg;
474		i8253_cascade_ns_to_timer(100, &div1, &div2,
475			&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
476		if (tmp != cmd->convert_arg)
477			err++;
478		if (cmd->scan_begin_src == TRIG_TIMER &&
479			cmd->scan_begin_arg <
480			cmd->convert_arg * cmd->scan_end_arg) {
481			cmd->scan_begin_arg =
482				cmd->convert_arg * cmd->scan_end_arg;
483			err++;
484		}
485	}
486
487	if (err)
488		return 4;
489
490	return 0;
491}
492
493static int das16cs_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
494	struct comedi_insn *insn, unsigned int *data)
495{
496	int i;
497	int chan = CR_CHAN(insn->chanspec);
498	unsigned short status1;
499	unsigned short d;
500	int bit;
501
502	for (i = 0; i < insn->n; i++) {
503		devpriv->ao_readback[chan] = data[i];
504		d = data[i];
505
506		outw(devpriv->status1, dev->iobase + 4);
507		udelay(1);
508
509		status1 = devpriv->status1 & ~0xf;
510		if (chan)
511			status1 |= 0x0001;
512		else
513			status1 |= 0x0008;
514
515/* 		printk("0x%04x\n",status1);*/
516		outw(status1, dev->iobase + 4);
517		udelay(1);
518
519		for (bit = 15; bit >= 0; bit--) {
520			int b = (d >> bit) & 0x1;
521			b <<= 1;
522/*			printk("0x%04x\n",status1 | b | 0x0000);*/
523			outw(status1 | b | 0x0000, dev->iobase + 4);
524			udelay(1);
525/*			printk("0x%04x\n",status1 | b | 0x0004);*/
526			outw(status1 | b | 0x0004, dev->iobase + 4);
527			udelay(1);
528		}
529/*		make high both DAC0CS and DAC1CS to load
530		new data and update analog output*/
531		outw(status1 | 0x9, dev->iobase + 4);
532	}
533
534	return i;
535}
536
537/* AO subdevices should have a read insn as well as a write insn.
538 * Usually this means copying a value stored in devpriv. */
539static int das16cs_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
540	struct comedi_insn *insn, unsigned int *data)
541{
542	int i;
543	int chan = CR_CHAN(insn->chanspec);
544
545	for (i = 0; i < insn->n; i++)
546		data[i] = devpriv->ao_readback[chan];
547
548	return i;
549}
550
551/* DIO devices are slightly special.  Although it is possible to
552 * implement the insn_read/insn_write interface, it is much more
553 * useful to applications if you implement the insn_bits interface.
554 * This allows packed reading/writing of the DIO channels.  The
555 * comedi core can convert between insn_bits and insn_read/write */
556static int das16cs_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
557	struct comedi_insn *insn, unsigned int *data)
558{
559	if (insn->n != 2)
560		return -EINVAL;
561
562	if (data[0]) {
563		s->state &= ~data[0];
564		s->state |= data[0] & data[1];
565
566		outw(s->state, dev->iobase + 16);
567	}
568
569	/* on return, data[1] contains the value of the digital
570	 * input and output lines. */
571	data[1] = inw(dev->iobase + 16);
572
573	return 2;
574}
575
576static int das16cs_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
577	struct comedi_insn *insn, unsigned int *data)
578{
579	int chan = CR_CHAN(insn->chanspec);
580	int bits;
581
582	if (chan < 4)
583		bits = 0x0f;
584	else
585		bits = 0xf0;
586
587	switch (data[0]) {
588	case INSN_CONFIG_DIO_OUTPUT:
589		s->io_bits |= bits;
590		break;
591	case INSN_CONFIG_DIO_INPUT:
592		s->io_bits &= bits;
593		break;
594	case INSN_CONFIG_DIO_QUERY:
595		data[1] =
596			(s->
597			io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
598		return insn->n;
599		break;
600	default:
601		return -EINVAL;
602		break;
603	}
604
605	devpriv->status2 &= ~0x00c0;
606	devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0;
607	devpriv->status2 |= (s->io_bits & 0x0f) ? 0x0040 : 0;
608
609	outw(devpriv->status2, dev->iobase + 6);
610
611	return insn->n;
612}
613
614static int das16cs_timer_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
615	struct comedi_insn *insn, unsigned int *data)
616{
617	return -EINVAL;
618}
619
620static int das16cs_timer_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
621	struct comedi_insn *insn, unsigned int *data)
622{
623	return -EINVAL;
624}
625
626/* PCMCIA stuff */
627
628/*======================================================================
629
630    The following pcmcia code for the pcm-das08 is adapted from the
631    dummy_cs.c driver of the Linux PCMCIA Card Services package.
632
633    The initial developer of the original code is David A. Hinds
634    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
635    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
636
637======================================================================*/
638
639/*
640   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
641   you do not define PCMCIA_DEBUG at all, all the debug code will be
642   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
643   be present but disabled -- but it can then be enabled for specific
644   modules at load time with a 'pc_debug=#' option to insmod.
645*/
646#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
647
648#ifdef PCMCIA_DEBUG
649static int pc_debug = PCMCIA_DEBUG;
650module_param(pc_debug, int, 0644);
651#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
652static char *version =
653	"cb_das16_cs.c pcmcia code (David Schleef), modified from dummy_cs.c 1.31 2001/08/24 12:13:13 (David Hinds)";
654#else
655#define DEBUG(n, args...)
656#endif
657
658/*====================================================================*/
659
660static void das16cs_pcmcia_config(struct pcmcia_device *link);
661static void das16cs_pcmcia_release(struct pcmcia_device *link);
662static int das16cs_pcmcia_suspend(struct pcmcia_device *p_dev);
663static int das16cs_pcmcia_resume(struct pcmcia_device *p_dev);
664
665/*
666   The attach() and detach() entry points are used to create and destroy
667   "instances" of the driver, where each instance represents everything
668   needed to manage one actual PCMCIA card.
669*/
670
671static int das16cs_pcmcia_attach(struct pcmcia_device *);
672static void das16cs_pcmcia_detach(struct pcmcia_device *);
673
674/*
675   You'll also need to prototype all the functions that will actually
676   be used to talk to your device.  See 'memory_cs' for a good example
677   of a fully self-sufficient driver; the other drivers rely more or
678   less on other parts of the kernel.
679*/
680
681/*
682   The dev_info variable is the "key" that is used to match up this
683   device driver with appropriate cards, through the card configuration
684   database.
685*/
686
687static dev_info_t dev_info = "cb_das16_cs";
688
689struct local_info_t {
690	struct pcmcia_device *link;
691	dev_node_t node;
692	int stop;
693	struct bus_operations *bus;
694};
695
696/*======================================================================
697
698    das16cs_pcmcia_attach() creates an "instance" of the driver, allocating
699    local data structures for one device.  The device is registered
700    with Card Services.
701
702    The dev_link structure is initialized, but we don't actually
703    configure the card at this point -- we wait until we receive a
704    card insertion event.
705
706======================================================================*/
707
708static int das16cs_pcmcia_attach(struct pcmcia_device *link)
709{
710	struct local_info_t *local;
711
712	DEBUG(0, "das16cs_pcmcia_attach()\n");
713
714	/* Allocate space for private device-specific data */
715	local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
716	if (!local)
717		return -ENOMEM;
718	local->link = link;
719	link->priv = local;
720
721	/* Initialize the pcmcia_device structure */
722	/* Interrupt setup */
723	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
724	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
725	link->irq.Handler = NULL;
726
727	link->conf.Attributes = 0;
728	link->conf.IntType = INT_MEMORY_AND_IO;
729
730	cur_dev = link;
731
732	das16cs_pcmcia_config(link);
733
734	return 0;
735}				/* das16cs_pcmcia_attach */
736
737static void das16cs_pcmcia_detach(struct pcmcia_device *link)
738{
739	DEBUG(0, "das16cs_pcmcia_detach(0x%p)\n", link);
740
741	if (link->dev_node) {
742		((struct local_info_t *) link->priv)->stop = 1;
743		das16cs_pcmcia_release(link);
744	}
745	/* This points to the parent struct local_info_t struct */
746	if (link->priv)
747		kfree(link->priv);
748}				/* das16cs_pcmcia_detach */
749
750static void das16cs_pcmcia_config(struct pcmcia_device *link)
751{
752	struct local_info_t *dev = link->priv;
753	tuple_t tuple;
754	cisparse_t parse;
755	int last_fn, last_ret;
756	u_char buf[64];
757	cistpl_cftable_entry_t dflt = { 0 };
758
759	DEBUG(0, "das16cs_pcmcia_config(0x%p)\n", link);
760
761	/*
762	   This reads the card's CONFIG tuple to find its configuration
763	   registers.
764	 */
765	tuple.DesiredTuple = CISTPL_CONFIG;
766	tuple.Attributes = 0;
767	tuple.TupleData = buf;
768	tuple.TupleDataMax = sizeof(buf);
769	tuple.TupleOffset = 0;
770
771	last_fn = GetFirstTuple;
772	last_ret = pcmcia_get_first_tuple(link, &tuple);
773	if (last_ret != 0)
774		goto cs_failed;
775
776	last_fn = GetTupleData;
777	last_ret = pcmcia_get_tuple_data(link, &tuple);
778	if (last_ret != 0)
779		goto cs_failed;
780
781	last_fn = ParseTuple;
782	last_ret = pcmcia_parse_tuple(&tuple, &parse);
783	if (last_ret != 0)
784		goto cs_failed;
785
786	link->conf.ConfigBase = parse.config.base;
787	link->conf.Present = parse.config.rmask[0];
788
789	/*
790	   In this loop, we scan the CIS for configuration table entries,
791	   each of which describes a valid card configuration, including
792	   voltage, IO window, memory window, and interrupt settings.
793
794	   We make no assumptions about the card to be configured: we use
795	   just the information available in the CIS.  In an ideal world,
796	   this would work for any PCMCIA card, but it requires a complete
797	   and accurate CIS.  In practice, a driver usually "knows" most of
798	   these things without consulting the CIS, and most client drivers
799	   will only use the CIS to fill in implementation-defined details.
800	 */
801	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
802	last_fn = GetFirstTuple;
803
804	last_ret = pcmcia_get_first_tuple(link, &tuple);
805	if (last_ret)
806		goto cs_failed;
807
808	while (1) {
809		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
810		if (pcmcia_get_tuple_data(link, &tuple))
811			goto next_entry;
812		if (pcmcia_parse_tuple(&tuple, &parse))
813			goto next_entry;
814
815		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
816			dflt = *cfg;
817		if (cfg->index == 0)
818			goto next_entry;
819		link->conf.ConfigIndex = cfg->index;
820
821		/* Does this card need audio output? */
822/*	if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
823		link->conf.Attributes |= CONF_ENABLE_SPKR;
824		link->conf.Status = CCSR_AUDIO_ENA;
825	}
826*/
827		/* Do we need to allocate an interrupt? */
828		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
829			link->conf.Attributes |= CONF_ENABLE_IRQ;
830
831		/* IO window settings */
832		link->io.NumPorts1 = link->io.NumPorts2 = 0;
833		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
834			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
835			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
836			if (!(io->flags & CISTPL_IO_8BIT))
837				link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
838			if (!(io->flags & CISTPL_IO_16BIT))
839				link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
840			link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
841			link->io.BasePort1 = io->win[0].base;
842			link->io.NumPorts1 = io->win[0].len;
843			if (io->nwin > 1) {
844				link->io.Attributes2 = link->io.Attributes1;
845				link->io.BasePort2 = io->win[1].base;
846				link->io.NumPorts2 = io->win[1].len;
847			}
848			/* This reserves IO space but doesn't actually enable it */
849			if (pcmcia_request_io(link, &link->io))
850				goto next_entry;
851		}
852
853		/* If we got this far, we're cool! */
854		break;
855
856	      next_entry:
857		last_fn = GetNextTuple;
858
859		last_ret = pcmcia_get_next_tuple(link, &tuple);
860		if (last_ret)
861			goto cs_failed;
862	}
863
864	/*
865	   Allocate an interrupt line.  Note that this does not assign a
866	   handler to the interrupt, unless the 'Handler' member of the
867	   irq structure is initialized.
868	 */
869	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
870		last_fn = RequestIRQ;
871
872		last_ret = pcmcia_request_irq(link, &link->irq);
873		if (last_ret)
874			goto cs_failed;
875	}
876	/*
877	   This actually configures the PCMCIA socket -- setting up
878	   the I/O windows and the interrupt mapping, and putting the
879	   card and host interface into "Memory and IO" mode.
880	 */
881	last_fn = RequestConfiguration;
882	last_ret = pcmcia_request_configuration(link, &link->conf);
883	if (last_ret)
884		goto cs_failed;
885
886	/*
887	   At this point, the dev_node_t structure(s) need to be
888	   initialized and arranged in a linked list at link->dev.
889	 */
890	sprintf(dev->node.dev_name, "cb_das16_cs");
891	dev->node.major = dev->node.minor = 0;
892	link->dev_node = &dev->node;
893
894	/* Finally, report what we've done */
895	printk(KERN_INFO "%s: index 0x%02x",
896		dev->node.dev_name, link->conf.ConfigIndex);
897	if (link->conf.Attributes & CONF_ENABLE_IRQ)
898		printk(", irq %u", link->irq.AssignedIRQ);
899	if (link->io.NumPorts1)
900		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
901			link->io.BasePort1 + link->io.NumPorts1 - 1);
902	if (link->io.NumPorts2)
903		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
904			link->io.BasePort2 + link->io.NumPorts2 - 1);
905	printk("\n");
906
907	return;
908
909      cs_failed:
910	cs_error(link, last_fn, last_ret);
911	das16cs_pcmcia_release(link);
912}				/* das16cs_pcmcia_config */
913
914static void das16cs_pcmcia_release(struct pcmcia_device *link)
915{
916	DEBUG(0, "das16cs_pcmcia_release(0x%p)\n", link);
917	pcmcia_disable_device(link);
918}				/* das16cs_pcmcia_release */
919
920static int das16cs_pcmcia_suspend(struct pcmcia_device *link)
921{
922	struct local_info_t *local = link->priv;
923
924	/* Mark the device as stopped, to block IO until later */
925	local->stop = 1;
926
927	return 0;
928}				/* das16cs_pcmcia_suspend */
929
930static int das16cs_pcmcia_resume(struct pcmcia_device *link)
931{
932	struct local_info_t *local = link->priv;
933
934	local->stop = 0;
935	return 0;
936}				/* das16cs_pcmcia_resume */
937
938/*====================================================================*/
939
940static struct pcmcia_device_id das16cs_id_table[] = {
941	PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
942	PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
943	PCMCIA_DEVICE_NULL
944};
945
946MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table);
947
948struct pcmcia_driver das16cs_driver = {
949	.probe = das16cs_pcmcia_attach,
950	.remove = das16cs_pcmcia_detach,
951	.suspend = das16cs_pcmcia_suspend,
952	.resume = das16cs_pcmcia_resume,
953	.id_table = das16cs_id_table,
954	.owner = THIS_MODULE,
955	.drv = {
956			.name = dev_info,
957		},
958};
959
960static int __init init_das16cs_pcmcia_cs(void)
961{
962	DEBUG(0, "%s\n", version);
963	pcmcia_register_driver(&das16cs_driver);
964	return 0;
965}
966
967static void __exit exit_das16cs_pcmcia_cs(void)
968{
969	DEBUG(0, "das16cs_pcmcia_cs: unloading\n");
970	pcmcia_unregister_driver(&das16cs_driver);
971}
972
973int __init init_module(void)
974{
975	int ret;
976
977	ret = init_das16cs_pcmcia_cs();
978	if (ret < 0)
979		return ret;
980
981	return comedi_driver_register(&driver_das16cs);
982}
983
984void __exit cleanup_module(void)
985{
986	exit_das16cs_pcmcia_cs();
987	comedi_driver_unregister(&driver_das16cs);
988}
989
990#else
991COMEDI_INITCLEANUP(driver_das16cs);
992#endif /* CONFIG_PCMCIA */
993