cb_das16_cs.c revision 589cabe1b13576b85419d73ba87e50f7f80463fb
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 374 * 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 489static 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. */ 536static 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 */ 554static 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 575static 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 613static 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 620static 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 643static void das16cs_pcmcia_config(struct pcmcia_device *link); 644static void das16cs_pcmcia_release(struct pcmcia_device *link); 645static int das16cs_pcmcia_suspend(struct pcmcia_device *p_dev); 646static 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 654static int das16cs_pcmcia_attach(struct pcmcia_device *); 655static 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 664struct local_info_t { 665 struct pcmcia_device *link; 666 int stop; 667 struct bus_operations *bus; 668}; 669 670/*====================================================================== 671 672 das16cs_pcmcia_attach() creates an "instance" of the driver, allocating 673 local data structures for one device. The device is registered 674 with Card Services. 675 676 The dev_link structure is initialized, but we don't actually 677 configure the card at this point -- we wait until we receive a 678 card insertion event. 679 680======================================================================*/ 681 682static int das16cs_pcmcia_attach(struct pcmcia_device *link) 683{ 684 struct local_info_t *local; 685 686 dev_dbg(&link->dev, "das16cs_pcmcia_attach()\n"); 687 688 /* Allocate space for private device-specific data */ 689 local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); 690 if (!local) 691 return -ENOMEM; 692 local->link = link; 693 link->priv = local; 694 695 cur_dev = link; 696 697 das16cs_pcmcia_config(link); 698 699 return 0; 700} /* das16cs_pcmcia_attach */ 701 702static void das16cs_pcmcia_detach(struct pcmcia_device *link) 703{ 704 dev_dbg(&link->dev, "das16cs_pcmcia_detach\n"); 705 706 ((struct local_info_t *)link->priv)->stop = 1; 707 das16cs_pcmcia_release(link); 708 /* This points to the parent struct local_info_t struct */ 709 kfree(link->priv); 710} /* das16cs_pcmcia_detach */ 711 712 713static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev, 714 void *priv_data) 715{ 716 if (p_dev->config_index == 0) 717 return -EINVAL; 718 719 return pcmcia_request_io(p_dev); 720} 721 722static void das16cs_pcmcia_config(struct pcmcia_device *link) 723{ 724 int ret; 725 726 dev_dbg(&link->dev, "das16cs_pcmcia_config\n"); 727 728 /* Do we need to allocate an interrupt? */ 729 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; 730 731 ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL); 732 if (ret) { 733 dev_warn(&link->dev, "no configuration found\n"); 734 goto failed; 735 } 736 737 if (!link->irq) 738 goto failed; 739 740 ret = pcmcia_enable_device(link); 741 if (ret) 742 goto failed; 743 744 return; 745 746failed: 747 das16cs_pcmcia_release(link); 748} /* das16cs_pcmcia_config */ 749 750static void das16cs_pcmcia_release(struct pcmcia_device *link) 751{ 752 dev_dbg(&link->dev, "das16cs_pcmcia_release\n"); 753 pcmcia_disable_device(link); 754} /* das16cs_pcmcia_release */ 755 756static int das16cs_pcmcia_suspend(struct pcmcia_device *link) 757{ 758 struct local_info_t *local = link->priv; 759 760 /* Mark the device as stopped, to block IO until later */ 761 local->stop = 1; 762 763 return 0; 764} /* das16cs_pcmcia_suspend */ 765 766static int das16cs_pcmcia_resume(struct pcmcia_device *link) 767{ 768 struct local_info_t *local = link->priv; 769 770 local->stop = 0; 771 return 0; 772} /* das16cs_pcmcia_resume */ 773 774/*====================================================================*/ 775 776static const struct pcmcia_device_id das16cs_id_table[] = { 777 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039), 778 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009), 779 PCMCIA_DEVICE_NULL 780}; 781 782MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table); 783MODULE_AUTHOR("David A. Schleef <ds@schleef.org>"); 784MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16"); 785MODULE_LICENSE("GPL"); 786 787struct pcmcia_driver das16cs_driver = { 788 .probe = das16cs_pcmcia_attach, 789 .remove = das16cs_pcmcia_detach, 790 .suspend = das16cs_pcmcia_suspend, 791 .resume = das16cs_pcmcia_resume, 792 .id_table = das16cs_id_table, 793 .owner = THIS_MODULE, 794 .name = "cb_das16_cs", 795}; 796 797static int __init init_das16cs_pcmcia_cs(void) 798{ 799 pcmcia_register_driver(&das16cs_driver); 800 return 0; 801} 802 803static void __exit exit_das16cs_pcmcia_cs(void) 804{ 805 pr_debug("das16cs_pcmcia_cs: unloading\n"); 806 pcmcia_unregister_driver(&das16cs_driver); 807} 808 809int __init init_module(void) 810{ 811 int ret; 812 813 ret = init_das16cs_pcmcia_cs(); 814 if (ret < 0) 815 return ret; 816 817 return comedi_driver_register(&driver_das16cs); 818} 819 820void __exit cleanup_module(void) 821{ 822 exit_das16cs_pcmcia_cs(); 823 comedi_driver_unregister(&driver_das16cs); 824} 825 826#else 827static int __init driver_das16cs_init_module(void) 828{ 829 return comedi_driver_register(&driver_das16cs); 830} 831 832static void __exit driver_das16cs_cleanup_module(void) 833{ 834 comedi_driver_unregister(&driver_das16cs); 835} 836 837module_init(driver_das16cs_init_module); 838module_exit(driver_das16cs_cleanup_module); 839#endif /* CONFIG_PCMCIA */ 840