pcmcia: move driver name to struct pcmcia_driver
[deliverable/linux.git] / drivers / staging / comedi / drivers / cb_das16_cs.c
CommitLineData
f0922ec5
DS
1/*
2 comedi/drivers/das16cs.c
3 Driver for Computer Boards PC-CARD DAS16/16.
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2000, 2001, 2002 David A. Schleef <ds@schleef.org>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22*/
23/*
24Driver: cb_das16_cs
25Description: Computer Boards PC-CARD DAS16/16
26Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), PC-CARD DAS16/16-AO
27Author: ds
28Updated: Mon, 04 Nov 2002 20:04:21 -0800
29Status: experimental
30
31
32*/
33
25436dc9 34#include <linux/interrupt.h>
5a0e3ad6 35#include <linux/slab.h>
f0922ec5
DS
36#include "../comedidev.h"
37#include <linux/delay.h>
38#include <linux/pci.h>
39
f0922ec5
DS
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
3281a63d 57struct das16cs_board {
f0922ec5
DS
58 const char *name;
59 int device_id;
60 int n_ao_chans;
3281a63d
BP
61};
62static const struct das16cs_board das16cs_boards[] = {
f0922ec5 63 {
0a85b6f0
MT
64 .device_id = 0x0000, /* unknown */
65 .name = "PC-CARD DAS16/16",
66 .n_ao_chans = 0,
67 },
f0922ec5 68 {
0a85b6f0
MT
69 .device_id = 0x0039,
70 .name = "PC-CARD DAS16/16-AO",
71 .n_ao_chans = 2,
72 },
f0922ec5 73 {
0a85b6f0
MT
74 .device_id = 0x4009,
75 .name = "PCM-DAS16s/16",
76 .n_ao_chans = 0,
77 },
f0922ec5
DS
78};
79
b6ac1613 80#define n_boards ARRAY_SIZE(das16cs_boards)
3281a63d 81#define thisboard ((const struct das16cs_board *)dev->board_ptr)
f0922ec5 82
bfae362a 83struct das16cs_private {
f0922ec5
DS
84 struct pcmcia_device *link;
85
790c5541 86 unsigned int ao_readback[2];
f0922ec5
DS
87 unsigned short status1;
88 unsigned short status2;
bfae362a
BP
89};
90#define devpriv ((struct das16cs_private *)dev->private)
f0922ec5 91
0a85b6f0
MT
92static int das16cs_attach(struct comedi_device *dev,
93 struct comedi_devconfig *it);
da91b269 94static int das16cs_detach(struct comedi_device *dev);
139dfbdf 95static struct comedi_driver driver_das16cs = {
68c3dbff
BP
96 .driver_name = "cb_das16_cs",
97 .module = THIS_MODULE,
98 .attach = das16cs_attach,
99 .detach = das16cs_detach,
f0922ec5
DS
100};
101
102static struct pcmcia_device *cur_dev = NULL;
103
9ced1de6 104static const struct comedi_lrange das16cs_ai_range = { 4, {
0a85b6f0
MT
105 RANGE(-10, 10),
106 RANGE(-5, 5),
107 RANGE(-2.5, 2.5),
108 RANGE(-1.25, 1.25),
109 }
f0922ec5
DS
110};
111
70265d24 112static irqreturn_t das16cs_interrupt(int irq, void *d);
0a85b6f0
MT
113static int das16cs_ai_rinsn(struct comedi_device *dev,
114 struct comedi_subdevice *s,
115 struct comedi_insn *insn, unsigned int *data);
116static int das16cs_ai_cmd(struct comedi_device *dev,
117 struct comedi_subdevice *s);
118static int das16cs_ai_cmdtest(struct comedi_device *dev,
119 struct comedi_subdevice *s,
120 struct comedi_cmd *cmd);
121static int das16cs_ao_winsn(struct comedi_device *dev,
122 struct comedi_subdevice *s,
123 struct comedi_insn *insn, unsigned int *data);
124static int das16cs_ao_rinsn(struct comedi_device *dev,
125 struct comedi_subdevice *s,
126 struct comedi_insn *insn, unsigned int *data);
127static int das16cs_dio_insn_bits(struct comedi_device *dev,
128 struct comedi_subdevice *s,
129 struct comedi_insn *insn, unsigned int *data);
130static int das16cs_dio_insn_config(struct comedi_device *dev,
131 struct comedi_subdevice *s,
132 struct comedi_insn *insn,
133 unsigned int *data);
134static int das16cs_timer_insn_read(struct comedi_device *dev,
135 struct comedi_subdevice *s,
136 struct comedi_insn *insn,
137 unsigned int *data);
138static int das16cs_timer_insn_config(struct comedi_device *dev,
139 struct comedi_subdevice *s,
140 struct comedi_insn *insn,
141 unsigned int *data);
814900c9 142
0a85b6f0
MT
143static const struct das16cs_board *das16cs_probe(struct comedi_device *dev,
144 struct pcmcia_device *link)
f0922ec5 145{
f0922ec5
DS
146 int i;
147
f0922ec5 148 for (i = 0; i < n_boards; i++) {
55a19b39 149 if (das16cs_boards[i].device_id == link->card_id)
f0922ec5 150 return das16cs_boards + i;
f0922ec5
DS
151 }
152
153 printk("unknown board!\n");
154
155 return NULL;
156}
157
0a85b6f0
MT
158static int das16cs_attach(struct comedi_device *dev,
159 struct comedi_devconfig *it)
f0922ec5
DS
160{
161 struct pcmcia_device *link;
34c43922 162 struct comedi_subdevice *s;
f0922ec5
DS
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
9a017a91 172 dev->iobase = link->resource[0]->start;;
f0922ec5
DS
173 printk("I/O base=0x%04lx ", dev->iobase);
174
175 printk("fingerprint:\n");
7b8f2d1a 176 for (i = 0; i < 48; i += 2)
f0922ec5 177 printk("%04x ", inw(dev->iobase + i));
7b8f2d1a 178
f0922ec5
DS
179 printk("\n");
180
eb14120f 181 ret = request_irq(link->irq, das16cs_interrupt,
5f74ea14 182 IRQF_SHARED, "cb_das16_cs", dev);
7b8f2d1a 183 if (ret < 0)
f0922ec5 184 return ret;
7b8f2d1a 185
eb14120f 186 dev->irq = link->irq;
c8d1a126 187
f0922ec5
DS
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
bfae362a 196 if (alloc_private(dev, sizeof(struct das16cs_private)) < 0)
f0922ec5
DS
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
da91b269 260static int das16cs_detach(struct comedi_device *dev)
f0922ec5
DS
261{
262 printk("comedi%d: das16cs: remove\n", dev->minor);
263
7b8f2d1a 264 if (dev->irq)
5f74ea14 265 free_irq(dev->irq, dev);
7b8f2d1a 266
f0922ec5
DS
267
268 return 0;
269}
270
70265d24 271static irqreturn_t das16cs_interrupt(int irq, void *d)
f0922ec5 272{
2696fb57 273 /* struct comedi_device *dev = d; */
f0922ec5
DS
274 return IRQ_HANDLED;
275}
276
277/*
278 * "instructions" read/write data in "one-shot" or "software-triggered"
279 * mode.
280 */
0a85b6f0
MT
281static int das16cs_ai_rinsn(struct comedi_device *dev,
282 struct comedi_subdevice *s,
283 struct comedi_insn *insn, unsigned int *data)
f0922ec5
DS
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
da91b269 324static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
f0922ec5
DS
325{
326 return -EINVAL;
327}
328
0a85b6f0
MT
329static int das16cs_ai_cmdtest(struct comedi_device *dev,
330 struct comedi_subdevice *s,
331 struct comedi_cmd *cmd)
f0922ec5
DS
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
828684f9 375 /* note that mutual compatibility is not an issue here */
f0922ec5 376 if (cmd->scan_begin_src != TRIG_TIMER &&
0a85b6f0 377 cmd->scan_begin_src != TRIG_EXT)
f0922ec5
DS
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) {
48b1aff5 455 unsigned int div1 = 0, div2 = 0;
f0922ec5
DS
456
457 tmp = cmd->scan_begin_arg;
458 i8253_cascade_ns_to_timer(100, &div1, &div2,
0a85b6f0
MT
459 &cmd->scan_begin_arg,
460 cmd->flags & TRIG_ROUND_MASK);
f0922ec5
DS
461 if (tmp != cmd->scan_begin_arg)
462 err++;
463 }
464 if (cmd->convert_src == TRIG_TIMER) {
48b1aff5 465 unsigned int div1 = 0, div2 = 0;
f0922ec5
DS
466
467 tmp = cmd->convert_arg;
468 i8253_cascade_ns_to_timer(100, &div1, &div2,
0a85b6f0
MT
469 &cmd->scan_begin_arg,
470 cmd->flags & TRIG_ROUND_MASK);
f0922ec5
DS
471 if (tmp != cmd->convert_arg)
472 err++;
473 if (cmd->scan_begin_src == TRIG_TIMER &&
0a85b6f0
MT
474 cmd->scan_begin_arg <
475 cmd->convert_arg * cmd->scan_end_arg) {
f0922ec5 476 cmd->scan_begin_arg =
0a85b6f0 477 cmd->convert_arg * cmd->scan_end_arg;
f0922ec5
DS
478 err++;
479 }
480 }
481
482 if (err)
483 return 4;
484
485 return 0;
486}
487
0a85b6f0
MT
488static int das16cs_ao_winsn(struct comedi_device *dev,
489 struct comedi_subdevice *s,
490 struct comedi_insn *insn, unsigned int *data)
f0922ec5
DS
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);
5f74ea14 503 udelay(1);
f0922ec5
DS
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);
5f74ea14 513 udelay(1);
f0922ec5
DS
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);
5f74ea14 520 udelay(1);
f0922ec5
DS
521/* printk("0x%04x\n",status1 | b | 0x0004);*/
522 outw(status1 | b | 0x0004, dev->iobase + 4);
5f74ea14 523 udelay(1);
f0922ec5
DS
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. */
0a85b6f0
MT
535static int das16cs_ao_rinsn(struct comedi_device *dev,
536 struct comedi_subdevice *s,
537 struct comedi_insn *insn, unsigned int *data)
f0922ec5
DS
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 */
0a85b6f0
MT
553static int das16cs_dio_insn_bits(struct comedi_device *dev,
554 struct comedi_subdevice *s,
555 struct comedi_insn *insn, unsigned int *data)
f0922ec5
DS
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
0a85b6f0
MT
574static int das16cs_dio_insn_config(struct comedi_device *dev,
575 struct comedi_subdevice *s,
576 struct comedi_insn *insn, unsigned int *data)
f0922ec5
DS
577{
578 int chan = CR_CHAN(insn->chanspec);
579 int bits;
580
581 if (chan < 4)
582 bits = 0x0f;
583 else
584 bits = 0xf0;
585
586 switch (data[0]) {
587 case INSN_CONFIG_DIO_OUTPUT:
588 s->io_bits |= bits;
589 break;
590 case INSN_CONFIG_DIO_INPUT:
591 s->io_bits &= bits;
592 break;
593 case INSN_CONFIG_DIO_QUERY:
594 data[1] =
0a85b6f0 595 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
f0922ec5
DS
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
0a85b6f0
MT
612static int das16cs_timer_insn_read(struct comedi_device *dev,
613 struct comedi_subdevice *s,
614 struct comedi_insn *insn, unsigned int *data)
f0922ec5
DS
615{
616 return -EINVAL;
617}
618
0a85b6f0
MT
619static int das16cs_timer_insn_config(struct comedi_device *dev,
620 struct comedi_subdevice *s,
621 struct comedi_insn *insn,
622 unsigned int *data)
f0922ec5
DS
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
f0922ec5
DS
640#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
641
f0922ec5
DS
642static void das16cs_pcmcia_config(struct pcmcia_device *link);
643static void das16cs_pcmcia_release(struct pcmcia_device *link);
644static int das16cs_pcmcia_suspend(struct pcmcia_device *p_dev);
645static 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
653static int das16cs_pcmcia_attach(struct pcmcia_device *);
654static 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
d2755d51 663struct local_info_t {
f0922ec5 664 struct pcmcia_device *link;
f0922ec5
DS
665 int stop;
666 struct bus_operations *bus;
d2755d51 667};
f0922ec5
DS
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
681static int das16cs_pcmcia_attach(struct pcmcia_device *link)
682{
d2755d51 683 struct local_info_t *local;
f0922ec5 684
55a19b39 685 dev_dbg(&link->dev, "das16cs_pcmcia_attach()\n");
f0922ec5
DS
686
687 /* Allocate space for private device-specific data */
d2755d51 688 local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
f0922ec5
DS
689 if (!local)
690 return -ENOMEM;
691 local->link = link;
692 link->priv = local;
693
f0922ec5
DS
694 cur_dev = link;
695
696 das16cs_pcmcia_config(link);
697
698 return 0;
699} /* das16cs_pcmcia_attach */
700
701static void das16cs_pcmcia_detach(struct pcmcia_device *link)
702{
55a19b39 703 dev_dbg(&link->dev, "das16cs_pcmcia_detach\n");
f0922ec5 704
eb8804f6
JMC
705 ((struct local_info_t *)link->priv)->stop = 1;
706 das16cs_pcmcia_release(link);
d2755d51 707 /* This points to the parent struct local_info_t struct */
f25bd6bf 708 kfree(link->priv);
f0922ec5
DS
709} /* das16cs_pcmcia_detach */
710
f0922ec5 711
55a19b39 712static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev,
55a19b39
DB
713 void *priv_data)
714{
00990e7c 715 if (p_dev->config_index == 0)
55a19b39 716 return -EINVAL;
f0922ec5 717
00990e7c 718 return pcmcia_request_io(p_dev);
55a19b39
DB
719}
720
721static void das16cs_pcmcia_config(struct pcmcia_device *link)
722{
55a19b39 723 int ret;
f0922ec5 724
55a19b39 725 dev_dbg(&link->dev, "das16cs_pcmcia_config\n");
c3744138 726
00990e7c
DB
727 /* Do we need to allocate an interrupt? */
728 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
729
55a19b39
DB
730 ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL);
731 if (ret) {
732 dev_warn(&link->dev, "no configuration found\n");
733 goto failed;
f0922ec5
DS
734 }
735
eb14120f
DB
736 if (!link->irq)
737 goto failed;
738
f0922ec5
DS
739 /*
740 This actually configures the PCMCIA socket -- setting up
741 the I/O windows and the interrupt mapping, and putting the
742 card and host interface into "Memory and IO" mode.
743 */
1ac71e5a 744 ret = pcmcia_enable_device(link);
55a19b39
DB
745 if (ret)
746 goto failed;
f0922ec5 747
f0922ec5
DS
748 return;
749
55a19b39 750failed:
f0922ec5
DS
751 das16cs_pcmcia_release(link);
752} /* das16cs_pcmcia_config */
753
754static void das16cs_pcmcia_release(struct pcmcia_device *link)
755{
55a19b39 756 dev_dbg(&link->dev, "das16cs_pcmcia_release\n");
f0922ec5
DS
757 pcmcia_disable_device(link);
758} /* das16cs_pcmcia_release */
759
760static int das16cs_pcmcia_suspend(struct pcmcia_device *link)
761{
d2755d51 762 struct local_info_t *local = link->priv;
f0922ec5
DS
763
764 /* Mark the device as stopped, to block IO until later */
765 local->stop = 1;
766
767 return 0;
768} /* das16cs_pcmcia_suspend */
769
770static int das16cs_pcmcia_resume(struct pcmcia_device *link)
771{
d2755d51 772 struct local_info_t *local = link->priv;
f0922ec5
DS
773
774 local->stop = 0;
775 return 0;
776} /* das16cs_pcmcia_resume */
777
778/*====================================================================*/
779
780static struct pcmcia_device_id das16cs_id_table[] = {
781 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
782 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
783 PCMCIA_DEVICE_NULL
784};
785
786MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table);
6c7f8196
AK
787MODULE_AUTHOR("David A. Schleef <ds@schleef.org>");
788MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16");
789MODULE_LICENSE("GPL");
f0922ec5
DS
790
791struct pcmcia_driver das16cs_driver = {
792 .probe = das16cs_pcmcia_attach,
793 .remove = das16cs_pcmcia_detach,
794 .suspend = das16cs_pcmcia_suspend,
795 .resume = das16cs_pcmcia_resume,
796 .id_table = das16cs_id_table,
797 .owner = THIS_MODULE,
2e9b981a 798 .name = "cb_das16_cs",
f0922ec5
DS
799};
800
801static int __init init_das16cs_pcmcia_cs(void)
802{
f0922ec5
DS
803 pcmcia_register_driver(&das16cs_driver);
804 return 0;
805}
806
807static void __exit exit_das16cs_pcmcia_cs(void)
808{
55a19b39 809 pr_debug("das16cs_pcmcia_cs: unloading\n");
f0922ec5
DS
810 pcmcia_unregister_driver(&das16cs_driver);
811}
812
813int __init init_module(void)
814{
815 int ret;
816
817 ret = init_das16cs_pcmcia_cs();
818 if (ret < 0)
819 return ret;
820
821 return comedi_driver_register(&driver_das16cs);
822}
823
824void __exit cleanup_module(void)
825{
826 exit_das16cs_pcmcia_cs();
827 comedi_driver_unregister(&driver_das16cs);
828}
829
830#else
7114a280
AT
831static int __init driver_das16cs_init_module(void)
832{
833 return comedi_driver_register(&driver_das16cs);
834}
835
836static void __exit driver_das16cs_cleanup_module(void)
837{
838 comedi_driver_unregister(&driver_das16cs);
839}
840
841module_init(driver_das16cs_init_module);
842module_exit(driver_das16cs_cleanup_module);
2696fb57 843#endif /* CONFIG_PCMCIA */
This page took 0.242192 seconds and 5 git commands to generate.