cb_das16_cs.c revision cc780e8f92e1576e4ac867e5d26d22ffbc39ddd8
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 dev_dbg(dev->hw_dev, "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 dev_dbg(dev->hw_dev, "comedi%d: cb_das16_cs: attached\n", dev->minor); 167 168 link = cur_dev; /* XXX hack */ 169 if (!link) 170 return -EIO; 171 172 dev->iobase = link->resource[0]->start; 173 dev_dbg(dev->hw_dev, "I/O base=0x%04lx\n", dev->iobase); 174 175 dev_dbg(dev->hw_dev, "fingerprint:\n"); 176 for (i = 0; i < 48; i += 2) 177 dev_dbg(dev->hw_dev, "%04x\n", inw(dev->iobase + i)); 178 179 180 ret = request_irq(link->irq, das16cs_interrupt, 181 IRQF_SHARED, "cb_das16_cs", dev); 182 if (ret < 0) 183 return ret; 184 185 dev->irq = link->irq; 186 187 dev_dbg(dev->hw_dev, "irq=%u\n", dev->irq); 188 189 dev->board_ptr = das16cs_probe(dev, link); 190 if (!dev->board_ptr) 191 return -EIO; 192 193 dev->board_name = thisboard->name; 194 195 if (alloc_private(dev, sizeof(struct das16cs_private)) < 0) 196 return -ENOMEM; 197 198 if (alloc_subdevices(dev, 4) < 0) 199 return -ENOMEM; 200 201 s = dev->subdevices + 0; 202 dev->read_subdev = s; 203 /* analog input subdevice */ 204 s->type = COMEDI_SUBD_AI; 205 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; 206 s->n_chan = 16; 207 s->maxdata = 0xffff; 208 s->range_table = &das16cs_ai_range; 209 s->len_chanlist = 16; 210 s->insn_read = das16cs_ai_rinsn; 211 s->do_cmd = das16cs_ai_cmd; 212 s->do_cmdtest = das16cs_ai_cmdtest; 213 214 s = dev->subdevices + 1; 215 /* analog output subdevice */ 216 if (thisboard->n_ao_chans) { 217 s->type = COMEDI_SUBD_AO; 218 s->subdev_flags = SDF_WRITABLE; 219 s->n_chan = thisboard->n_ao_chans; 220 s->maxdata = 0xffff; 221 s->range_table = &range_bipolar10; 222 s->insn_write = &das16cs_ao_winsn; 223 s->insn_read = &das16cs_ao_rinsn; 224 } 225 226 s = dev->subdevices + 2; 227 /* digital i/o subdevice */ 228 if (1) { 229 s->type = COMEDI_SUBD_DIO; 230 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 231 s->n_chan = 8; 232 s->maxdata = 1; 233 s->range_table = &range_digital; 234 s->insn_bits = das16cs_dio_insn_bits; 235 s->insn_config = das16cs_dio_insn_config; 236 } else { 237 s->type = COMEDI_SUBD_UNUSED; 238 } 239 240 s = dev->subdevices + 3; 241 /* timer subdevice */ 242 if (0) { 243 s->type = COMEDI_SUBD_TIMER; 244 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 245 s->n_chan = 1; 246 s->maxdata = 0xff; 247 s->range_table = &range_unknown; 248 s->insn_read = das16cs_timer_insn_read; 249 s->insn_config = das16cs_timer_insn_config; 250 } else { 251 s->type = COMEDI_SUBD_UNUSED; 252 } 253 254 255 return 1; 256} 257 258static int das16cs_detach(struct comedi_device *dev) 259{ 260 dev_dbg(dev->hw_dev, "comedi%d: das16cs: remove\n", dev->minor); 261 262 if (dev->irq) 263 free_irq(dev->irq, dev); 264 265 266 return 0; 267} 268 269static irqreturn_t das16cs_interrupt(int irq, void *d) 270{ 271 /* struct comedi_device *dev = d; */ 272 return IRQ_HANDLED; 273} 274 275/* 276 * "instructions" read/write data in "one-shot" or "software-triggered" 277 * mode. 278 */ 279static int das16cs_ai_rinsn(struct comedi_device *dev, 280 struct comedi_subdevice *s, 281 struct comedi_insn *insn, unsigned int *data) 282{ 283 int i; 284 int to; 285 int aref; 286 int range; 287 int chan; 288 static int range_bits[] = { 0x800, 0x000, 0x100, 0x200 }; 289 290 chan = CR_CHAN(insn->chanspec); 291 aref = CR_AREF(insn->chanspec); 292 range = CR_RANGE(insn->chanspec); 293 294 outw(chan, dev->iobase + 2); 295 296 devpriv->status1 &= ~0xf320; 297 devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020; 298 outw(devpriv->status1, dev->iobase + 4); 299 300 devpriv->status2 &= ~0xff00; 301 devpriv->status2 |= range_bits[range]; 302 outw(devpriv->status2, dev->iobase + 6); 303 304 for (i = 0; i < insn->n; i++) { 305 outw(0, dev->iobase); 306 307#define TIMEOUT 1000 308 for (to = 0; to < TIMEOUT; to++) { 309 if (inw(dev->iobase + 4) & 0x0080) 310 break; 311 } 312 if (to == TIMEOUT) { 313 dev_dbg(dev->hw_dev, "cb_das16_cs: ai timeout\n"); 314 return -ETIME; 315 } 316 data[i] = (unsigned short)inw(dev->iobase + 0); 317 } 318 319 return i; 320} 321 322static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 323{ 324 return -EINVAL; 325} 326 327static int das16cs_ai_cmdtest(struct comedi_device *dev, 328 struct comedi_subdevice *s, 329 struct comedi_cmd *cmd) 330{ 331 int err = 0; 332 int tmp; 333 334 /* cmdtest tests a particular command to see if it is valid. 335 * Using the cmdtest ioctl, a user can create a valid cmd 336 * and then have it executes by the cmd ioctl. 337 * 338 * cmdtest returns 1,2,3,4 or 0, depending on which tests 339 * the command passes. */ 340 341 /* step 1: make sure trigger sources are trivially valid */ 342 343 tmp = cmd->start_src; 344 cmd->start_src &= TRIG_NOW; 345 if (!cmd->start_src || tmp != cmd->start_src) 346 err++; 347 348 tmp = cmd->scan_begin_src; 349 cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; 350 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 351 err++; 352 353 tmp = cmd->convert_src; 354 cmd->convert_src &= TRIG_TIMER | TRIG_EXT; 355 if (!cmd->convert_src || tmp != cmd->convert_src) 356 err++; 357 358 tmp = cmd->scan_end_src; 359 cmd->scan_end_src &= TRIG_COUNT; 360 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 361 err++; 362 363 tmp = cmd->stop_src; 364 cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 365 if (!cmd->stop_src || tmp != cmd->stop_src) 366 err++; 367 368 if (err) 369 return 1; 370 371 /* step 2: make sure trigger sources are unique and 372 * mutually compatible */ 373 374 /* note that mutual compatibility is not an issue here */ 375 if (cmd->scan_begin_src != TRIG_TIMER && 376 cmd->scan_begin_src != TRIG_EXT) 377 err++; 378 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) 379 err++; 380 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) 381 err++; 382 383 if (err) 384 return 2; 385 386 /* step 3: make sure arguments are trivially compatible */ 387 388 if (cmd->start_arg != 0) { 389 cmd->start_arg = 0; 390 err++; 391 } 392#define MAX_SPEED 10000 /* in nanoseconds */ 393#define MIN_SPEED 1000000000 /* in nanoseconds */ 394 395 if (cmd->scan_begin_src == TRIG_TIMER) { 396 if (cmd->scan_begin_arg < MAX_SPEED) { 397 cmd->scan_begin_arg = MAX_SPEED; 398 err++; 399 } 400 if (cmd->scan_begin_arg > MIN_SPEED) { 401 cmd->scan_begin_arg = MIN_SPEED; 402 err++; 403 } 404 } else { 405 /* external trigger */ 406 /* should be level/edge, hi/lo specification here */ 407 /* should specify multiple external triggers */ 408 if (cmd->scan_begin_arg > 9) { 409 cmd->scan_begin_arg = 9; 410 err++; 411 } 412 } 413 if (cmd->convert_src == TRIG_TIMER) { 414 if (cmd->convert_arg < MAX_SPEED) { 415 cmd->convert_arg = MAX_SPEED; 416 err++; 417 } 418 if (cmd->convert_arg > MIN_SPEED) { 419 cmd->convert_arg = MIN_SPEED; 420 err++; 421 } 422 } else { 423 /* external trigger */ 424 /* see above */ 425 if (cmd->convert_arg > 9) { 426 cmd->convert_arg = 9; 427 err++; 428 } 429 } 430 431 if (cmd->scan_end_arg != cmd->chanlist_len) { 432 cmd->scan_end_arg = cmd->chanlist_len; 433 err++; 434 } 435 if (cmd->stop_src == TRIG_COUNT) { 436 if (cmd->stop_arg > 0x00ffffff) { 437 cmd->stop_arg = 0x00ffffff; 438 err++; 439 } 440 } else { 441 /* TRIG_NONE */ 442 if (cmd->stop_arg != 0) { 443 cmd->stop_arg = 0; 444 err++; 445 } 446 } 447 448 if (err) 449 return 3; 450 451 /* step 4: fix up any arguments */ 452 453 if (cmd->scan_begin_src == TRIG_TIMER) { 454 unsigned int div1 = 0, div2 = 0; 455 456 tmp = cmd->scan_begin_arg; 457 i8253_cascade_ns_to_timer(100, &div1, &div2, 458 &cmd->scan_begin_arg, 459 cmd->flags & TRIG_ROUND_MASK); 460 if (tmp != cmd->scan_begin_arg) 461 err++; 462 } 463 if (cmd->convert_src == TRIG_TIMER) { 464 unsigned int div1 = 0, div2 = 0; 465 466 tmp = cmd->convert_arg; 467 i8253_cascade_ns_to_timer(100, &div1, &div2, 468 &cmd->scan_begin_arg, 469 cmd->flags & TRIG_ROUND_MASK); 470 if (tmp != cmd->convert_arg) 471 err++; 472 if (cmd->scan_begin_src == TRIG_TIMER && 473 cmd->scan_begin_arg < 474 cmd->convert_arg * cmd->scan_end_arg) { 475 cmd->scan_begin_arg = 476 cmd->convert_arg * cmd->scan_end_arg; 477 err++; 478 } 479 } 480 481 if (err) 482 return 4; 483 484 return 0; 485} 486 487static int das16cs_ao_winsn(struct comedi_device *dev, 488 struct comedi_subdevice *s, 489 struct comedi_insn *insn, unsigned int *data) 490{ 491 int i; 492 int chan = CR_CHAN(insn->chanspec); 493 unsigned short status1; 494 unsigned short d; 495 int bit; 496 497 for (i = 0; i < insn->n; i++) { 498 devpriv->ao_readback[chan] = data[i]; 499 d = data[i]; 500 501 outw(devpriv->status1, dev->iobase + 4); 502 udelay(1); 503 504 status1 = devpriv->status1 & ~0xf; 505 if (chan) 506 status1 |= 0x0001; 507 else 508 status1 |= 0x0008; 509 510/* printk("0x%04x\n",status1);*/ 511 outw(status1, dev->iobase + 4); 512 udelay(1); 513 514 for (bit = 15; bit >= 0; bit--) { 515 int b = (d >> bit) & 0x1; 516 b <<= 1; 517/* printk("0x%04x\n",status1 | b | 0x0000);*/ 518 outw(status1 | b | 0x0000, dev->iobase + 4); 519 udelay(1); 520/* printk("0x%04x\n",status1 | b | 0x0004);*/ 521 outw(status1 | b | 0x0004, dev->iobase + 4); 522 udelay(1); 523 } 524/* make high both DAC0CS and DAC1CS to load 525 new data and update analog output*/ 526 outw(status1 | 0x9, dev->iobase + 4); 527 } 528 529 return i; 530} 531 532/* AO subdevices should have a read insn as well as a write insn. 533 * Usually this means copying a value stored in devpriv. */ 534static int das16cs_ao_rinsn(struct comedi_device *dev, 535 struct comedi_subdevice *s, 536 struct comedi_insn *insn, unsigned int *data) 537{ 538 int i; 539 int chan = CR_CHAN(insn->chanspec); 540 541 for (i = 0; i < insn->n; i++) 542 data[i] = devpriv->ao_readback[chan]; 543 544 return i; 545} 546 547/* DIO devices are slightly special. Although it is possible to 548 * implement the insn_read/insn_write interface, it is much more 549 * useful to applications if you implement the insn_bits interface. 550 * This allows packed reading/writing of the DIO channels. The 551 * comedi core can convert between insn_bits and insn_read/write */ 552static int das16cs_dio_insn_bits(struct comedi_device *dev, 553 struct comedi_subdevice *s, 554 struct comedi_insn *insn, unsigned int *data) 555{ 556 if (insn->n != 2) 557 return -EINVAL; 558 559 if (data[0]) { 560 s->state &= ~data[0]; 561 s->state |= data[0] & data[1]; 562 563 outw(s->state, dev->iobase + 16); 564 } 565 566 /* on return, data[1] contains the value of the digital 567 * input and output lines. */ 568 data[1] = inw(dev->iobase + 16); 569 570 return 2; 571} 572 573static int das16cs_dio_insn_config(struct comedi_device *dev, 574 struct comedi_subdevice *s, 575 struct comedi_insn *insn, unsigned int *data) 576{ 577 int chan = CR_CHAN(insn->chanspec); 578 int bits; 579 580 if (chan < 4) 581 bits = 0x0f; 582 else 583 bits = 0xf0; 584 585 switch (data[0]) { 586 case INSN_CONFIG_DIO_OUTPUT: 587 s->io_bits |= bits; 588 break; 589 case INSN_CONFIG_DIO_INPUT: 590 s->io_bits &= bits; 591 break; 592 case INSN_CONFIG_DIO_QUERY: 593 data[1] = 594 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; 595 return insn->n; 596 break; 597 default: 598 return -EINVAL; 599 break; 600 } 601 602 devpriv->status2 &= ~0x00c0; 603 devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0; 604 devpriv->status2 |= (s->io_bits & 0x0f) ? 0x0040 : 0; 605 606 outw(devpriv->status2, dev->iobase + 6); 607 608 return insn->n; 609} 610 611static int das16cs_timer_insn_read(struct comedi_device *dev, 612 struct comedi_subdevice *s, 613 struct comedi_insn *insn, unsigned int *data) 614{ 615 return -EINVAL; 616} 617 618static int das16cs_timer_insn_config(struct comedi_device *dev, 619 struct comedi_subdevice *s, 620 struct comedi_insn *insn, 621 unsigned int *data) 622{ 623 return -EINVAL; 624} 625 626/* PCMCIA stuff */ 627 628/*====================================================================== 629 630 The following pcmcia code for the pcm-das08 is adapted from the 631 dummy_cs.c driver of the Linux PCMCIA Card Services package. 632 633 The initial developer of the original code is David A. Hinds 634 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds 635 are Copyright (C) 1999 David A. Hinds. All Rights Reserved. 636 637======================================================================*/ 638 639#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE) 640 641static void das16cs_pcmcia_config(struct pcmcia_device *link); 642static void das16cs_pcmcia_release(struct pcmcia_device *link); 643static int das16cs_pcmcia_suspend(struct pcmcia_device *p_dev); 644static int das16cs_pcmcia_resume(struct pcmcia_device *p_dev); 645 646/* 647 The attach() and detach() entry points are used to create and destroy 648 "instances" of the driver, where each instance represents everything 649 needed to manage one actual PCMCIA card. 650*/ 651 652static int das16cs_pcmcia_attach(struct pcmcia_device *); 653static void das16cs_pcmcia_detach(struct pcmcia_device *); 654 655/* 656 You'll also need to prototype all the functions that will actually 657 be used to talk to your device. See 'memory_cs' for a good example 658 of a fully self-sufficient driver; the other drivers rely more or 659 less on other parts of the kernel. 660*/ 661 662struct local_info_t { 663 struct pcmcia_device *link; 664 int stop; 665 struct bus_operations *bus; 666}; 667 668/*====================================================================== 669 670 das16cs_pcmcia_attach() creates an "instance" of the driver, allocating 671 local data structures for one device. The device is registered 672 with Card Services. 673 674 The dev_link structure is initialized, but we don't actually 675 configure the card at this point -- we wait until we receive a 676 card insertion event. 677 678======================================================================*/ 679 680static int das16cs_pcmcia_attach(struct pcmcia_device *link) 681{ 682 struct local_info_t *local; 683 684 dev_dbg(&link->dev, "das16cs_pcmcia_attach()\n"); 685 686 /* Allocate space for private device-specific data */ 687 local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); 688 if (!local) 689 return -ENOMEM; 690 local->link = link; 691 link->priv = local; 692 693 cur_dev = link; 694 695 das16cs_pcmcia_config(link); 696 697 return 0; 698} /* das16cs_pcmcia_attach */ 699 700static void das16cs_pcmcia_detach(struct pcmcia_device *link) 701{ 702 dev_dbg(&link->dev, "das16cs_pcmcia_detach\n"); 703 704 ((struct local_info_t *)link->priv)->stop = 1; 705 das16cs_pcmcia_release(link); 706 /* This points to the parent struct local_info_t struct */ 707 kfree(link->priv); 708} /* das16cs_pcmcia_detach */ 709 710 711static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev, 712 void *priv_data) 713{ 714 if (p_dev->config_index == 0) 715 return -EINVAL; 716 717 return pcmcia_request_io(p_dev); 718} 719 720static void das16cs_pcmcia_config(struct pcmcia_device *link) 721{ 722 int ret; 723 724 dev_dbg(&link->dev, "das16cs_pcmcia_config\n"); 725 726 /* Do we need to allocate an interrupt? */ 727 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; 728 729 ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL); 730 if (ret) { 731 dev_warn(&link->dev, "no configuration found\n"); 732 goto failed; 733 } 734 735 if (!link->irq) 736 goto failed; 737 738 ret = pcmcia_enable_device(link); 739 if (ret) 740 goto failed; 741 742 return; 743 744failed: 745 das16cs_pcmcia_release(link); 746} /* das16cs_pcmcia_config */ 747 748static void das16cs_pcmcia_release(struct pcmcia_device *link) 749{ 750 dev_dbg(&link->dev, "das16cs_pcmcia_release\n"); 751 pcmcia_disable_device(link); 752} /* das16cs_pcmcia_release */ 753 754static int das16cs_pcmcia_suspend(struct pcmcia_device *link) 755{ 756 struct local_info_t *local = link->priv; 757 758 /* Mark the device as stopped, to block IO until later */ 759 local->stop = 1; 760 761 return 0; 762} /* das16cs_pcmcia_suspend */ 763 764static int das16cs_pcmcia_resume(struct pcmcia_device *link) 765{ 766 struct local_info_t *local = link->priv; 767 768 local->stop = 0; 769 return 0; 770} /* das16cs_pcmcia_resume */ 771 772/*====================================================================*/ 773 774static const struct pcmcia_device_id das16cs_id_table[] = { 775 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039), 776 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009), 777 PCMCIA_DEVICE_NULL 778}; 779 780MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table); 781MODULE_AUTHOR("David A. Schleef <ds@schleef.org>"); 782MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16"); 783MODULE_LICENSE("GPL"); 784 785struct pcmcia_driver das16cs_driver = { 786 .probe = das16cs_pcmcia_attach, 787 .remove = das16cs_pcmcia_detach, 788 .suspend = das16cs_pcmcia_suspend, 789 .resume = das16cs_pcmcia_resume, 790 .id_table = das16cs_id_table, 791 .owner = THIS_MODULE, 792 .name = "cb_das16_cs", 793}; 794 795static int __init init_das16cs_pcmcia_cs(void) 796{ 797 pcmcia_register_driver(&das16cs_driver); 798 return 0; 799} 800 801static void __exit exit_das16cs_pcmcia_cs(void) 802{ 803 pr_debug("das16cs_pcmcia_cs: unloading\n"); 804 pcmcia_unregister_driver(&das16cs_driver); 805} 806 807int __init init_module(void) 808{ 809 int ret; 810 811 ret = init_das16cs_pcmcia_cs(); 812 if (ret < 0) 813 return ret; 814 815 return comedi_driver_register(&driver_das16cs); 816} 817 818void __exit cleanup_module(void) 819{ 820 exit_das16cs_pcmcia_cs(); 821 comedi_driver_unregister(&driver_das16cs); 822} 823 824#else 825static int __init driver_das16cs_init_module(void) 826{ 827 return comedi_driver_register(&driver_das16cs); 828} 829 830static void __exit driver_das16cs_cleanup_module(void) 831{ 832 comedi_driver_unregister(&driver_das16cs); 833} 834 835module_init(driver_das16cs_init_module); 836module_exit(driver_das16cs_cleanup_module); 837#endif /* CONFIG_PCMCIA */ 838