pcmmio.c revision 4b2ba24399cfcd7c80a20cd3bbedc5df0ebd4345
1/* 2 comedi/drivers/pcmmio.c 3 Driver for Winsystems PC-104 based multifunction IO board. 4 5 COMEDI - Linux Control and Measurement Device Interface 6 Copyright (C) 2007 Calin A. Culianu <calin@ajvar.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/* 23Driver: pcmmio 24Description: A driver for the PCM-MIO multifunction board 25Devices: [Winsystems] PCM-MIO (pcmmio) 26Author: Calin Culianu <calin@ajvar.org> 27Updated: Wed, May 16 2007 16:21:10 -0500 28Status: works 29 30A driver for the relatively new PCM-MIO multifunction board from 31Winsystems. This board is a PC-104 based I/O board. It contains 32four subdevices: 33 subdevice 0 - 16 channels of 16-bit AI 34 subdevice 1 - 8 channels of 16-bit AO 35 subdevice 2 - first 24 channels of the 48 channel of DIO 36 (with edge-triggered interrupt support) 37 subdevice 3 - last 24 channels of the 48 channel DIO 38 (no interrupt support for this bank of channels) 39 40 Some notes: 41 42 Synchronous reads and writes are the only things implemented for AI and AO, 43 even though the hardware itself can do streaming acquisition, etc. Anyone 44 want to add asynchronous I/O for AI/AO as a feature? Be my guest... 45 46 Asynchronous I/O for the DIO subdevices *is* implemented, however! They are 47 basically edge-triggered interrupts for any configuration of the first 48 24 DIO-lines. 49 50 Also note that this interrupt support is untested. 51 52 A few words about edge-detection IRQ support (commands on DIO): 53 54 * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ 55 of the board to the comedi_config command. The board IRQ is not jumpered 56 but rather configured through software, so any IRQ from 1-15 is OK. 57 58 * Due to the genericity of the comedi API, you need to create a special 59 comedi_command in order to use edge-triggered interrupts for DIO. 60 61 * Use comedi_commands with TRIG_NOW. Your callback will be called each 62 time an edge is detected on the specified DIO line(s), and the data 63 values will be two sample_t's, which should be concatenated to form 64 one 32-bit unsigned int. This value is the mask of channels that had 65 edges detected from your channel list. Note that the bits positions 66 in the mask correspond to positions in your chanlist when you 67 specified the command and *not* channel id's! 68 69 * To set the polarity of the edge-detection interrupts pass a nonzero value 70 for either CR_RANGE or CR_AREF for edge-up polarity, or a zero 71 value for both CR_RANGE and CR_AREF if you want edge-down polarity. 72 73Configuration Options: 74 [0] - I/O port base address 75 [1] - IRQ (optional -- for edge-detect interrupt support only, 76 leave out if you don't need this feature) 77*/ 78 79#include <linux/interrupt.h> 80#include "../comedidev.h" 81#include "pcm_common.h" 82#include <linux/pci.h> /* for PCI devices */ 83 84/* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */ 85#define CHANS_PER_PORT 8 86#define PORTS_PER_ASIC 6 87#define INTR_PORTS_PER_ASIC 3 88#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */ 89#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT) 90#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC) 91#define INTR_CHANS_PER_ASIC 24 92#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT) 93#define MAX_DIO_CHANS (PORTS_PER_ASIC*1*CHANS_PER_PORT) 94#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC) 95#define SDEV_NO ((int)(s - dev->subdevices)) 96#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/) 97/* IO Memory sizes */ 98#define ASIC_IOSIZE (0x0B) 99#define PCMMIO48_IOSIZE ASIC_IOSIZE 100 101/* Some offsets - these are all in the 16byte IO memory offset from 102 the base address. Note that there is a paging scheme to swap out 103 offsets 0x8-0xA using the PAGELOCK register. See the table below. 104 105 Register(s) Pages R/W? Description 106 -------------------------------------------------------------- 107 REG_PORTx All R/W Read/Write/Configure IO 108 REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int. 109 REG_PAGELOCK All WriteOnly Select a page 110 REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity 111 REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int. 112 REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints. 113 */ 114#define REG_PORT0 0x0 115#define REG_PORT1 0x1 116#define REG_PORT2 0x2 117#define REG_PORT3 0x3 118#define REG_PORT4 0x4 119#define REG_PORT5 0x5 120#define REG_INT_PENDING 0x6 121#define REG_PAGELOCK 0x7 /* 122 * page selector register, upper 2 bits select 123 * a page and bits 0-5 are used to 'lock down' 124 * a particular port above to make it readonly. 125 */ 126#define REG_POL0 0x8 127#define REG_POL1 0x9 128#define REG_POL2 0xA 129#define REG_ENAB0 0x8 130#define REG_ENAB1 0x9 131#define REG_ENAB2 0xA 132#define REG_INT_ID0 0x8 133#define REG_INT_ID1 0x9 134#define REG_INT_ID2 0xA 135 136#define NUM_PAGED_REGS 3 137#define NUM_PAGES 4 138#define FIRST_PAGED_REG 0x8 139#define REG_PAGE_BITOFFSET 6 140#define REG_LOCK_BITOFFSET 0 141#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1)) 142#define REG_LOCK_MASK (~(REG_PAGE_MASK)) 143#define PAGE_POL 1 144#define PAGE_ENAB 2 145#define PAGE_INT_ID 3 146 147typedef int (*comedi_insn_fn_t) (struct comedi_device *, 148 struct comedi_subdevice *, 149 struct comedi_insn *, unsigned int *); 150 151static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *, 152 struct comedi_insn *, unsigned int *); 153static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *, 154 struct comedi_insn *, unsigned int *); 155static int ao_winsn(struct comedi_device *, struct comedi_subdevice *, 156 struct comedi_insn *, unsigned int *); 157 158/* 159 * Board descriptions for two imaginary boards. Describing the 160 * boards in this way is optional, and completely driver-dependent. 161 * Some drivers use arrays such as this, other do not. 162 */ 163struct pcmmio_board { 164 const char *name; 165 const int dio_num_asics; 166 const int dio_num_ports; 167 const int total_iosize; 168 const int ai_bits; 169 const int ao_bits; 170 const int n_ai_chans; 171 const int n_ao_chans; 172 const struct comedi_lrange *ai_range_table, *ao_range_table; 173 comedi_insn_fn_t ai_rinsn, ao_rinsn, ao_winsn; 174}; 175 176static const struct comedi_lrange ranges_ai = { 177 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)} 178}; 179 180static const struct comedi_lrange ranges_ao = { 181 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.), 182 RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)} 183}; 184 185static const struct pcmmio_board pcmmio_boards[] = { 186 { 187 .name = "pcmmio", 188 .dio_num_asics = 1, 189 .dio_num_ports = 6, 190 .total_iosize = 32, 191 .ai_bits = 16, 192 .ao_bits = 16, 193 .n_ai_chans = 16, 194 .n_ao_chans = 8, 195 .ai_range_table = &ranges_ai, 196 .ao_range_table = &ranges_ao, 197 .ai_rinsn = ai_rinsn, 198 .ao_rinsn = ao_rinsn, 199 .ao_winsn = ao_winsn}, 200}; 201 202/* 203 * Useful for shorthand access to the particular board structure 204 */ 205#define thisboard ((const struct pcmmio_board *)dev->board_ptr) 206 207/* this structure is for data unique to this subdevice. */ 208struct pcmmio_subdev_private { 209 210 union { 211 /* for DIO: mapping of halfwords (bytes) 212 in port/chanarray to iobase */ 213 unsigned long iobases[PORTS_PER_SUBDEV]; 214 215 /* for AI/AO */ 216 unsigned long iobase; 217 }; 218 union { 219 struct { 220 221 /* The below is only used for intr subdevices */ 222 struct { 223 /* 224 * if non-negative, this subdev has an 225 * interrupt asic 226 */ 227 int asic; 228 /* 229 * if nonnegative, the first channel id for 230 * interrupts. 231 */ 232 int first_chan; 233 /* 234 * the number of asic channels in this subdev 235 * that have interrutps 236 */ 237 int num_asic_chans; 238 /* 239 * if nonnegative, the first channel id with 240 * respect to the asic that has interrupts 241 */ 242 int asic_chan; 243 /* 244 * subdev-relative channel mask for channels 245 * we are interested in 246 */ 247 int enabled_mask; 248 int active; 249 int stop_count; 250 int continuous; 251 spinlock_t spinlock; 252 } intr; 253 } dio; 254 struct { 255 /* the last unsigned int data written */ 256 unsigned int shadow_samples[8]; 257 } ao; 258 }; 259}; 260 261/* 262 * this structure is for data unique to this hardware driver. If 263 * several hardware drivers keep similar information in this structure, 264 * feel free to suggest moving the variable to the struct comedi_device struct. 265 */ 266struct pcmmio_private { 267 /* stuff for DIO */ 268 struct { 269 unsigned char pagelock; /* current page and lock */ 270 /* shadow of POLx registers */ 271 unsigned char pol[NUM_PAGED_REGS]; 272 /* shadow of ENABx registers */ 273 unsigned char enab[NUM_PAGED_REGS]; 274 int num; 275 unsigned long iobase; 276 unsigned int irq; 277 spinlock_t spinlock; 278 } asics[MAX_ASICS]; 279 struct pcmmio_subdev_private *sprivs; 280}; 281 282/* 283 * most drivers define the following macro to make it easy to 284 * access the private structure. 285 */ 286#define devpriv ((struct pcmmio_private *)dev->private) 287#define subpriv ((struct pcmmio_subdev_private *)s->private) 288/* 289 * The struct comedi_driver structure tells the Comedi core module 290 * which functions to call to configure/deconfigure (attach/detach) 291 * the board, and also about the kernel module that contains 292 * the device code. 293 */ 294static int pcmmio_attach(struct comedi_device *dev, 295 struct comedi_devconfig *it); 296static int pcmmio_detach(struct comedi_device *dev); 297 298static struct comedi_driver driver = { 299 .driver_name = "pcmmio", 300 .module = THIS_MODULE, 301 .attach = pcmmio_attach, 302 .detach = pcmmio_detach, 303/* It is not necessary to implement the following members if you are 304 * writing a driver for a ISA PnP or PCI card */ 305 /* Most drivers will support multiple types of boards by 306 * having an array of board structures. These were defined 307 * in pcmmio_boards[] above. Note that the element 'name' 308 * was first in the structure -- Comedi uses this fact to 309 * extract the name of the board without knowing any details 310 * about the structure except for its length. 311 * When a device is attached (by comedi_config), the name 312 * of the device is given to Comedi, and Comedi tries to 313 * match it by going through the list of board names. If 314 * there is a match, the address of the pointer is put 315 * into dev->board_ptr and driver->attach() is called. 316 * 317 * Note that these are not necessary if you can determine 318 * the type of board in software. ISA PnP, PCI, and PCMCIA 319 * devices are such boards. 320 */ 321 .board_name = &pcmmio_boards[0].name, 322 .offset = sizeof(struct pcmmio_board), 323 .num_names = ARRAY_SIZE(pcmmio_boards), 324}; 325 326static int pcmmio_dio_insn_bits(struct comedi_device *dev, 327 struct comedi_subdevice *s, 328 struct comedi_insn *insn, unsigned int *data); 329static int pcmmio_dio_insn_config(struct comedi_device *dev, 330 struct comedi_subdevice *s, 331 struct comedi_insn *insn, unsigned int *data); 332 333static irqreturn_t interrupt_pcmmio(int irq, void *d); 334static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *); 335static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s); 336static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s); 337static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, 338 struct comedi_cmd *cmd); 339 340/* some helper functions to deal with specifics of this device's registers */ 341/* sets up/clears ASIC chips to defaults */ 342static void init_asics(struct comedi_device *dev); 343static void switch_page(struct comedi_device *dev, int asic, int page); 344#ifdef notused 345static void lock_port(struct comedi_device *dev, int asic, int port); 346static void unlock_port(struct comedi_device *dev, int asic, int port); 347#endif 348 349/* 350 * Attach is called by the Comedi core to configure the driver 351 * for a particular board. If you specified a board_name array 352 * in the driver structure, dev->board_ptr contains that 353 * address. 354 */ 355static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) 356{ 357 struct comedi_subdevice *s; 358 int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic, 359 thisasic_chanct = 0; 360 unsigned long iobase; 361 unsigned int irq[MAX_ASICS]; 362 363 iobase = it->options[0]; 364 irq[0] = it->options[1]; 365 366 printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name, 367 iobase); 368 369 dev->iobase = iobase; 370 371 if (!iobase || !request_region(iobase, 372 thisboard->total_iosize, 373 driver.driver_name)) { 374 printk("I/O port conflict\n"); 375 return -EIO; 376 } 377 378/* 379 * Initialize dev->board_name. Note that we can use the "thisboard" 380 * macro now, since we just initialized it in the last line. 381 */ 382 dev->board_name = thisboard->name; 383 384/* 385 * Allocate the private structure area. alloc_private() is a 386 * convenient macro defined in comedidev.h. 387 */ 388 if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) { 389 printk("cannot allocate private data structure\n"); 390 return -ENOMEM; 391 } 392 393 for (asic = 0; asic < MAX_ASICS; ++asic) { 394 devpriv->asics[asic].num = asic; 395 devpriv->asics[asic].iobase = 396 dev->iobase + 16 + asic * ASIC_IOSIZE; 397 /* 398 * this gets actually set at the end of this function when we 399 * request_irqs 400 */ 401 devpriv->asics[asic].irq = 0; 402 spin_lock_init(&devpriv->asics[asic].spinlock); 403 } 404 405 chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics; 406 n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left); 407 n_subdevs = n_dio_subdevs + 2; 408 devpriv->sprivs = 409 kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private), 410 GFP_KERNEL); 411 if (!devpriv->sprivs) { 412 printk("cannot allocate subdevice private data structures\n"); 413 return -ENOMEM; 414 } 415 /* 416 * Allocate the subdevice structures. alloc_subdevice() is a 417 * convenient macro defined in comedidev.h. 418 * 419 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO) 420 */ 421 if (alloc_subdevices(dev, n_subdevs) < 0) { 422 printk("cannot allocate subdevice data structures\n"); 423 return -ENOMEM; 424 } 425 426 /* First, AI */ 427 sdev_no = 0; 428 s = dev->subdevices + sdev_no; 429 s->private = devpriv->sprivs + sdev_no; 430 s->maxdata = (1 << thisboard->ai_bits) - 1; 431 s->range_table = thisboard->ai_range_table; 432 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; 433 s->type = COMEDI_SUBD_AI; 434 s->n_chan = thisboard->n_ai_chans; 435 s->len_chanlist = s->n_chan; 436 s->insn_read = thisboard->ai_rinsn; 437 subpriv->iobase = dev->iobase + 0; 438 /* initialize the resource enable register by clearing it */ 439 outb(0, subpriv->iobase + 3); 440 outb(0, subpriv->iobase + 4 + 3); 441 442 /* Next, AO */ 443 ++sdev_no; 444 s = dev->subdevices + sdev_no; 445 s->private = devpriv->sprivs + sdev_no; 446 s->maxdata = (1 << thisboard->ao_bits) - 1; 447 s->range_table = thisboard->ao_range_table; 448 s->subdev_flags = SDF_READABLE; 449 s->type = COMEDI_SUBD_AO; 450 s->n_chan = thisboard->n_ao_chans; 451 s->len_chanlist = s->n_chan; 452 s->insn_read = thisboard->ao_rinsn; 453 s->insn_write = thisboard->ao_winsn; 454 subpriv->iobase = dev->iobase + 8; 455 /* initialize the resource enable register by clearing it */ 456 outb(0, subpriv->iobase + 3); 457 outb(0, subpriv->iobase + 4 + 3); 458 459 ++sdev_no; 460 port = 0; 461 asic = 0; 462 for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) { 463 int byte_no; 464 465 s = dev->subdevices + sdev_no; 466 s->private = devpriv->sprivs + sdev_no; 467 s->maxdata = 1; 468 s->range_table = &range_digital; 469 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 470 s->type = COMEDI_SUBD_DIO; 471 s->insn_bits = pcmmio_dio_insn_bits; 472 s->insn_config = pcmmio_dio_insn_config; 473 s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV); 474 subpriv->dio.intr.asic = -1; 475 subpriv->dio.intr.first_chan = -1; 476 subpriv->dio.intr.asic_chan = -1; 477 subpriv->dio.intr.num_asic_chans = -1; 478 subpriv->dio.intr.active = 0; 479 s->len_chanlist = 1; 480 481 /* save the ioport address for each 'port' of 8 channels in the 482 subdevice */ 483 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) { 484 if (port >= PORTS_PER_ASIC) { 485 port = 0; 486 ++asic; 487 thisasic_chanct = 0; 488 } 489 subpriv->iobases[byte_no] = 490 devpriv->asics[asic].iobase + port; 491 492 if (thisasic_chanct < 493 CHANS_PER_PORT * INTR_PORTS_PER_ASIC 494 && subpriv->dio.intr.asic < 0) { 495 /* 496 * this is an interrupt subdevice, 497 * so setup the struct 498 */ 499 subpriv->dio.intr.asic = asic; 500 subpriv->dio.intr.active = 0; 501 subpriv->dio.intr.stop_count = 0; 502 subpriv->dio.intr.first_chan = byte_no * 8; 503 subpriv->dio.intr.asic_chan = thisasic_chanct; 504 subpriv->dio.intr.num_asic_chans = 505 s->n_chan - subpriv->dio.intr.first_chan; 506 s->cancel = pcmmio_cancel; 507 s->do_cmd = pcmmio_cmd; 508 s->do_cmdtest = pcmmio_cmdtest; 509 s->len_chanlist = 510 subpriv->dio.intr.num_asic_chans; 511 } 512 thisasic_chanct += CHANS_PER_PORT; 513 } 514 spin_lock_init(&subpriv->dio.intr.spinlock); 515 516 chans_left -= s->n_chan; 517 518 if (!chans_left) { 519 /* 520 * reset the asic to our first asic, 521 * to do intr subdevs 522 */ 523 asic = 0; 524 port = 0; 525 } 526 527 } 528 529 init_asics(dev); /* clear out all the registers, basically */ 530 531 for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { 532 if (irq[asic] 533 && request_irq(irq[asic], interrupt_pcmmio, 534 IRQF_SHARED, thisboard->name, dev)) { 535 int i; 536 /* unroll the allocated irqs.. */ 537 for (i = asic - 1; i >= 0; --i) { 538 free_irq(irq[i], dev); 539 devpriv->asics[i].irq = irq[i] = 0; 540 } 541 irq[asic] = 0; 542 } 543 devpriv->asics[asic].irq = irq[asic]; 544 } 545 546 dev->irq = irq[0]; /* 547 * grr.. wish comedi dev struct supported 548 * multiple irqs.. 549 */ 550 551 if (irq[0]) { 552 printk("irq: %u ", irq[0]); 553 if (thisboard->dio_num_asics == 2 && irq[1]) 554 printk("second ASIC irq: %u ", irq[1]); 555 } else { 556 printk("(IRQ mode disabled) "); 557 } 558 559 printk("attached\n"); 560 561 return 1; 562} 563 564/* 565 * _detach is called to deconfigure a device. It should deallocate 566 * resources. 567 * This function is also called when _attach() fails, so it should be 568 * careful not to release resources that were not necessarily 569 * allocated by _attach(). dev->private and dev->subdevices are 570 * deallocated automatically by the core. 571 */ 572static int pcmmio_detach(struct comedi_device *dev) 573{ 574 int i; 575 576 printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name); 577 if (dev->iobase) 578 release_region(dev->iobase, thisboard->total_iosize); 579 580 for (i = 0; i < MAX_ASICS; ++i) { 581 if (devpriv && devpriv->asics[i].irq) 582 free_irq(devpriv->asics[i].irq, dev); 583 } 584 585 if (devpriv && devpriv->sprivs) 586 kfree(devpriv->sprivs); 587 588 return 0; 589} 590 591/* DIO devices are slightly special. Although it is possible to 592 * implement the insn_read/insn_write interface, it is much more 593 * useful to applications if you implement the insn_bits interface. 594 * This allows packed reading/writing of the DIO channels. The 595 * comedi core can convert between insn_bits and insn_read/write */ 596static int pcmmio_dio_insn_bits(struct comedi_device *dev, 597 struct comedi_subdevice *s, 598 struct comedi_insn *insn, unsigned int *data) 599{ 600 int byte_no; 601 if (insn->n != 2) 602 return -EINVAL; 603 604 /* NOTE: 605 reading a 0 means this channel was high 606 writine a 0 sets the channel high 607 reading a 1 means this channel was low 608 writing a 1 means set this channel low 609 610 Therefore everything is always inverted. */ 611 612 /* The insn data is a mask in data[0] and the new data 613 * in data[1], each channel cooresponding to a bit. */ 614 615#ifdef DAMMIT_ITS_BROKEN 616 /* DEBUG */ 617 printk("write mask: %08x data: %08x\n", data[0], data[1]); 618#endif 619 620 s->state = 0; 621 622 for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) { 623 /* address of 8-bit port */ 624 unsigned long ioaddr = subpriv->iobases[byte_no], 625 /* bit offset of port in 32-bit doubleword */ 626 offset = byte_no * 8; 627 /* this 8-bit port's data */ 628 unsigned char byte = 0, 629 /* The write mask for this port (if any) */ 630 write_mask_byte = (data[0] >> offset) & 0xff, 631 /* The data byte for this port */ 632 data_byte = (data[1] >> offset) & 0xff; 633 634 byte = inb(ioaddr); /* read all 8-bits for this port */ 635 636#ifdef DAMMIT_ITS_BROKEN 637 /* DEBUG */ 638 printk 639 ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ", 640 byte_no, (unsigned)write_mask_byte, (unsigned)data_byte, 641 offset, ioaddr, (unsigned)byte); 642#endif 643 644 if (write_mask_byte) { 645 /* 646 * this byte has some write_bits 647 * -- so set the output lines 648 */ 649 /* clear bits for write mask */ 650 byte &= ~write_mask_byte; 651 /* set to inverted data_byte */ 652 byte |= ~data_byte & write_mask_byte; 653 /* Write out the new digital output state */ 654 outb(byte, ioaddr); 655 } 656#ifdef DAMMIT_ITS_BROKEN 657 /* DEBUG */ 658 printk("data_out_byte %02x\n", (unsigned)byte); 659#endif 660 /* save the digital input lines for this byte.. */ 661 s->state |= ((unsigned int)byte) << offset; 662 } 663 664 /* now return the DIO lines to data[1] - note they came inverted! */ 665 data[1] = ~s->state; 666 667#ifdef DAMMIT_ITS_BROKEN 668 /* DEBUG */ 669 printk("s->state %08x data_out %08x\n", s->state, data[1]); 670#endif 671 672 return 2; 673} 674 675/* The input or output configuration of each digital line is 676 * configured by a special insn_config instruction. chanspec 677 * contains the channel to be changed, and data[0] contains the 678 * value COMEDI_INPUT or COMEDI_OUTPUT. */ 679static int pcmmio_dio_insn_config(struct comedi_device *dev, 680 struct comedi_subdevice *s, 681 struct comedi_insn *insn, unsigned int *data) 682{ 683 int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no = 684 chan % 8; 685 unsigned long ioaddr; 686 unsigned char byte; 687 688 /* Compute ioaddr for this channel */ 689 ioaddr = subpriv->iobases[byte_no]; 690 691 /* NOTE: 692 writing a 0 an IO channel's bit sets the channel to INPUT 693 and pulls the line high as well 694 695 writing a 1 to an IO channel's bit pulls the line low 696 697 All channels are implicitly always in OUTPUT mode -- but when 698 they are high they can be considered to be in INPUT mode.. 699 700 Thus, we only force channels low if the config request was INPUT, 701 otherwise we do nothing to the hardware. */ 702 703 switch (data[0]) { 704 case INSN_CONFIG_DIO_OUTPUT: 705 /* save to io_bits -- don't actually do anything since 706 all input channels are also output channels... */ 707 s->io_bits |= 1 << chan; 708 break; 709 case INSN_CONFIG_DIO_INPUT: 710 /* write a 0 to the actual register representing the channel 711 to set it to 'input'. 0 means "float high". */ 712 byte = inb(ioaddr); 713 byte &= ~(1 << bit_no); 714 /**< set input channel to '0' */ 715 716 /* 717 * write out byte -- this is the only time we actually affect 718 * the hardware as all channels are implicitly output 719 * -- but input channels are set to float-high 720 */ 721 outb(byte, ioaddr); 722 723 /* save to io_bits */ 724 s->io_bits &= ~(1 << chan); 725 break; 726 727 case INSN_CONFIG_DIO_QUERY: 728 /* retreive from shadow register */ 729 data[1] = 730 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; 731 return insn->n; 732 break; 733 734 default: 735 return -EINVAL; 736 break; 737 } 738 739 return insn->n; 740} 741 742static void init_asics(struct comedi_device *dev) 743{ /* sets up an 744 ASIC chip to defaults */ 745 int asic; 746 747 for (asic = 0; asic < thisboard->dio_num_asics; ++asic) { 748 int port, page; 749 unsigned long baseaddr = devpriv->asics[asic].iobase; 750 751 switch_page(dev, asic, 0); /* switch back to page 0 */ 752 753 /* first, clear all the DIO port bits */ 754 for (port = 0; port < PORTS_PER_ASIC; ++port) 755 outb(0, baseaddr + REG_PORT0 + port); 756 757 /* Next, clear all the paged registers for each page */ 758 for (page = 1; page < NUM_PAGES; ++page) { 759 int reg; 760 /* now clear all the paged registers */ 761 switch_page(dev, asic, page); 762 for (reg = FIRST_PAGED_REG; 763 reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg) 764 outb(0, baseaddr + reg); 765 } 766 767 /* DEBUG set rising edge interrupts on port0 of both asics */ 768 /*switch_page(dev, asic, PAGE_POL); 769 outb(0xff, baseaddr + REG_POL0); 770 switch_page(dev, asic, PAGE_ENAB); 771 outb(0xff, baseaddr + REG_ENAB0); */ 772 /* END DEBUG */ 773 774 /* switch back to default page 0 */ 775 switch_page(dev, asic, 0); 776 } 777} 778 779static void switch_page(struct comedi_device *dev, int asic, int page) 780{ 781 if (asic < 0 || asic >= thisboard->dio_num_asics) 782 return; /* paranoia */ 783 if (page < 0 || page >= NUM_PAGES) 784 return; /* more paranoia */ 785 786 devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK; 787 devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET; 788 789 /* now write out the shadow register */ 790 outb(devpriv->asics[asic].pagelock, 791 devpriv->asics[asic].iobase + REG_PAGELOCK); 792} 793 794#ifdef notused 795static void lock_port(struct comedi_device *dev, int asic, int port) 796{ 797 if (asic < 0 || asic >= thisboard->dio_num_asics) 798 return; /* paranoia */ 799 if (port < 0 || port >= PORTS_PER_ASIC) 800 return; /* more paranoia */ 801 802 devpriv->asics[asic].pagelock |= 0x1 << port; 803 /* now write out the shadow register */ 804 outb(devpriv->asics[asic].pagelock, 805 devpriv->asics[asic].iobase + REG_PAGELOCK); 806 return; 807} 808 809static void unlock_port(struct comedi_device *dev, int asic, int port) 810{ 811 if (asic < 0 || asic >= thisboard->dio_num_asics) 812 return; /* paranoia */ 813 if (port < 0 || port >= PORTS_PER_ASIC) 814 return; /* more paranoia */ 815 devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK; 816 /* now write out the shadow register */ 817 outb(devpriv->asics[asic].pagelock, 818 devpriv->asics[asic].iobase + REG_PAGELOCK); 819} 820#endif /* notused */ 821 822static irqreturn_t interrupt_pcmmio(int irq, void *d) 823{ 824 int asic, got1 = 0; 825 struct comedi_device *dev = (struct comedi_device *)d; 826 827 for (asic = 0; asic < MAX_ASICS; ++asic) { 828 if (irq == devpriv->asics[asic].irq) { 829 unsigned long flags; 830 unsigned triggered = 0; 831 unsigned long iobase = devpriv->asics[asic].iobase; 832 /* it is an interrupt for ASIC #asic */ 833 unsigned char int_pend; 834 835 spin_lock_irqsave(&devpriv->asics[asic].spinlock, 836 flags); 837 838 int_pend = inb(iobase + REG_INT_PENDING) & 0x07; 839 840 if (int_pend) { 841 int port; 842 for (port = 0; port < INTR_PORTS_PER_ASIC; 843 ++port) { 844 if (int_pend & (0x1 << port)) { 845 unsigned char 846 io_lines_with_edges = 0; 847 switch_page(dev, asic, 848 PAGE_INT_ID); 849 io_lines_with_edges = 850 inb(iobase + 851 REG_INT_ID0 + port); 852 853 if (io_lines_with_edges) 854 /* 855 * clear pending 856 * interrupt 857 */ 858 outb(0, iobase + 859 REG_INT_ID0 + 860 port); 861 862 triggered |= 863 io_lines_with_edges << 864 port * 8; 865 } 866 } 867 868 ++got1; 869 } 870 871 spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, 872 flags); 873 874 if (triggered) { 875 struct comedi_subdevice *s; 876 /* 877 * TODO here: dispatch io lines to subdevs 878 * with commands.. 879 */ 880 printk 881 ("PCMMIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", 882 irq, asic, triggered); 883 for (s = dev->subdevices + 2; 884 s < dev->subdevices + dev->n_subdevices; 885 ++s) { 886 /* 887 * this is an interrupt subdev, 888 * and it matches this asic! 889 */ 890 if (subpriv->dio.intr.asic == asic) { 891 unsigned long flags; 892 unsigned oldevents; 893 894 spin_lock_irqsave(&subpriv->dio. 895 intr.spinlock, 896 flags); 897 898 oldevents = s->async->events; 899 900 if (subpriv->dio.intr.active) { 901 unsigned mytrig = 902 ((triggered >> 903 subpriv->dio.intr.asic_chan) 904 & 905 ((0x1 << subpriv-> 906 dio.intr. 907 num_asic_chans) - 908 1)) << subpriv-> 909 dio.intr.first_chan; 910 if (mytrig & 911 subpriv->dio. 912 intr.enabled_mask) { 913 unsigned int val 914 = 0; 915 unsigned int n, 916 ch, len; 917 918 len = 919 s-> 920 async->cmd.chanlist_len; 921 for (n = 0; 922 n < len; 923 n++) { 924 ch = CR_CHAN(s->async->cmd.chanlist[n]); 925 if (mytrig & (1U << ch)) 926 val |= (1U << n); 927 } 928 /* Write the scan to the buffer. */ 929 if (comedi_buf_put(s->async, ((short *)&val)[0]) 930 && 931 comedi_buf_put 932 (s->async, 933 ((short *) 934 &val)[1])) { 935 s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); 936 } else { 937 /* Overflow! Stop acquisition!! */ 938 /* TODO: STOP_ACQUISITION_CALL_HERE!! */ 939 pcmmio_stop_intr 940 (dev, 941 s); 942 } 943 944 /* Check for end of acquisition. */ 945 if (!subpriv->dio.intr.continuous) { 946 /* stop_src == TRIG_COUNT */ 947 if (subpriv->dio.intr.stop_count > 0) { 948 subpriv->dio.intr.stop_count--; 949 if (subpriv->dio.intr.stop_count == 0) { 950 s->async->events |= COMEDI_CB_EOA; 951 /* TODO: STOP_ACQUISITION_CALL_HERE!! */ 952 pcmmio_stop_intr 953 (dev, 954 s); 955 } 956 } 957 } 958 } 959 } 960 961 spin_unlock_irqrestore 962 (&subpriv->dio.intr. 963 spinlock, flags); 964 965 if (oldevents != 966 s->async->events) { 967 comedi_event(dev, s); 968 } 969 970 } 971 972 } 973 } 974 975 } 976 } 977 if (!got1) 978 return IRQ_NONE; /* interrupt from other source */ 979 return IRQ_HANDLED; 980} 981 982static void pcmmio_stop_intr(struct comedi_device *dev, 983 struct comedi_subdevice *s) 984{ 985 int nports, firstport, asic, port; 986 987 asic = subpriv->dio.intr.asic; 988 if (asic < 0) 989 return; /* not an interrupt subdev */ 990 991 subpriv->dio.intr.enabled_mask = 0; 992 subpriv->dio.intr.active = 0; 993 s->async->inttrig = 0; 994 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT; 995 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT; 996 switch_page(dev, asic, PAGE_ENAB); 997 for (port = firstport; port < firstport + nports; ++port) { 998 /* disable all intrs for this subdev.. */ 999 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port); 1000 } 1001} 1002 1003static int pcmmio_start_intr(struct comedi_device *dev, 1004 struct comedi_subdevice *s) 1005{ 1006 if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) { 1007 /* An empty acquisition! */ 1008 s->async->events |= COMEDI_CB_EOA; 1009 subpriv->dio.intr.active = 0; 1010 return 1; 1011 } else { 1012 unsigned bits = 0, pol_bits = 0, n; 1013 int nports, firstport, asic, port; 1014 struct comedi_cmd *cmd = &s->async->cmd; 1015 1016 asic = subpriv->dio.intr.asic; 1017 if (asic < 0) 1018 return 1; /* not an interrupt 1019 subdev */ 1020 subpriv->dio.intr.enabled_mask = 0; 1021 subpriv->dio.intr.active = 1; 1022 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT; 1023 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT; 1024 if (cmd->chanlist) { 1025 for (n = 0; n < cmd->chanlist_len; n++) { 1026 bits |= (1U << CR_CHAN(cmd->chanlist[n])); 1027 pol_bits |= (CR_AREF(cmd->chanlist[n]) 1028 || CR_RANGE(cmd-> 1029 chanlist[n]) ? 1U : 0U) 1030 << CR_CHAN(cmd->chanlist[n]); 1031 } 1032 } 1033 bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) - 1034 1) << subpriv->dio.intr.first_chan; 1035 subpriv->dio.intr.enabled_mask = bits; 1036 1037 { 1038 /* 1039 * the below code configures the board 1040 * to use a specific IRQ from 0-15. 1041 */ 1042 unsigned char b; 1043 /* 1044 * set resource enable register 1045 * to enable IRQ operation 1046 */ 1047 outb(1 << 4, dev->iobase + 3); 1048 /* set bits 0-3 of b to the irq number from 0-15 */ 1049 b = dev->irq & ((1 << 4) - 1); 1050 outb(b, dev->iobase + 2); 1051 /* done, we told the board what irq to use */ 1052 } 1053 1054 switch_page(dev, asic, PAGE_ENAB); 1055 for (port = firstport; port < firstport + nports; ++port) { 1056 unsigned enab = 1057 bits >> (subpriv->dio.intr.first_chan + (port - 1058 firstport) 1059 * 8) & 0xff, pol = 1060 pol_bits >> (subpriv->dio.intr.first_chan + 1061 (port - firstport) * 8) & 0xff; 1062 /* set enab intrs for this subdev.. */ 1063 outb(enab, 1064 devpriv->asics[asic].iobase + REG_ENAB0 + port); 1065 switch_page(dev, asic, PAGE_POL); 1066 outb(pol, 1067 devpriv->asics[asic].iobase + REG_ENAB0 + port); 1068 } 1069 } 1070 return 0; 1071} 1072 1073static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 1074{ 1075 unsigned long flags; 1076 1077 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); 1078 if (subpriv->dio.intr.active) 1079 pcmmio_stop_intr(dev, s); 1080 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); 1081 1082 return 0; 1083} 1084 1085/* 1086 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. 1087 */ 1088static int 1089pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, 1090 unsigned int trignum) 1091{ 1092 unsigned long flags; 1093 int event = 0; 1094 1095 if (trignum != 0) 1096 return -EINVAL; 1097 1098 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); 1099 s->async->inttrig = 0; 1100 if (subpriv->dio.intr.active) 1101 event = pcmmio_start_intr(dev, s); 1102 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); 1103 1104 if (event) 1105 comedi_event(dev, s); 1106 1107 return 1; 1108} 1109 1110/* 1111 * 'do_cmd' function for an 'INTERRUPT' subdevice. 1112 */ 1113static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 1114{ 1115 struct comedi_cmd *cmd = &s->async->cmd; 1116 unsigned long flags; 1117 int event = 0; 1118 1119 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); 1120 subpriv->dio.intr.active = 1; 1121 1122 /* Set up end of acquisition. */ 1123 switch (cmd->stop_src) { 1124 case TRIG_COUNT: 1125 subpriv->dio.intr.continuous = 0; 1126 subpriv->dio.intr.stop_count = cmd->stop_arg; 1127 break; 1128 default: 1129 /* TRIG_NONE */ 1130 subpriv->dio.intr.continuous = 1; 1131 subpriv->dio.intr.stop_count = 0; 1132 break; 1133 } 1134 1135 /* Set up start of acquisition. */ 1136 switch (cmd->start_src) { 1137 case TRIG_INT: 1138 s->async->inttrig = pcmmio_inttrig_start_intr; 1139 break; 1140 default: 1141 /* TRIG_NOW */ 1142 event = pcmmio_start_intr(dev, s); 1143 break; 1144 } 1145 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); 1146 1147 if (event) 1148 comedi_event(dev, s); 1149 1150 return 0; 1151} 1152 1153static int 1154pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, 1155 struct comedi_cmd *cmd) 1156{ 1157 return comedi_pcm_cmdtest(dev, s, cmd); 1158} 1159 1160static int adc_wait_ready(unsigned long iobase) 1161{ 1162 unsigned long retry = 100000; 1163 while (retry--) 1164 if (inb(iobase + 3) & 0x80) 1165 return 0; 1166 return 1; 1167} 1168 1169/* All this is for AI and AO */ 1170static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 1171 struct comedi_insn *insn, unsigned int *data) 1172{ 1173 int n; 1174 unsigned long iobase = subpriv->iobase; 1175 1176 /* 1177 1. write the CMD byte (to BASE+2) 1178 2. read junk lo byte (BASE+0) 1179 3. read junk hi byte (BASE+1) 1180 4. (mux settled so) write CMD byte again (BASE+2) 1181 5. read valid lo byte(BASE+0) 1182 6. read valid hi byte(BASE+1) 1183 1184 Additionally note that the BASE += 4 if the channel >= 8 1185 */ 1186 1187 /* convert n samples */ 1188 for (n = 0; n < insn->n; n++) { 1189 unsigned chan = CR_CHAN(insn->chanspec), range = 1190 CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec); 1191 unsigned char command_byte = 0; 1192 unsigned iooffset = 0; 1193 short sample, adc_adjust = 0; 1194 1195 if (chan > 7) 1196 chan -= 8, iooffset = 4; /* 1197 * use the second dword 1198 * for channels > 7 1199 */ 1200 1201 if (aref != AREF_DIFF) { 1202 aref = AREF_GROUND; 1203 command_byte |= 1 << 7; /* 1204 * set bit 7 to indicate 1205 * single-ended 1206 */ 1207 } 1208 if (range < 2) 1209 adc_adjust = 0x8000; /* 1210 * bipolar ranges 1211 * (-5,5 .. -10,10 need to be 1212 * adjusted -- that is.. they 1213 * need to wrap around by 1214 * adding 0x8000 1215 */ 1216 1217 if (chan % 2) { 1218 command_byte |= 1 << 6; /* 1219 * odd-numbered channels 1220 * have bit 6 set 1221 */ 1222 } 1223 1224 /* select the channel, bits 4-5 == chan/2 */ 1225 command_byte |= ((chan / 2) & 0x3) << 4; 1226 1227 /* set the range, bits 2-3 */ 1228 command_byte |= (range & 0x3) << 2; 1229 1230 /* need to do this twice to make sure mux settled */ 1231 /* chan/range/aref select */ 1232 outb(command_byte, iobase + iooffset + 2); 1233 1234 /* wait for the adc to say it finised the conversion */ 1235 adc_wait_ready(iobase + iooffset); 1236 1237 /* select the chan/range/aref AGAIN */ 1238 outb(command_byte, iobase + iooffset + 2); 1239 1240 adc_wait_ready(iobase + iooffset); 1241 1242 /* read data lo byte */ 1243 sample = inb(iobase + iooffset + 0); 1244 1245 /* read data hi byte */ 1246 sample |= inb(iobase + iooffset + 1) << 8; 1247 sample += adc_adjust; /* adjustment .. munge data */ 1248 data[n] = sample; 1249 } 1250 /* return the number of samples read/written */ 1251 return n; 1252} 1253 1254static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 1255 struct comedi_insn *insn, unsigned int *data) 1256{ 1257 int n; 1258 for (n = 0; n < insn->n; n++) { 1259 unsigned chan = CR_CHAN(insn->chanspec); 1260 if (chan < s->n_chan) 1261 data[n] = subpriv->ao.shadow_samples[chan]; 1262 } 1263 return n; 1264} 1265 1266static int wait_dac_ready(unsigned long iobase) 1267{ 1268 unsigned long retry = 100000L; 1269 1270 /* This may seem like an absurd way to handle waiting and violates the 1271 "no busy waiting" policy. The fact is that the hardware is 1272 normally so fast that we usually only need one time through the loop 1273 anyway. The longer timeout is for rare occasions and for detecting 1274 non-existant hardware. */ 1275 1276 while (retry--) { 1277 if (inb(iobase + 3) & 0x80) 1278 return 0; 1279 1280 } 1281 return 1; 1282} 1283 1284static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, 1285 struct comedi_insn *insn, unsigned int *data) 1286{ 1287 int n; 1288 unsigned iobase = subpriv->iobase, iooffset = 0; 1289 1290 for (n = 0; n < insn->n; n++) { 1291 unsigned chan = CR_CHAN(insn->chanspec), range = 1292 CR_RANGE(insn->chanspec); 1293 if (chan < s->n_chan) { 1294 unsigned char command_byte = 0, range_byte = 1295 range & ((1 << 4) - 1); 1296 if (chan >= 4) 1297 chan -= 4, iooffset += 4; 1298 /* set the range.. */ 1299 outb(range_byte, iobase + iooffset + 0); 1300 outb(0, iobase + iooffset + 1); 1301 1302 /* tell it to begin */ 1303 command_byte = (chan << 1) | 0x60; 1304 outb(command_byte, iobase + iooffset + 2); 1305 1306 wait_dac_ready(iobase + iooffset); 1307 1308 /* low order byte */ 1309 outb(data[n] & 0xff, iobase + iooffset + 0); 1310 1311 /* high order byte */ 1312 outb((data[n] >> 8) & 0xff, iobase + iooffset + 1); 1313 1314 /* 1315 * set bit 4 of command byte to indicate 1316 * data is loaded and trigger conversion 1317 */ 1318 command_byte = 0x70 | (chan << 1); 1319 /* trigger converion */ 1320 outb(command_byte, iobase + iooffset + 2); 1321 1322 wait_dac_ready(iobase + iooffset); 1323 1324 /* save to shadow register for ao_rinsn */ 1325 subpriv->ao.shadow_samples[chan] = data[n]; 1326 } 1327 } 1328 return n; 1329} 1330 1331/* 1332 * A convenient macro that defines init_module() and cleanup_module(), 1333 * as necessary. 1334 */ 1335COMEDI_INITCLEANUP(driver); 1336