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