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