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