cb_das16_cs.c revision 5a0e3ad6af8660be21ca98a971cd00f331318c05
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.AssignedIRQ, das16cs_interrupt, 184 IRQF_SHARED, "cb_das16_cs", dev); 185 if (ret < 0) { 186 return ret; 187 } 188 dev->irq = link->irq.AssignedIRQ; 189 printk("irq=%u ", dev->irq); 190 191 dev->board_ptr = das16cs_probe(dev, link); 192 if (!dev->board_ptr) 193 return -EIO; 194 195 dev->board_name = thisboard->name; 196 197 if (alloc_private(dev, sizeof(struct das16cs_private)) < 0) 198 return -ENOMEM; 199 200 if (alloc_subdevices(dev, 4) < 0) 201 return -ENOMEM; 202 203 s = dev->subdevices + 0; 204 dev->read_subdev = s; 205 /* analog input subdevice */ 206 s->type = COMEDI_SUBD_AI; 207 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; 208 s->n_chan = 16; 209 s->maxdata = 0xffff; 210 s->range_table = &das16cs_ai_range; 211 s->len_chanlist = 16; 212 s->insn_read = das16cs_ai_rinsn; 213 s->do_cmd = das16cs_ai_cmd; 214 s->do_cmdtest = das16cs_ai_cmdtest; 215 216 s = dev->subdevices + 1; 217 /* analog output subdevice */ 218 if (thisboard->n_ao_chans) { 219 s->type = COMEDI_SUBD_AO; 220 s->subdev_flags = SDF_WRITABLE; 221 s->n_chan = thisboard->n_ao_chans; 222 s->maxdata = 0xffff; 223 s->range_table = &range_bipolar10; 224 s->insn_write = &das16cs_ao_winsn; 225 s->insn_read = &das16cs_ao_rinsn; 226 } 227 228 s = dev->subdevices + 2; 229 /* digital i/o subdevice */ 230 if (1) { 231 s->type = COMEDI_SUBD_DIO; 232 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 233 s->n_chan = 8; 234 s->maxdata = 1; 235 s->range_table = &range_digital; 236 s->insn_bits = das16cs_dio_insn_bits; 237 s->insn_config = das16cs_dio_insn_config; 238 } else { 239 s->type = COMEDI_SUBD_UNUSED; 240 } 241 242 s = dev->subdevices + 3; 243 /* timer subdevice */ 244 if (0) { 245 s->type = COMEDI_SUBD_TIMER; 246 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 247 s->n_chan = 1; 248 s->maxdata = 0xff; 249 s->range_table = &range_unknown; 250 s->insn_read = das16cs_timer_insn_read; 251 s->insn_config = das16cs_timer_insn_config; 252 } else { 253 s->type = COMEDI_SUBD_UNUSED; 254 } 255 256 printk("attached\n"); 257 258 return 1; 259} 260 261static int das16cs_detach(struct comedi_device *dev) 262{ 263 printk("comedi%d: das16cs: remove\n", dev->minor); 264 265 if (dev->irq) { 266 free_irq(dev->irq, dev); 267 } 268 269 return 0; 270} 271 272static irqreturn_t das16cs_interrupt(int irq, void *d) 273{ 274 /* struct comedi_device *dev = d; */ 275 return IRQ_HANDLED; 276} 277 278/* 279 * "instructions" read/write data in "one-shot" or "software-triggered" 280 * mode. 281 */ 282static int das16cs_ai_rinsn(struct comedi_device *dev, 283 struct comedi_subdevice *s, 284 struct comedi_insn *insn, unsigned int *data) 285{ 286 int i; 287 int to; 288 int aref; 289 int range; 290 int chan; 291 static int range_bits[] = { 0x800, 0x000, 0x100, 0x200 }; 292 293 chan = CR_CHAN(insn->chanspec); 294 aref = CR_AREF(insn->chanspec); 295 range = CR_RANGE(insn->chanspec); 296 297 outw(chan, dev->iobase + 2); 298 299 devpriv->status1 &= ~0xf320; 300 devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020; 301 outw(devpriv->status1, dev->iobase + 4); 302 303 devpriv->status2 &= ~0xff00; 304 devpriv->status2 |= range_bits[range]; 305 outw(devpriv->status2, dev->iobase + 6); 306 307 for (i = 0; i < insn->n; i++) { 308 outw(0, dev->iobase); 309 310#define TIMEOUT 1000 311 for (to = 0; to < TIMEOUT; to++) { 312 if (inw(dev->iobase + 4) & 0x0080) 313 break; 314 } 315 if (to == TIMEOUT) { 316 printk("cb_das16_cs: ai timeout\n"); 317 return -ETIME; 318 } 319 data[i] = (unsigned short)inw(dev->iobase + 0); 320 } 321 322 return i; 323} 324 325static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 326{ 327 return -EINVAL; 328} 329 330static int das16cs_ai_cmdtest(struct comedi_device *dev, 331 struct comedi_subdevice *s, 332 struct comedi_cmd *cmd) 333{ 334 int err = 0; 335 int tmp; 336 337 /* cmdtest tests a particular command to see if it is valid. 338 * Using the cmdtest ioctl, a user can create a valid cmd 339 * and then have it executes by the cmd ioctl. 340 * 341 * cmdtest returns 1,2,3,4 or 0, depending on which tests 342 * the command passes. */ 343 344 /* step 1: make sure trigger sources are trivially valid */ 345 346 tmp = cmd->start_src; 347 cmd->start_src &= TRIG_NOW; 348 if (!cmd->start_src || tmp != cmd->start_src) 349 err++; 350 351 tmp = cmd->scan_begin_src; 352 cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; 353 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 354 err++; 355 356 tmp = cmd->convert_src; 357 cmd->convert_src &= TRIG_TIMER | TRIG_EXT; 358 if (!cmd->convert_src || tmp != cmd->convert_src) 359 err++; 360 361 tmp = cmd->scan_end_src; 362 cmd->scan_end_src &= TRIG_COUNT; 363 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 364 err++; 365 366 tmp = cmd->stop_src; 367 cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 368 if (!cmd->stop_src || tmp != cmd->stop_src) 369 err++; 370 371 if (err) 372 return 1; 373 374 /* step 2: make sure trigger sources are unique and 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 664/* 665 The dev_info variable is the "key" that is used to match up this 666 device driver with appropriate cards, through the card configuration 667 database. 668*/ 669 670static dev_info_t dev_info = "cb_das16_cs"; 671 672struct local_info_t { 673 struct pcmcia_device *link; 674 dev_node_t node; 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 /* Interrupt setup */ 706 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; 707 link->irq.Handler = NULL; 708 709 link->conf.Attributes = 0; 710 link->conf.IntType = INT_MEMORY_AND_IO; 711 712 cur_dev = link; 713 714 das16cs_pcmcia_config(link); 715 716 return 0; 717} /* das16cs_pcmcia_attach */ 718 719static void das16cs_pcmcia_detach(struct pcmcia_device *link) 720{ 721 dev_dbg(&link->dev, "das16cs_pcmcia_detach\n"); 722 723 if (link->dev_node) { 724 ((struct local_info_t *)link->priv)->stop = 1; 725 das16cs_pcmcia_release(link); 726 } 727 /* This points to the parent struct local_info_t struct */ 728 if (link->priv) 729 kfree(link->priv); 730} /* das16cs_pcmcia_detach */ 731 732 733static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev, 734 cistpl_cftable_entry_t *cfg, 735 cistpl_cftable_entry_t *dflt, 736 unsigned int vcc, 737 void *priv_data) 738{ 739 if (cfg->index == 0) 740 return -EINVAL; 741 742 /* Do we need to allocate an interrupt? */ 743 if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) 744 p_dev->conf.Attributes |= CONF_ENABLE_IRQ; 745 746 /* IO window settings */ 747 p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; 748 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { 749 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; 750 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; 751 if (!(io->flags & CISTPL_IO_8BIT)) 752 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; 753 if (!(io->flags & CISTPL_IO_16BIT)) 754 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; 755 p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; 756 p_dev->io.BasePort1 = io->win[0].base; 757 p_dev->io.NumPorts1 = io->win[0].len; 758 if (io->nwin > 1) { 759 p_dev->io.Attributes2 = p_dev->io.Attributes1; 760 p_dev->io.BasePort2 = io->win[1].base; 761 p_dev->io.NumPorts2 = io->win[1].len; 762 } 763 /* This reserves IO space but doesn't actually enable it */ 764 return pcmcia_request_io(p_dev, &p_dev->io); 765 } 766 767 return 0; 768} 769 770static void das16cs_pcmcia_config(struct pcmcia_device *link) 771{ 772 struct local_info_t *dev = link->priv; 773 int ret; 774 775 dev_dbg(&link->dev, "das16cs_pcmcia_config\n"); 776 777 ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL); 778 if (ret) { 779 dev_warn(&link->dev, "no configuration found\n"); 780 goto failed; 781 } 782 783 /* 784 Allocate an interrupt line. Note that this does not assign a 785 handler to the interrupt, unless the 'Handler' member of the 786 irq structure is initialized. 787 */ 788 if (link->conf.Attributes & CONF_ENABLE_IRQ) { 789 ret = pcmcia_request_irq(link, &link->irq); 790 if (ret) 791 goto failed; 792 } 793 /* 794 This actually configures the PCMCIA socket -- setting up 795 the I/O windows and the interrupt mapping, and putting the 796 card and host interface into "Memory and IO" mode. 797 */ 798 ret = pcmcia_request_configuration(link, &link->conf); 799 if (ret) 800 goto failed; 801 802 /* 803 At this point, the dev_node_t structure(s) need to be 804 initialized and arranged in a linked list at link->dev. 805 */ 806 sprintf(dev->node.dev_name, "cb_das16_cs"); 807 dev->node.major = dev->node.minor = 0; 808 link->dev_node = &dev->node; 809 810 /* Finally, report what we've done */ 811 printk(KERN_INFO "%s: index 0x%02x", 812 dev->node.dev_name, link->conf.ConfigIndex); 813 if (link->conf.Attributes & CONF_ENABLE_IRQ) 814 printk(", irq %u", link->irq.AssignedIRQ); 815 if (link->io.NumPorts1) 816 printk(", io 0x%04x-0x%04x", link->io.BasePort1, 817 link->io.BasePort1 + link->io.NumPorts1 - 1); 818 if (link->io.NumPorts2) 819 printk(" & 0x%04x-0x%04x", link->io.BasePort2, 820 link->io.BasePort2 + link->io.NumPorts2 - 1); 821 printk("\n"); 822 823 return; 824 825failed: 826 das16cs_pcmcia_release(link); 827} /* das16cs_pcmcia_config */ 828 829static void das16cs_pcmcia_release(struct pcmcia_device *link) 830{ 831 dev_dbg(&link->dev, "das16cs_pcmcia_release\n"); 832 pcmcia_disable_device(link); 833} /* das16cs_pcmcia_release */ 834 835static int das16cs_pcmcia_suspend(struct pcmcia_device *link) 836{ 837 struct local_info_t *local = link->priv; 838 839 /* Mark the device as stopped, to block IO until later */ 840 local->stop = 1; 841 842 return 0; 843} /* das16cs_pcmcia_suspend */ 844 845static int das16cs_pcmcia_resume(struct pcmcia_device *link) 846{ 847 struct local_info_t *local = link->priv; 848 849 local->stop = 0; 850 return 0; 851} /* das16cs_pcmcia_resume */ 852 853/*====================================================================*/ 854 855static struct pcmcia_device_id das16cs_id_table[] = { 856 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039), 857 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009), 858 PCMCIA_DEVICE_NULL 859}; 860 861MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table); 862 863struct pcmcia_driver das16cs_driver = { 864 .probe = das16cs_pcmcia_attach, 865 .remove = das16cs_pcmcia_detach, 866 .suspend = das16cs_pcmcia_suspend, 867 .resume = das16cs_pcmcia_resume, 868 .id_table = das16cs_id_table, 869 .owner = THIS_MODULE, 870 .drv = { 871 .name = dev_info, 872 }, 873}; 874 875static int __init init_das16cs_pcmcia_cs(void) 876{ 877 pcmcia_register_driver(&das16cs_driver); 878 return 0; 879} 880 881static void __exit exit_das16cs_pcmcia_cs(void) 882{ 883 pr_debug("das16cs_pcmcia_cs: unloading\n"); 884 pcmcia_unregister_driver(&das16cs_driver); 885} 886 887int __init init_module(void) 888{ 889 int ret; 890 891 ret = init_das16cs_pcmcia_cs(); 892 if (ret < 0) 893 return ret; 894 895 return comedi_driver_register(&driver_das16cs); 896} 897 898void __exit cleanup_module(void) 899{ 900 exit_das16cs_pcmcia_cs(); 901 comedi_driver_unregister(&driver_das16cs); 902} 903 904#else 905COMEDI_INITCLEANUP(driver_das16cs); 906#endif /* CONFIG_PCMCIA */ 907