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