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