678fbf67d7a89b05a3f39401e7e861f1a891c23e
[linux-2.6.git] / drivers / staging / comedi / drivers / cb_das16_cs.c
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 /*
24 Driver: cb_das16_cs
25 Description: Computer Boards PC-CARD DAS16/16
26 Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), PC-CARD DAS16/16-AO
27 Author: ds
28 Updated: Mon, 04 Nov 2002 20:04:21 -0800
29 Status: experimental
30
31
32 */
33
34 #include <linux/interrupt.h>
35 #include <linux/slab.h>
36 #include "../comedidev.h"
37 #include <linux/delay.h>
38 #include <linux/pci.h>
39
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
57 struct das16cs_board {
58         const char *name;
59         int device_id;
60         int n_ao_chans;
61 };
62 static 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 ARRAY_SIZE(das16cs_boards)
81 #define thisboard ((const struct das16cs_board *)dev->board_ptr)
82
83 struct 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
92 static int das16cs_attach(struct comedi_device *dev,
93                           struct comedi_devconfig *it);
94 static int das16cs_detach(struct comedi_device *dev);
95 static 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
102 static struct pcmcia_device *cur_dev = NULL;
103
104 static 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
112 static irqreturn_t das16cs_interrupt(int irq, void *d);
113 static int das16cs_ai_rinsn(struct comedi_device *dev,
114                             struct comedi_subdevice *s,
115                             struct comedi_insn *insn, unsigned int *data);
116 static int das16cs_ai_cmd(struct comedi_device *dev,
117                           struct comedi_subdevice *s);
118 static int das16cs_ai_cmdtest(struct comedi_device *dev,
119                               struct comedi_subdevice *s,
120                               struct comedi_cmd *cmd);
121 static int das16cs_ao_winsn(struct comedi_device *dev,
122                             struct comedi_subdevice *s,
123                             struct comedi_insn *insn, unsigned int *data);
124 static int das16cs_ao_rinsn(struct comedi_device *dev,
125                             struct comedi_subdevice *s,
126                             struct comedi_insn *insn, unsigned int *data);
127 static int das16cs_dio_insn_bits(struct comedi_device *dev,
128                                  struct comedi_subdevice *s,
129                                  struct comedi_insn *insn, unsigned int *data);
130 static int das16cs_dio_insn_config(struct comedi_device *dev,
131                                    struct comedi_subdevice *s,
132                                    struct comedi_insn *insn,
133                                    unsigned int *data);
134 static int das16cs_timer_insn_read(struct comedi_device *dev,
135                                    struct comedi_subdevice *s,
136                                    struct comedi_insn *insn,
137                                    unsigned int *data);
138 static int das16cs_timer_insn_config(struct comedi_device *dev,
139                                      struct comedi_subdevice *s,
140                                      struct comedi_insn *insn,
141                                      unsigned int *data);
142
143 static const struct das16cs_board *das16cs_probe(struct comedi_device *dev,
144                                                  struct pcmcia_device *link)
145 {
146         int i;
147
148         for (i = 0; i < n_boards; i++) {
149                 if (das16cs_boards[i].device_id == link->card_id)
150                         return das16cs_boards + i;
151         }
152
153         printk("unknown board!\n");
154
155         return NULL;
156 }
157
158 static int das16cs_attach(struct comedi_device *dev,
159                           struct comedi_devconfig *it)
160 {
161         struct pcmcia_device *link;
162         struct comedi_subdevice *s;
163         int ret;
164         int i;
165
166         printk("comedi%d: cb_das16_cs: ", dev->minor);
167
168         link = cur_dev;         /* XXX hack */
169         if (!link)
170                 return -EIO;
171
172         dev->iobase = link->resource[0]->start;;
173         printk("I/O base=0x%04lx ", dev->iobase);
174
175         printk("fingerprint:\n");
176         for (i = 0; i < 48; i += 2)
177                 printk("%04x ", inw(dev->iobase + i));
178
179         printk("\n");
180
181         ret = request_irq(link->irq, das16cs_interrupt,
182                           IRQF_SHARED, "cb_das16_cs", dev);
183         if (ret < 0)
184                 return ret;
185
186         dev->irq = link->irq;
187
188         printk("irq=%u ", dev->irq);
189
190         dev->board_ptr = das16cs_probe(dev, link);
191         if (!dev->board_ptr)
192                 return -EIO;
193
194         dev->board_name = thisboard->name;
195
196         if (alloc_private(dev, sizeof(struct das16cs_private)) < 0)
197                 return -ENOMEM;
198
199         if (alloc_subdevices(dev, 4) < 0)
200                 return -ENOMEM;
201
202         s = dev->subdevices + 0;
203         dev->read_subdev = s;
204         /* analog input subdevice */
205         s->type = COMEDI_SUBD_AI;
206         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
207         s->n_chan = 16;
208         s->maxdata = 0xffff;
209         s->range_table = &das16cs_ai_range;
210         s->len_chanlist = 16;
211         s->insn_read = das16cs_ai_rinsn;
212         s->do_cmd = das16cs_ai_cmd;
213         s->do_cmdtest = das16cs_ai_cmdtest;
214
215         s = dev->subdevices + 1;
216         /* analog output subdevice */
217         if (thisboard->n_ao_chans) {
218                 s->type = COMEDI_SUBD_AO;
219                 s->subdev_flags = SDF_WRITABLE;
220                 s->n_chan = thisboard->n_ao_chans;
221                 s->maxdata = 0xffff;
222                 s->range_table = &range_bipolar10;
223                 s->insn_write = &das16cs_ao_winsn;
224                 s->insn_read = &das16cs_ao_rinsn;
225         }
226
227         s = dev->subdevices + 2;
228         /* digital i/o subdevice */
229         if (1) {
230                 s->type = COMEDI_SUBD_DIO;
231                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
232                 s->n_chan = 8;
233                 s->maxdata = 1;
234                 s->range_table = &range_digital;
235                 s->insn_bits = das16cs_dio_insn_bits;
236                 s->insn_config = das16cs_dio_insn_config;
237         } else {
238                 s->type = COMEDI_SUBD_UNUSED;
239         }
240
241         s = dev->subdevices + 3;
242         /* timer subdevice */
243         if (0) {
244                 s->type = COMEDI_SUBD_TIMER;
245                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
246                 s->n_chan = 1;
247                 s->maxdata = 0xff;
248                 s->range_table = &range_unknown;
249                 s->insn_read = das16cs_timer_insn_read;
250                 s->insn_config = das16cs_timer_insn_config;
251         } else {
252                 s->type = COMEDI_SUBD_UNUSED;
253         }
254
255         printk("attached\n");
256
257         return 1;
258 }
259
260 static int das16cs_detach(struct comedi_device *dev)
261 {
262         printk("comedi%d: das16cs: remove\n", dev->minor);
263
264         if (dev->irq)
265                 free_irq(dev->irq, dev);
266
267
268         return 0;
269 }
270
271 static irqreturn_t das16cs_interrupt(int irq, void *d)
272 {
273         /* struct comedi_device *dev = d; */
274         return IRQ_HANDLED;
275 }
276
277 /*
278  * "instructions" read/write data in "one-shot" or "software-triggered"
279  * mode.
280  */
281 static int das16cs_ai_rinsn(struct comedi_device *dev,
282                             struct comedi_subdevice *s,
283                             struct comedi_insn *insn, unsigned int *data)
284 {
285         int i;
286         int to;
287         int aref;
288         int range;
289         int chan;
290         static int range_bits[] = { 0x800, 0x000, 0x100, 0x200 };
291
292         chan = CR_CHAN(insn->chanspec);
293         aref = CR_AREF(insn->chanspec);
294         range = CR_RANGE(insn->chanspec);
295
296         outw(chan, dev->iobase + 2);
297
298         devpriv->status1 &= ~0xf320;
299         devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020;
300         outw(devpriv->status1, dev->iobase + 4);
301
302         devpriv->status2 &= ~0xff00;
303         devpriv->status2 |= range_bits[range];
304         outw(devpriv->status2, dev->iobase + 6);
305
306         for (i = 0; i < insn->n; i++) {
307                 outw(0, dev->iobase);
308
309 #define TIMEOUT 1000
310                 for (to = 0; to < TIMEOUT; to++) {
311                         if (inw(dev->iobase + 4) & 0x0080)
312                                 break;
313                 }
314                 if (to == TIMEOUT) {
315                         printk("cb_das16_cs: ai timeout\n");
316                         return -ETIME;
317                 }
318                 data[i] = (unsigned short)inw(dev->iobase + 0);
319         }
320
321         return i;
322 }
323
324 static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
325 {
326         return -EINVAL;
327 }
328
329 static int das16cs_ai_cmdtest(struct comedi_device *dev,
330                               struct comedi_subdevice *s,
331                               struct comedi_cmd *cmd)
332 {
333         int err = 0;
334         int tmp;
335
336         /* cmdtest tests a particular command to see if it is valid.
337          * Using the cmdtest ioctl, a user can create a valid cmd
338          * and then have it executes by the cmd ioctl.
339          *
340          * cmdtest returns 1,2,3,4 or 0, depending on which tests
341          * the command passes. */
342
343         /* step 1: make sure trigger sources are trivially valid */
344
345         tmp = cmd->start_src;
346         cmd->start_src &= TRIG_NOW;
347         if (!cmd->start_src || tmp != cmd->start_src)
348                 err++;
349
350         tmp = cmd->scan_begin_src;
351         cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
352         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
353                 err++;
354
355         tmp = cmd->convert_src;
356         cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
357         if (!cmd->convert_src || tmp != cmd->convert_src)
358                 err++;
359
360         tmp = cmd->scan_end_src;
361         cmd->scan_end_src &= TRIG_COUNT;
362         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
363                 err++;
364
365         tmp = cmd->stop_src;
366         cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
367         if (!cmd->stop_src || tmp != cmd->stop_src)
368                 err++;
369
370         if (err)
371                 return 1;
372
373         /* step 2: make sure trigger sources are unique and mutually compatible */
374
375         /* note that mutual compatibility is not an issue here */
376         if (cmd->scan_begin_src != TRIG_TIMER &&
377             cmd->scan_begin_src != TRIG_EXT)
378                 err++;
379         if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
380                 err++;
381         if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
382                 err++;
383
384         if (err)
385                 return 2;
386
387         /* step 3: make sure arguments are trivially compatible */
388
389         if (cmd->start_arg != 0) {
390                 cmd->start_arg = 0;
391                 err++;
392         }
393 #define MAX_SPEED       10000   /* in nanoseconds */
394 #define MIN_SPEED       1000000000      /* in nanoseconds */
395
396         if (cmd->scan_begin_src == TRIG_TIMER) {
397                 if (cmd->scan_begin_arg < MAX_SPEED) {
398                         cmd->scan_begin_arg = MAX_SPEED;
399                         err++;
400                 }
401                 if (cmd->scan_begin_arg > MIN_SPEED) {
402                         cmd->scan_begin_arg = MIN_SPEED;
403                         err++;
404                 }
405         } else {
406                 /* external trigger */
407                 /* should be level/edge, hi/lo specification here */
408                 /* should specify multiple external triggers */
409                 if (cmd->scan_begin_arg > 9) {
410                         cmd->scan_begin_arg = 9;
411                         err++;
412                 }
413         }
414         if (cmd->convert_src == TRIG_TIMER) {
415                 if (cmd->convert_arg < MAX_SPEED) {
416                         cmd->convert_arg = MAX_SPEED;
417                         err++;
418                 }
419                 if (cmd->convert_arg > MIN_SPEED) {
420                         cmd->convert_arg = MIN_SPEED;
421                         err++;
422                 }
423         } else {
424                 /* external trigger */
425                 /* see above */
426                 if (cmd->convert_arg > 9) {
427                         cmd->convert_arg = 9;
428                         err++;
429                 }
430         }
431
432         if (cmd->scan_end_arg != cmd->chanlist_len) {
433                 cmd->scan_end_arg = cmd->chanlist_len;
434                 err++;
435         }
436         if (cmd->stop_src == TRIG_COUNT) {
437                 if (cmd->stop_arg > 0x00ffffff) {
438                         cmd->stop_arg = 0x00ffffff;
439                         err++;
440                 }
441         } else {
442                 /* TRIG_NONE */
443                 if (cmd->stop_arg != 0) {
444                         cmd->stop_arg = 0;
445                         err++;
446                 }
447         }
448
449         if (err)
450                 return 3;
451
452         /* step 4: fix up any arguments */
453
454         if (cmd->scan_begin_src == TRIG_TIMER) {
455                 unsigned int div1 = 0, div2 = 0;
456
457                 tmp = cmd->scan_begin_arg;
458                 i8253_cascade_ns_to_timer(100, &div1, &div2,
459                                           &cmd->scan_begin_arg,
460                                           cmd->flags & TRIG_ROUND_MASK);
461                 if (tmp != cmd->scan_begin_arg)
462                         err++;
463         }
464         if (cmd->convert_src == TRIG_TIMER) {
465                 unsigned int div1 = 0, div2 = 0;
466
467                 tmp = cmd->convert_arg;
468                 i8253_cascade_ns_to_timer(100, &div1, &div2,
469                                           &cmd->scan_begin_arg,
470                                           cmd->flags & TRIG_ROUND_MASK);
471                 if (tmp != cmd->convert_arg)
472                         err++;
473                 if (cmd->scan_begin_src == TRIG_TIMER &&
474                     cmd->scan_begin_arg <
475                     cmd->convert_arg * cmd->scan_end_arg) {
476                         cmd->scan_begin_arg =
477                             cmd->convert_arg * cmd->scan_end_arg;
478                         err++;
479                 }
480         }
481
482         if (err)
483                 return 4;
484
485         return 0;
486 }
487
488 static int das16cs_ao_winsn(struct comedi_device *dev,
489                             struct comedi_subdevice *s,
490                             struct comedi_insn *insn, unsigned int *data)
491 {
492         int i;
493         int chan = CR_CHAN(insn->chanspec);
494         unsigned short status1;
495         unsigned short d;
496         int bit;
497
498         for (i = 0; i < insn->n; i++) {
499                 devpriv->ao_readback[chan] = data[i];
500                 d = data[i];
501
502                 outw(devpriv->status1, dev->iobase + 4);
503                 udelay(1);
504
505                 status1 = devpriv->status1 & ~0xf;
506                 if (chan)
507                         status1 |= 0x0001;
508                 else
509                         status1 |= 0x0008;
510
511 /*              printk("0x%04x\n",status1);*/
512                 outw(status1, dev->iobase + 4);
513                 udelay(1);
514
515                 for (bit = 15; bit >= 0; bit--) {
516                         int b = (d >> bit) & 0x1;
517                         b <<= 1;
518 /*                      printk("0x%04x\n",status1 | b | 0x0000);*/
519                         outw(status1 | b | 0x0000, dev->iobase + 4);
520                         udelay(1);
521 /*                      printk("0x%04x\n",status1 | b | 0x0004);*/
522                         outw(status1 | b | 0x0004, dev->iobase + 4);
523                         udelay(1);
524                 }
525 /*              make high both DAC0CS and DAC1CS to load
526                 new data and update analog output*/
527                 outw(status1 | 0x9, dev->iobase + 4);
528         }
529
530         return i;
531 }
532
533 /* AO subdevices should have a read insn as well as a write insn.
534  * Usually this means copying a value stored in devpriv. */
535 static int das16cs_ao_rinsn(struct comedi_device *dev,
536                             struct comedi_subdevice *s,
537                             struct comedi_insn *insn, unsigned int *data)
538 {
539         int i;
540         int chan = CR_CHAN(insn->chanspec);
541
542         for (i = 0; i < insn->n; i++)
543                 data[i] = devpriv->ao_readback[chan];
544
545         return i;
546 }
547
548 /* DIO devices are slightly special.  Although it is possible to
549  * implement the insn_read/insn_write interface, it is much more
550  * useful to applications if you implement the insn_bits interface.
551  * This allows packed reading/writing of the DIO channels.  The
552  * comedi core can convert between insn_bits and insn_read/write */
553 static int das16cs_dio_insn_bits(struct comedi_device *dev,
554                                  struct comedi_subdevice *s,
555                                  struct comedi_insn *insn, unsigned int *data)
556 {
557         if (insn->n != 2)
558                 return -EINVAL;
559
560         if (data[0]) {
561                 s->state &= ~data[0];
562                 s->state |= data[0] & data[1];
563
564                 outw(s->state, dev->iobase + 16);
565         }
566
567         /* on return, data[1] contains the value of the digital
568          * input and output lines. */
569         data[1] = inw(dev->iobase + 16);
570
571         return 2;
572 }
573
574 static int das16cs_dio_insn_config(struct comedi_device *dev,
575                                    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->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
596                 return insn->n;
597                 break;
598         default:
599                 return -EINVAL;
600                 break;
601         }
602
603         devpriv->status2 &= ~0x00c0;
604         devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0;
605         devpriv->status2 |= (s->io_bits & 0x0f) ? 0x0040 : 0;
606
607         outw(devpriv->status2, dev->iobase + 6);
608
609         return insn->n;
610 }
611
612 static int das16cs_timer_insn_read(struct comedi_device *dev,
613                                    struct comedi_subdevice *s,
614                                    struct comedi_insn *insn, unsigned int *data)
615 {
616         return -EINVAL;
617 }
618
619 static int das16cs_timer_insn_config(struct comedi_device *dev,
620                                      struct comedi_subdevice *s,
621                                      struct comedi_insn *insn,
622                                      unsigned int *data)
623 {
624         return -EINVAL;
625 }
626
627 /* PCMCIA stuff */
628
629 /*======================================================================
630
631     The following pcmcia code for the pcm-das08 is adapted from the
632     dummy_cs.c driver of the Linux PCMCIA Card Services package.
633
634     The initial developer of the original code is David A. Hinds
635     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
636     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
637
638 ======================================================================*/
639
640 #if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
641
642 static void das16cs_pcmcia_config(struct pcmcia_device *link);
643 static void das16cs_pcmcia_release(struct pcmcia_device *link);
644 static int das16cs_pcmcia_suspend(struct pcmcia_device *p_dev);
645 static int das16cs_pcmcia_resume(struct pcmcia_device *p_dev);
646
647 /*
648    The attach() and detach() entry points are used to create and destroy
649    "instances" of the driver, where each instance represents everything
650    needed to manage one actual PCMCIA card.
651 */
652
653 static int das16cs_pcmcia_attach(struct pcmcia_device *);
654 static void das16cs_pcmcia_detach(struct pcmcia_device *);
655
656 /*
657    You'll also need to prototype all the functions that will actually
658    be used to talk to your device.  See 'memory_cs' for a good example
659    of a fully self-sufficient driver; the other drivers rely more or
660    less on other parts of the kernel.
661 */
662
663 struct local_info_t {
664         struct pcmcia_device *link;
665         int stop;
666         struct bus_operations *bus;
667 };
668
669 /*======================================================================
670
671     das16cs_pcmcia_attach() creates an "instance" of the driver, allocating
672     local data structures for one device.  The device is registered
673     with Card Services.
674
675     The dev_link structure is initialized, but we don't actually
676     configure the card at this point -- we wait until we receive a
677     card insertion event.
678
679 ======================================================================*/
680
681 static int das16cs_pcmcia_attach(struct pcmcia_device *link)
682 {
683         struct local_info_t *local;
684
685         dev_dbg(&link->dev, "das16cs_pcmcia_attach()\n");
686
687         /* Allocate space for private device-specific data */
688         local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
689         if (!local)
690                 return -ENOMEM;
691         local->link = link;
692         link->priv = local;
693
694         cur_dev = link;
695
696         das16cs_pcmcia_config(link);
697
698         return 0;
699 }                               /* das16cs_pcmcia_attach */
700
701 static void das16cs_pcmcia_detach(struct pcmcia_device *link)
702 {
703         dev_dbg(&link->dev, "das16cs_pcmcia_detach\n");
704
705         ((struct local_info_t *)link->priv)->stop = 1;
706         das16cs_pcmcia_release(link);
707         /* This points to the parent struct local_info_t struct */
708         kfree(link->priv);
709 }                               /* das16cs_pcmcia_detach */
710
711
712 static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev,
713                                 cistpl_cftable_entry_t *cfg,
714                                 cistpl_cftable_entry_t *dflt,
715                                 void *priv_data)
716 {
717         if (cfg->index == 0)
718                 return -EINVAL;
719
720         /* Do we need to allocate an interrupt? */
721         p_dev->config_flags |= CONF_ENABLE_IRQ;
722
723         /* IO window settings */
724         p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
725         if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
726                 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
727                 p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
728                 p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
729                 p_dev->resource[0]->flags |=
730                         pcmcia_io_cfg_data_width(io->flags);
731                 p_dev->resource[0]->start = io->win[0].base;
732                 p_dev->resource[0]->end = io->win[0].len;
733                 if (io->nwin > 1) {
734                         p_dev->resource[1]->flags = p_dev->resource[0]->flags;
735                         p_dev->resource[1]->start = io->win[1].base;
736                         p_dev->resource[1]->end = io->win[1].len;
737                 }
738                 /* This reserves IO space but doesn't actually enable it */
739                 return pcmcia_request_io(p_dev);
740         }
741
742         return 0;
743 }
744
745 static void das16cs_pcmcia_config(struct pcmcia_device *link)
746 {
747         int ret;
748
749         dev_dbg(&link->dev, "das16cs_pcmcia_config\n");
750
751         ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL);
752         if (ret) {
753                 dev_warn(&link->dev, "no configuration found\n");
754                 goto failed;
755         }
756
757         if (!link->irq)
758                 goto failed;
759
760         /*
761            This actually configures the PCMCIA socket -- setting up
762            the I/O windows and the interrupt mapping, and putting the
763            card and host interface into "Memory and IO" mode.
764          */
765         ret = pcmcia_enable_device(link);
766         if (ret)
767                 goto failed;
768
769         /* Finally, report what we've done */
770         dev_info(&link->dev, "index 0x%02x", link->config_index);
771         printk(", irq %u", link->irq);
772         if (link->resource[0])
773                 printk(", io %pR", link->resource[0]);
774         if (link->resource[1])
775                 printk(", io %pR", link->resource[1]);
776         printk("\n");
777
778         return;
779
780 failed:
781         das16cs_pcmcia_release(link);
782 }                               /* das16cs_pcmcia_config */
783
784 static void das16cs_pcmcia_release(struct pcmcia_device *link)
785 {
786         dev_dbg(&link->dev, "das16cs_pcmcia_release\n");
787         pcmcia_disable_device(link);
788 }                               /* das16cs_pcmcia_release */
789
790 static int das16cs_pcmcia_suspend(struct pcmcia_device *link)
791 {
792         struct local_info_t *local = link->priv;
793
794         /* Mark the device as stopped, to block IO until later */
795         local->stop = 1;
796
797         return 0;
798 }                               /* das16cs_pcmcia_suspend */
799
800 static int das16cs_pcmcia_resume(struct pcmcia_device *link)
801 {
802         struct local_info_t *local = link->priv;
803
804         local->stop = 0;
805         return 0;
806 }                               /* das16cs_pcmcia_resume */
807
808 /*====================================================================*/
809
810 static struct pcmcia_device_id das16cs_id_table[] = {
811         PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
812         PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
813         PCMCIA_DEVICE_NULL
814 };
815
816 MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table);
817 MODULE_AUTHOR("David A. Schleef <ds@schleef.org>");
818 MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16");
819 MODULE_LICENSE("GPL");
820
821 struct pcmcia_driver das16cs_driver = {
822         .probe = das16cs_pcmcia_attach,
823         .remove = das16cs_pcmcia_detach,
824         .suspend = das16cs_pcmcia_suspend,
825         .resume = das16cs_pcmcia_resume,
826         .id_table = das16cs_id_table,
827         .owner = THIS_MODULE,
828         .drv = {
829                 .name = "cb_das16_cs",
830                 },
831 };
832
833 static int __init init_das16cs_pcmcia_cs(void)
834 {
835         pcmcia_register_driver(&das16cs_driver);
836         return 0;
837 }
838
839 static void __exit exit_das16cs_pcmcia_cs(void)
840 {
841         pr_debug("das16cs_pcmcia_cs: unloading\n");
842         pcmcia_unregister_driver(&das16cs_driver);
843 }
844
845 int __init init_module(void)
846 {
847         int ret;
848
849         ret = init_das16cs_pcmcia_cs();
850         if (ret < 0)
851                 return ret;
852
853         return comedi_driver_register(&driver_das16cs);
854 }
855
856 void __exit cleanup_module(void)
857 {
858         exit_das16cs_pcmcia_cs();
859         comedi_driver_unregister(&driver_das16cs);
860 }
861
862 #else
863 static int __init driver_das16cs_init_module(void)
864 {
865         return comedi_driver_register(&driver_das16cs);
866 }
867
868 static void __exit driver_das16cs_cleanup_module(void)
869 {
870         comedi_driver_unregister(&driver_das16cs);
871 }
872
873 module_init(driver_das16cs_init_module);
874 module_exit(driver_das16cs_cleanup_module);
875 #endif /* CONFIG_PCMCIA */