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