cb_das16_cs.c revision 2202a5a7490a9de282846ea8d4a56d0249e09033
1/* 2 comedi/drivers/das16cs.c 3 Driver for Computer Boards PC-CARD DAS16/16. 4 5 COMEDI - Linux Control and Measurement Device Interface 6 Copyright (C) 2000, 2001, 2002 David A. Schleef <ds@schleef.org> 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 22*/ 23/* 24Driver: cb_das16_cs 25Description: Computer Boards PC-CARD DAS16/16 26Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), PC-CARD DAS16/16-AO 27Author: ds 28Updated: Mon, 04 Nov 2002 20:04:21 -0800 29Status: experimental 30 31 32*/ 33 34#include <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 57struct das16cs_board { 58 const char *name; 59 int device_id; 60 int n_ao_chans; 61}; 62static 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 83struct 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 92static int das16cs_attach(struct comedi_device *dev, 93 struct comedi_devconfig *it); 94static int das16cs_detach(struct comedi_device *dev); 95static 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 102static struct pcmcia_device *cur_dev = NULL; 103 104static 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 112static irqreturn_t das16cs_interrupt(int irq, void *d); 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); 142 143static 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 158static 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 260static 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 271static 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 */ 281static 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 324static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 325{ 326 return -EINVAL; 327} 328 329static 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 488static 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. */ 535static 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 */ 553static 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 574static 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 612static 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 619static 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 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 663struct 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 681static 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 701static 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 712static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev, 713 void *priv_data) 714{ 715 if (p_dev->config_index == 0) 716 return -EINVAL; 717 718 return pcmcia_request_io(p_dev); 719} 720 721static void das16cs_pcmcia_config(struct pcmcia_device *link) 722{ 723 int ret; 724 725 dev_dbg(&link->dev, "das16cs_pcmcia_config\n"); 726 727 /* Do we need to allocate an interrupt? */ 728 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; 729 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; 734 } 735 736 if (!link->irq) 737 goto failed; 738 739 ret = pcmcia_enable_device(link); 740 if (ret) 741 goto failed; 742 743 return; 744 745failed: 746 das16cs_pcmcia_release(link); 747} /* das16cs_pcmcia_config */ 748 749static void das16cs_pcmcia_release(struct pcmcia_device *link) 750{ 751 dev_dbg(&link->dev, "das16cs_pcmcia_release\n"); 752 pcmcia_disable_device(link); 753} /* das16cs_pcmcia_release */ 754 755static int das16cs_pcmcia_suspend(struct pcmcia_device *link) 756{ 757 struct local_info_t *local = link->priv; 758 759 /* Mark the device as stopped, to block IO until later */ 760 local->stop = 1; 761 762 return 0; 763} /* das16cs_pcmcia_suspend */ 764 765static int das16cs_pcmcia_resume(struct pcmcia_device *link) 766{ 767 struct local_info_t *local = link->priv; 768 769 local->stop = 0; 770 return 0; 771} /* das16cs_pcmcia_resume */ 772 773/*====================================================================*/ 774 775static const struct pcmcia_device_id das16cs_id_table[] = { 776 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039), 777 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009), 778 PCMCIA_DEVICE_NULL 779}; 780 781MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table); 782MODULE_AUTHOR("David A. Schleef <ds@schleef.org>"); 783MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16"); 784MODULE_LICENSE("GPL"); 785 786struct pcmcia_driver das16cs_driver = { 787 .probe = das16cs_pcmcia_attach, 788 .remove = das16cs_pcmcia_detach, 789 .suspend = das16cs_pcmcia_suspend, 790 .resume = das16cs_pcmcia_resume, 791 .id_table = das16cs_id_table, 792 .owner = THIS_MODULE, 793 .name = "cb_das16_cs", 794}; 795 796static int __init init_das16cs_pcmcia_cs(void) 797{ 798 pcmcia_register_driver(&das16cs_driver); 799 return 0; 800} 801 802static void __exit exit_das16cs_pcmcia_cs(void) 803{ 804 pr_debug("das16cs_pcmcia_cs: unloading\n"); 805 pcmcia_unregister_driver(&das16cs_driver); 806} 807 808int __init init_module(void) 809{ 810 int ret; 811 812 ret = init_das16cs_pcmcia_cs(); 813 if (ret < 0) 814 return ret; 815 816 return comedi_driver_register(&driver_das16cs); 817} 818 819void __exit cleanup_module(void) 820{ 821 exit_das16cs_pcmcia_cs(); 822 comedi_driver_unregister(&driver_das16cs); 823} 824 825#else 826static int __init driver_das16cs_init_module(void) 827{ 828 return comedi_driver_register(&driver_das16cs); 829} 830 831static void __exit driver_das16cs_cleanup_module(void) 832{ 833 comedi_driver_unregister(&driver_das16cs); 834} 835 836module_init(driver_das16cs_init_module); 837module_exit(driver_das16cs_cleanup_module); 838#endif /* CONFIG_PCMCIA */ 839