Staging: comedi: Remove comedi_subdevice typedef
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / comedi / drivers / cb_das16_cs.c
CommitLineData
f0922ec5
DS
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
57typedef struct das16cs_board_struct {
58 const char *name;
59 int device_id;
60 int n_ao_chans;
61} das16cs_board;
62static const 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 das16cs_board *)dev->board_ptr)
82
83typedef struct {
84 struct pcmcia_device *link;
85
790c5541 86 unsigned int ao_readback[2];
f0922ec5
DS
87 unsigned short status1;
88 unsigned short status2;
89} das16cs_private;
90#define devpriv ((das16cs_private *)dev->private)
91
71b5f4f1
BP
92static int das16cs_attach(struct comedi_device * dev, comedi_devconfig * it);
93static int das16cs_detach(struct comedi_device * dev);
f0922ec5
DS
94static 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 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 PT_REGS_ARG);
34c43922 112static int das16cs_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 113 comedi_insn * insn, unsigned int * data);
34c43922
BP
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,
f0922ec5 116 comedi_cmd * cmd);
34c43922 117static int das16cs_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 118 comedi_insn * insn, unsigned int * data);
34c43922 119static int das16cs_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 120 comedi_insn * insn, unsigned int * data);
34c43922 121static int das16cs_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 122 comedi_insn * insn, unsigned int * data);
34c43922 123static int das16cs_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 124 comedi_insn * insn, unsigned int * data);
34c43922 125static int das16cs_timer_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 126 comedi_insn * insn, unsigned int * data);
34c43922 127static int das16cs_timer_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 128 comedi_insn * insn, unsigned int * data);
f0922ec5 129
71b5f4f1 130static int get_prodid(struct comedi_device * dev, struct pcmcia_device *link)
f0922ec5
DS
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
71b5f4f1 149static const das16cs_board *das16cs_probe(struct comedi_device * dev,
f0922ec5
DS
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
71b5f4f1 168static int das16cs_attach(struct comedi_device * dev, comedi_devconfig * it)
f0922ec5
DS
169{
170 struct pcmcia_device *link;
34c43922 171 struct comedi_subdevice *s;
f0922ec5
DS
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(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
71b5f4f1 268static int das16cs_detach(struct comedi_device * dev)
f0922ec5
DS
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 PT_REGS_ARG)
280{
71b5f4f1 281 //struct comedi_device *dev = d;
f0922ec5
DS
282 return IRQ_HANDLED;
283}
284
285/*
286 * "instructions" read/write data in "one-shot" or "software-triggered"
287 * mode.
288 */
34c43922 289static int das16cs_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 290 comedi_insn * insn, unsigned int * data)
f0922ec5
DS
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
34c43922 331static int das16cs_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
f0922ec5
DS
332{
333 return -EINVAL;
334}
335
34c43922 336static int das16cs_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
f0922ec5
DS
337 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
34c43922 492static int das16cs_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 493 comedi_insn * insn, unsigned int * data)
f0922ec5
DS
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. */
34c43922 538static int das16cs_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 539 comedi_insn * insn, unsigned int * data)
f0922ec5
DS
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 */
34c43922 555static int das16cs_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 556 comedi_insn * insn, unsigned int * data)
f0922ec5
DS
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
34c43922 575static int das16cs_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 576 comedi_insn * insn, unsigned int * data)
f0922ec5
DS
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
34c43922 613static int das16cs_timer_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 614 comedi_insn * insn, unsigned int * data)
f0922ec5
DS
615{
616 return -EINVAL;
617}
618
34c43922 619static int das16cs_timer_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
790c5541 620 comedi_insn * insn, unsigned int * data)
f0922ec5
DS
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
688typedef struct local_info_t {
689 struct pcmcia_device *link;
690 dev_node_t node;
691 int stop;
692 struct bus_operations *bus;
693} local_info_t;
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 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(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 ((local_info_t *) link->priv)->stop = 1;
742 das16cs_pcmcia_release(link);
743 }
744 /* This points to the parent 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 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(link, &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(link, &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 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 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