ALSA: hda - Add position_fix quirk for Biostar mobo
[pandora-kernel.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 "../comedidev.h"
36 #include <linux/delay.h>
37 #include <linux/pci.h>
38
39 #include <pcmcia/cs_types.h>
40 #include <pcmcia/cs.h>
41 #include <pcmcia/cistpl.h>
42 #include <pcmcia/ds.h>
43
44 #include "8253.h"
45
46 #define DAS16CS_SIZE                    18
47
48 #define DAS16CS_ADC_DATA                0
49 #define DAS16CS_DIO_MUX                 2
50 #define DAS16CS_MISC1                   4
51 #define DAS16CS_MISC2                   6
52 #define DAS16CS_CTR0                    8
53 #define DAS16CS_CTR1                    10
54 #define DAS16CS_CTR2                    12
55 #define DAS16CS_CTR_CONTROL             14
56 #define DAS16CS_DIO                     16
57
58 struct das16cs_board {
59         const char *name;
60         int device_id;
61         int n_ao_chans;
62 };
63 static const struct das16cs_board das16cs_boards[] = {
64         {
65          .device_id = 0x0000,   /* unknown */
66          .name = "PC-CARD DAS16/16",
67          .n_ao_chans = 0,
68          },
69         {
70          .device_id = 0x0039,
71          .name = "PC-CARD DAS16/16-AO",
72          .n_ao_chans = 2,
73          },
74         {
75          .device_id = 0x4009,
76          .name = "PCM-DAS16s/16",
77          .n_ao_chans = 0,
78          },
79 };
80
81 #define n_boards ARRAY_SIZE(das16cs_boards)
82 #define thisboard ((const struct das16cs_board *)dev->board_ptr)
83
84 struct das16cs_private {
85         struct pcmcia_device *link;
86
87         unsigned int ao_readback[2];
88         unsigned short status1;
89         unsigned short status2;
90 };
91 #define devpriv ((struct das16cs_private *)dev->private)
92
93 static int das16cs_attach(struct comedi_device *dev,
94                           struct comedi_devconfig *it);
95 static int das16cs_detach(struct comedi_device *dev);
96 static struct comedi_driver driver_das16cs = {
97         .driver_name = "cb_das16_cs",
98         .module = THIS_MODULE,
99         .attach = das16cs_attach,
100         .detach = das16cs_detach,
101 };
102
103 static struct pcmcia_device *cur_dev = NULL;
104
105 static const struct comedi_lrange das16cs_ai_range = { 4, {
106                                                            RANGE(-10, 10),
107                                                            RANGE(-5, 5),
108                                                            RANGE(-2.5, 2.5),
109                                                            RANGE(-1.25, 1.25),
110                                                            }
111 };
112
113 static irqreturn_t das16cs_interrupt(int irq, void *d);
114 static int das16cs_ai_rinsn(struct comedi_device *dev,
115                             struct comedi_subdevice *s,
116                             struct comedi_insn *insn, unsigned int *data);
117 static int das16cs_ai_cmd(struct comedi_device *dev,
118                           struct comedi_subdevice *s);
119 static int das16cs_ai_cmdtest(struct comedi_device *dev,
120                               struct comedi_subdevice *s,
121                               struct comedi_cmd *cmd);
122 static int das16cs_ao_winsn(struct comedi_device *dev,
123                             struct comedi_subdevice *s,
124                             struct comedi_insn *insn, unsigned int *data);
125 static int das16cs_ao_rinsn(struct comedi_device *dev,
126                             struct comedi_subdevice *s,
127                             struct comedi_insn *insn, unsigned int *data);
128 static int das16cs_dio_insn_bits(struct comedi_device *dev,
129                                  struct comedi_subdevice *s,
130                                  struct comedi_insn *insn, unsigned int *data);
131 static int das16cs_dio_insn_config(struct comedi_device *dev,
132                                    struct comedi_subdevice *s,
133                                    struct comedi_insn *insn,
134                                    unsigned int *data);
135 static int das16cs_timer_insn_read(struct comedi_device *dev,
136                                    struct comedi_subdevice *s,
137                                    struct comedi_insn *insn,
138                                    unsigned int *data);
139 static int das16cs_timer_insn_config(struct comedi_device *dev,
140                                      struct comedi_subdevice *s,
141                                      struct comedi_insn *insn,
142                                      unsigned int *data);
143
144 static const struct das16cs_board *das16cs_probe(struct comedi_device *dev,
145                                                  struct pcmcia_device *link)
146 {
147         int i;
148
149         for (i = 0; i < n_boards; i++) {
150                 if (das16cs_boards[i].device_id == link->card_id)
151                         return das16cs_boards + i;
152         }
153
154         printk("unknown board!\n");
155
156         return NULL;
157 }
158
159 static int das16cs_attach(struct comedi_device *dev,
160                           struct comedi_devconfig *it)
161 {
162         struct pcmcia_device *link;
163         struct comedi_subdevice *s;
164         int ret;
165         int i;
166
167         printk("comedi%d: cb_das16_cs: ", dev->minor);
168
169         link = cur_dev;         /* XXX hack */
170         if (!link)
171                 return -EIO;
172
173         dev->iobase = link->io.BasePort1;
174         printk("I/O base=0x%04lx ", dev->iobase);
175
176         printk("fingerprint:\n");
177         for (i = 0; i < 48; i += 2) {
178                 printk("%04x ", inw(dev->iobase + i));
179         }
180         printk("\n");
181
182         ret = request_irq(link->irq.AssignedIRQ, das16cs_interrupt,
183                           IRQF_SHARED, "cb_das16_cs", dev);
184         if (ret < 0) {
185                 return ret;
186         }
187         dev->irq = link->irq.AssignedIRQ;
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 /*
664    The dev_info variable is the "key" that is used to match up this
665    device driver with appropriate cards, through the card configuration
666    database.
667 */
668
669 static dev_info_t dev_info = "cb_das16_cs";
670
671 struct local_info_t {
672         struct pcmcia_device *link;
673         dev_node_t node;
674         int stop;
675         struct bus_operations *bus;
676 };
677
678 /*======================================================================
679
680     das16cs_pcmcia_attach() creates an "instance" of the driver, allocating
681     local data structures for one device.  The device is registered
682     with Card Services.
683
684     The dev_link structure is initialized, but we don't actually
685     configure the card at this point -- we wait until we receive a
686     card insertion event.
687
688 ======================================================================*/
689
690 static int das16cs_pcmcia_attach(struct pcmcia_device *link)
691 {
692         struct local_info_t *local;
693
694         dev_dbg(&link->dev, "das16cs_pcmcia_attach()\n");
695
696         /* Allocate space for private device-specific data */
697         local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
698         if (!local)
699                 return -ENOMEM;
700         local->link = link;
701         link->priv = local;
702
703         /* Initialize the pcmcia_device structure */
704         /* Interrupt setup */
705         link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
706         link->irq.Handler = NULL;
707
708         link->conf.Attributes = 0;
709         link->conf.IntType = INT_MEMORY_AND_IO;
710
711         cur_dev = link;
712
713         das16cs_pcmcia_config(link);
714
715         return 0;
716 }                               /* das16cs_pcmcia_attach */
717
718 static void das16cs_pcmcia_detach(struct pcmcia_device *link)
719 {
720         dev_dbg(&link->dev, "das16cs_pcmcia_detach\n");
721
722         if (link->dev_node) {
723                 ((struct local_info_t *)link->priv)->stop = 1;
724                 das16cs_pcmcia_release(link);
725         }
726         /* This points to the parent struct local_info_t struct */
727         if (link->priv)
728                 kfree(link->priv);
729 }                               /* das16cs_pcmcia_detach */
730
731
732 static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev,
733                                 cistpl_cftable_entry_t *cfg,
734                                 cistpl_cftable_entry_t *dflt,
735                                 unsigned int vcc,
736                                 void *priv_data)
737 {
738         if (cfg->index == 0)
739                 return -EINVAL;
740
741         /* Do we need to allocate an interrupt? */
742         if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
743                 p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
744
745         /* IO window settings */
746         p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
747         if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
748                 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
749                 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
750                 if (!(io->flags & CISTPL_IO_8BIT))
751                         p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
752                 if (!(io->flags & CISTPL_IO_16BIT))
753                         p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
754                 p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
755                 p_dev->io.BasePort1 = io->win[0].base;
756                 p_dev->io.NumPorts1 = io->win[0].len;
757                 if (io->nwin > 1) {
758                         p_dev->io.Attributes2 = p_dev->io.Attributes1;
759                         p_dev->io.BasePort2 = io->win[1].base;
760                         p_dev->io.NumPorts2 = io->win[1].len;
761                 }
762                 /* This reserves IO space but doesn't actually enable it */
763                 return pcmcia_request_io(p_dev, &p_dev->io);
764         }
765
766         return 0;
767 }
768
769 static void das16cs_pcmcia_config(struct pcmcia_device *link)
770 {
771         struct local_info_t *dev = link->priv;
772         int ret;
773
774         dev_dbg(&link->dev, "das16cs_pcmcia_config\n");
775
776         ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL);
777         if (ret) {
778                 dev_warn(&link->dev, "no configuration found\n");
779                 goto failed;
780         }
781
782         /*
783            Allocate an interrupt line.  Note that this does not assign a
784            handler to the interrupt, unless the 'Handler' member of the
785            irq structure is initialized.
786          */
787         if (link->conf.Attributes & CONF_ENABLE_IRQ) {
788                 ret = pcmcia_request_irq(link, &link->irq);
789                 if (ret)
790                         goto failed;
791         }
792         /*
793            This actually configures the PCMCIA socket -- setting up
794            the I/O windows and the interrupt mapping, and putting the
795            card and host interface into "Memory and IO" mode.
796          */
797         ret = pcmcia_request_configuration(link, &link->conf);
798         if (ret)
799                 goto failed;
800
801         /*
802            At this point, the dev_node_t structure(s) need to be
803            initialized and arranged in a linked list at link->dev.
804          */
805         sprintf(dev->node.dev_name, "cb_das16_cs");
806         dev->node.major = dev->node.minor = 0;
807         link->dev_node = &dev->node;
808
809         /* Finally, report what we've done */
810         printk(KERN_INFO "%s: index 0x%02x",
811                dev->node.dev_name, link->conf.ConfigIndex);
812         if (link->conf.Attributes & CONF_ENABLE_IRQ)
813                 printk(", irq %u", link->irq.AssignedIRQ);
814         if (link->io.NumPorts1)
815                 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
816                        link->io.BasePort1 + link->io.NumPorts1 - 1);
817         if (link->io.NumPorts2)
818                 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
819                        link->io.BasePort2 + link->io.NumPorts2 - 1);
820         printk("\n");
821
822         return;
823
824 failed:
825         das16cs_pcmcia_release(link);
826 }                               /* das16cs_pcmcia_config */
827
828 static void das16cs_pcmcia_release(struct pcmcia_device *link)
829 {
830         dev_dbg(&link->dev, "das16cs_pcmcia_release\n");
831         pcmcia_disable_device(link);
832 }                               /* das16cs_pcmcia_release */
833
834 static int das16cs_pcmcia_suspend(struct pcmcia_device *link)
835 {
836         struct local_info_t *local = link->priv;
837
838         /* Mark the device as stopped, to block IO until later */
839         local->stop = 1;
840
841         return 0;
842 }                               /* das16cs_pcmcia_suspend */
843
844 static int das16cs_pcmcia_resume(struct pcmcia_device *link)
845 {
846         struct local_info_t *local = link->priv;
847
848         local->stop = 0;
849         return 0;
850 }                               /* das16cs_pcmcia_resume */
851
852 /*====================================================================*/
853
854 static struct pcmcia_device_id das16cs_id_table[] = {
855         PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
856         PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
857         PCMCIA_DEVICE_NULL
858 };
859
860 MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table);
861
862 struct pcmcia_driver das16cs_driver = {
863         .probe = das16cs_pcmcia_attach,
864         .remove = das16cs_pcmcia_detach,
865         .suspend = das16cs_pcmcia_suspend,
866         .resume = das16cs_pcmcia_resume,
867         .id_table = das16cs_id_table,
868         .owner = THIS_MODULE,
869         .drv = {
870                 .name = dev_info,
871                 },
872 };
873
874 static int __init init_das16cs_pcmcia_cs(void)
875 {
876         pcmcia_register_driver(&das16cs_driver);
877         return 0;
878 }
879
880 static void __exit exit_das16cs_pcmcia_cs(void)
881 {
882         pr_debug("das16cs_pcmcia_cs: unloading\n");
883         pcmcia_unregister_driver(&das16cs_driver);
884 }
885
886 int __init init_module(void)
887 {
888         int ret;
889
890         ret = init_das16cs_pcmcia_cs();
891         if (ret < 0)
892                 return ret;
893
894         return comedi_driver_register(&driver_das16cs);
895 }
896
897 void __exit cleanup_module(void)
898 {
899         exit_das16cs_pcmcia_cs();
900         comedi_driver_unregister(&driver_das16cs);
901 }
902
903 #else
904 COMEDI_INITCLEANUP(driver_das16cs);
905 #endif /* CONFIG_PCMCIA */