ni_65xx.c revision 90035c0886b256d75bced13b3b3cea5234aff136
1/* 2 comedi/drivers/ni_6514.c 3 driver for National Instruments PCI-6514 4 5 Copyright (C) 2006 Jon Grierson <jd@renko.co.uk> 6 Copyright (C) 2006 Frank Mori Hess <fmhess@users.sourceforge.net> 7 8 COMEDI - Linux Control and Measurement Device Interface 9 Copyright (C) 1999,2002,2003 David A. Schleef <ds@schleef.org> 10 11 This program is free software; you can redistribute it and/or modify 12 it under the terms of the GNU General Public License as published by 13 the Free Software Foundation; either version 2 of the License, or 14 (at your option) any later version. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program; if not, write to the Free Software 23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 25*/ 26/* 27Driver: ni_65xx 28Description: National Instruments 65xx static dio boards 29Author: Jon Grierson <jd@renko.co.uk>, Frank Mori Hess <fmhess@users.sourceforge.net> 30Status: testing 31Devices: [National Instruments] PCI-6509 (ni_65xx), PXI-6509, PCI-6510, PCI-6511, 32 PXI-6511, PCI-6512, PXI-6512, PCI-6513, PXI-6513, PCI-6514, PXI-6514, PCI-6515, 33 PXI-6515, PCI-6516, PCI-6517, PCI-6518, PCI-6519, PCI-6520, PCI-6521, PXI-6521, 34 PCI-6528, PXI-6528 35Updated: Wed Oct 18 08:59:11 EDT 2006 36 37Based on the PCI-6527 driver by ds. 38The interrupt subdevice (subdevice 3) is probably broken for all boards 39except maybe the 6514. 40 41*/ 42 43/* 44 Manuals (available from ftp://ftp.natinst.com/support/manuals) 45 46 370106b.pdf 6514 Register Level Programmer Manual 47 48 */ 49 50#define _GNU_SOURCE 51#define DEBUG 1 52#define DEBUG_FLAGS 53#include "../comedidev.h" 54 55#include "mite.h" 56 57#define NI6514_DIO_SIZE 4096 58#define NI6514_MITE_SIZE 4096 59 60#define NI_65XX_MAX_NUM_PORTS 12 61static const unsigned ni_65xx_channels_per_port = 8; 62static const unsigned ni_65xx_port_offset = 0x10; 63 64static inline unsigned Port_Data(unsigned port) 65{ 66 return 0x40 + port * ni_65xx_port_offset; 67} 68static inline unsigned Port_Select(unsigned port) 69{ 70 return 0x41 + port * ni_65xx_port_offset; 71} 72static inline unsigned Rising_Edge_Detection_Enable(unsigned port) 73{ 74 return 0x42 + port * ni_65xx_port_offset; 75} 76static inline unsigned Falling_Edge_Detection_Enable(unsigned port) 77{ 78 return 0x43 + port * ni_65xx_port_offset; 79} 80static inline unsigned Filter_Enable(unsigned port) 81{ 82 return 0x44 + port * ni_65xx_port_offset; 83} 84 85#define ID_Register 0x00 86 87#define Clear_Register 0x01 88#define ClrEdge 0x08 89#define ClrOverflow 0x04 90 91#define Filter_Interval 0x08 92 93#define Change_Status 0x02 94#define MasterInterruptStatus 0x04 95#define Overflow 0x02 96#define EdgeStatus 0x01 97 98#define Master_Interrupt_Control 0x03 99#define FallingEdgeIntEnable 0x10 100#define RisingEdgeIntEnable 0x08 101#define MasterInterruptEnable 0x04 102#define OverflowIntEnable 0x02 103#define EdgeIntEnable 0x01 104 105static int ni_65xx_attach(struct comedi_device * dev, comedi_devconfig * it); 106static int ni_65xx_detach(struct comedi_device * dev); 107static struct comedi_driver driver_ni_65xx = { 108 driver_name:"ni_65xx", 109 module:THIS_MODULE, 110 attach:ni_65xx_attach, 111 detach:ni_65xx_detach, 112}; 113 114typedef struct { 115 int dev_id; 116 const char *name; 117 unsigned num_dio_ports; 118 unsigned num_di_ports; 119 unsigned num_do_ports; 120 unsigned invert_outputs:1; 121} ni_65xx_board; 122static const ni_65xx_board ni_65xx_boards[] = { 123 { 124 dev_id: 0x7085, 125 name: "pci-6509", 126 num_dio_ports:12, 127 invert_outputs:0}, 128 { 129 dev_id: 0x1710, 130 name: "pxi-6509", 131 num_dio_ports:12, 132 invert_outputs:0}, 133 { 134 dev_id: 0x7124, 135 name: "pci-6510", 136 num_di_ports:4}, 137 { 138 dev_id: 0x70c3, 139 name: "pci-6511", 140 num_di_ports:8}, 141 { 142 dev_id: 0x70d3, 143 name: "pxi-6511", 144 num_di_ports:8}, 145 { 146 dev_id: 0x70cc, 147 name: "pci-6512", 148 num_do_ports:8}, 149 { 150 dev_id: 0x70d2, 151 name: "pxi-6512", 152 num_do_ports:8}, 153 { 154 dev_id: 0x70c8, 155 name: "pci-6513", 156 num_do_ports:8, 157 invert_outputs:1}, 158 { 159 dev_id: 0x70d1, 160 name: "pxi-6513", 161 num_do_ports:8, 162 invert_outputs:1}, 163 { 164 dev_id: 0x7088, 165 name: "pci-6514", 166 num_di_ports:4, 167 num_do_ports:4, 168 invert_outputs:1}, 169 { 170 dev_id: 0x70CD, 171 name: "pxi-6514", 172 num_di_ports:4, 173 num_do_ports:4, 174 invert_outputs:1}, 175 { 176 dev_id: 0x7087, 177 name: "pci-6515", 178 num_di_ports:4, 179 num_do_ports:4, 180 invert_outputs:1}, 181 { 182 dev_id: 0x70c9, 183 name: "pxi-6515", 184 num_di_ports:4, 185 num_do_ports:4, 186 invert_outputs:1}, 187 { 188 dev_id: 0x7125, 189 name: "pci-6516", 190 num_do_ports:4, 191 invert_outputs:1}, 192 { 193 dev_id: 0x7126, 194 name: "pci-6517", 195 num_do_ports:4, 196 invert_outputs:1}, 197 { 198 dev_id: 0x7127, 199 name: "pci-6518", 200 num_di_ports:2, 201 num_do_ports:2, 202 invert_outputs:1}, 203 { 204 dev_id: 0x7128, 205 name: "pci-6519", 206 num_di_ports:2, 207 num_do_ports:2, 208 invert_outputs:1}, 209 { 210 dev_id: 0x71c5, 211 name: "pci-6520", 212 num_di_ports:1, 213 num_do_ports:1, 214 }, 215 { 216 dev_id: 0x718b, 217 name: "pci-6521", 218 num_di_ports:1, 219 num_do_ports:1, 220 }, 221 { 222 dev_id: 0x718c, 223 name: "pxi-6521", 224 num_di_ports:1, 225 num_do_ports:1, 226 }, 227 { 228 dev_id: 0x70a9, 229 name: "pci-6528", 230 num_di_ports:3, 231 num_do_ports:3, 232 }, 233 { 234 dev_id: 0x7086, 235 name: "pxi-6528", 236 num_di_ports:3, 237 num_do_ports:3, 238 }, 239}; 240 241#define n_ni_65xx_boards (sizeof(ni_65xx_boards)/sizeof(ni_65xx_boards[0])) 242static inline const ni_65xx_board *board(struct comedi_device * dev) 243{ 244 return dev->board_ptr; 245} 246static inline unsigned ni_65xx_port_by_channel(unsigned channel) 247{ 248 return channel / ni_65xx_channels_per_port; 249} 250static inline unsigned ni_65xx_total_num_ports(const ni_65xx_board * board) 251{ 252 return board->num_dio_ports + board->num_di_ports + board->num_do_ports; 253} 254 255static DEFINE_PCI_DEVICE_TABLE(ni_65xx_pci_table) = { 256 {PCI_VENDOR_ID_NATINST, 0x1710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 257 {PCI_VENDOR_ID_NATINST, 0x7085, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 258 {PCI_VENDOR_ID_NATINST, 0x7086, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 259 {PCI_VENDOR_ID_NATINST, 0x7087, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 260 {PCI_VENDOR_ID_NATINST, 0x7088, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 261 {PCI_VENDOR_ID_NATINST, 0x70a9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 262 {PCI_VENDOR_ID_NATINST, 0x70c3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 263 {PCI_VENDOR_ID_NATINST, 0x70c8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 264 {PCI_VENDOR_ID_NATINST, 0x70c9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 265 {PCI_VENDOR_ID_NATINST, 0x70cc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 266 {PCI_VENDOR_ID_NATINST, 0x70CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 267 {PCI_VENDOR_ID_NATINST, 0x70d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 268 {PCI_VENDOR_ID_NATINST, 0x70d2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 269 {PCI_VENDOR_ID_NATINST, 0x70d3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 270 {PCI_VENDOR_ID_NATINST, 0x7124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 271 {PCI_VENDOR_ID_NATINST, 0x7125, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 272 {PCI_VENDOR_ID_NATINST, 0x7126, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 273 {PCI_VENDOR_ID_NATINST, 0x7127, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 274 {PCI_VENDOR_ID_NATINST, 0x7128, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 275 {PCI_VENDOR_ID_NATINST, 0x718b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 276 {PCI_VENDOR_ID_NATINST, 0x718c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 277 {PCI_VENDOR_ID_NATINST, 0x71c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 278 {0} 279}; 280 281MODULE_DEVICE_TABLE(pci, ni_65xx_pci_table); 282 283typedef struct { 284 struct mite_struct *mite; 285 unsigned int filter_interval; 286 unsigned short filter_enable[NI_65XX_MAX_NUM_PORTS]; 287 unsigned short output_bits[NI_65XX_MAX_NUM_PORTS]; 288 unsigned short dio_direction[NI_65XX_MAX_NUM_PORTS]; 289} ni_65xx_private; 290static inline ni_65xx_private *private(struct comedi_device * dev) 291{ 292 return dev->private; 293} 294 295typedef struct { 296 unsigned base_port; 297} ni_65xx_subdevice_private; 298static inline ni_65xx_subdevice_private *sprivate(struct comedi_subdevice * subdev) 299{ 300 return subdev->private; 301} 302static ni_65xx_subdevice_private *ni_65xx_alloc_subdevice_private(void) 303{ 304 ni_65xx_subdevice_private *subdev_private = 305 kzalloc(sizeof(ni_65xx_subdevice_private), GFP_KERNEL); 306 if (subdev_private == NULL) 307 return NULL; 308 return subdev_private; 309} 310 311static int ni_65xx_find_device(struct comedi_device * dev, int bus, int slot); 312 313static int ni_65xx_config_filter(struct comedi_device * dev, struct comedi_subdevice * s, 314 struct comedi_insn * insn, unsigned int * data) 315{ 316 const unsigned chan = CR_CHAN(insn->chanspec); 317 const unsigned port = 318 sprivate(s)->base_port + ni_65xx_port_by_channel(chan); 319 320 if (data[0] != INSN_CONFIG_FILTER) 321 return -EINVAL; 322 if (data[1]) { 323 static const unsigned filter_resolution_ns = 200; 324 static const unsigned max_filter_interval = 0xfffff; 325 unsigned interval = 326 (data[1] + 327 (filter_resolution_ns / 2)) / filter_resolution_ns; 328 if (interval > max_filter_interval) 329 interval = max_filter_interval; 330 data[1] = interval * filter_resolution_ns; 331 332 if (interval != private(dev)->filter_interval) { 333 writeb(interval, 334 private(dev)->mite->daq_io_addr + 335 Filter_Interval); 336 private(dev)->filter_interval = interval; 337 } 338 339 private(dev)->filter_enable[port] |= 340 1 << (chan % ni_65xx_channels_per_port); 341 } else { 342 private(dev)->filter_enable[port] &= 343 ~(1 << (chan % ni_65xx_channels_per_port)); 344 } 345 346 writeb(private(dev)->filter_enable[port], 347 private(dev)->mite->daq_io_addr + Filter_Enable(port)); 348 349 return 2; 350} 351 352static int ni_65xx_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, 353 struct comedi_insn * insn, unsigned int * data) 354{ 355 unsigned port; 356 357 if (insn->n < 1) 358 return -EINVAL; 359 port = sprivate(s)->base_port + 360 ni_65xx_port_by_channel(CR_CHAN(insn->chanspec)); 361 switch (data[0]) { 362 case INSN_CONFIG_FILTER: 363 return ni_65xx_config_filter(dev, s, insn, data); 364 break; 365 case INSN_CONFIG_DIO_OUTPUT: 366 if (s->type != COMEDI_SUBD_DIO) 367 return -EINVAL; 368 private(dev)->dio_direction[port] = COMEDI_OUTPUT; 369 writeb(0, private(dev)->mite->daq_io_addr + Port_Select(port)); 370 return 1; 371 break; 372 case INSN_CONFIG_DIO_INPUT: 373 if (s->type != COMEDI_SUBD_DIO) 374 return -EINVAL; 375 private(dev)->dio_direction[port] = COMEDI_INPUT; 376 writeb(1, private(dev)->mite->daq_io_addr + Port_Select(port)); 377 return 1; 378 break; 379 case INSN_CONFIG_DIO_QUERY: 380 if (s->type != COMEDI_SUBD_DIO) 381 return -EINVAL; 382 data[1] = private(dev)->dio_direction[port]; 383 return insn->n; 384 break; 385 default: 386 break; 387 } 388 return -EINVAL; 389} 390 391static int ni_65xx_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 392 struct comedi_insn * insn, unsigned int * data) 393{ 394 unsigned base_bitfield_channel; 395 const unsigned max_ports_per_bitfield = 5; 396 unsigned read_bits = 0; 397 unsigned j; 398 if (insn->n != 2) 399 return -EINVAL; 400 base_bitfield_channel = CR_CHAN(insn->chanspec); 401 for (j = 0; j < max_ports_per_bitfield; ++j) { 402 const unsigned port = 403 sprivate(s)->base_port + 404 ni_65xx_port_by_channel(base_bitfield_channel) + j; 405 unsigned base_port_channel; 406 unsigned port_mask, port_data, port_read_bits; 407 int bitshift; 408 if (port >= ni_65xx_total_num_ports(board(dev))) 409 break; 410 base_port_channel = port * ni_65xx_channels_per_port; 411 port_mask = data[0]; 412 port_data = data[1]; 413 bitshift = base_port_channel - base_bitfield_channel; 414 if (bitshift >= 32 || bitshift <= -32) 415 break; 416 if (bitshift > 0) { 417 port_mask >>= bitshift; 418 port_data >>= bitshift; 419 } else { 420 port_mask <<= -bitshift; 421 port_data <<= -bitshift; 422 } 423 port_mask &= 0xff; 424 port_data &= 0xff; 425 if (port_mask) { 426 unsigned bits; 427 private(dev)->output_bits[port] &= ~port_mask; 428 private(dev)->output_bits[port] |= 429 port_data & port_mask; 430 bits = private(dev)->output_bits[port]; 431 if (board(dev)->invert_outputs) 432 bits = ~bits; 433 writeb(bits, 434 private(dev)->mite->daq_io_addr + 435 Port_Data(port)); 436// rt_printk("wrote 0x%x to port %i\n", bits, port); 437 } 438 port_read_bits = 439 readb(private(dev)->mite->daq_io_addr + 440 Port_Data(port)); 441// rt_printk("read 0x%x from port %i\n", port_read_bits, port); 442 if (bitshift > 0) { 443 port_read_bits <<= bitshift; 444 } else { 445 port_read_bits >>= -bitshift; 446 } 447 read_bits |= port_read_bits; 448 } 449 data[1] = read_bits; 450 return insn->n; 451} 452 453static irqreturn_t ni_65xx_interrupt(int irq, void *d PT_REGS_ARG) 454{ 455 struct comedi_device *dev = d; 456 struct comedi_subdevice *s = dev->subdevices + 2; 457 unsigned int status; 458 459 status = readb(private(dev)->mite->daq_io_addr + Change_Status); 460 if ((status & MasterInterruptStatus) == 0) 461 return IRQ_NONE; 462 if ((status & EdgeStatus) == 0) 463 return IRQ_NONE; 464 465 writeb(ClrEdge | ClrOverflow, 466 private(dev)->mite->daq_io_addr + Clear_Register); 467 468 comedi_buf_put(s->async, 0); 469 s->async->events |= COMEDI_CB_EOS; 470 comedi_event(dev, s); 471 return IRQ_HANDLED; 472} 473 474static int ni_65xx_intr_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, 475 struct comedi_cmd * cmd) 476{ 477 int err = 0; 478 int tmp; 479 480 /* step 1: make sure trigger sources are trivially valid */ 481 482 tmp = cmd->start_src; 483 cmd->start_src &= TRIG_NOW; 484 if (!cmd->start_src || tmp != cmd->start_src) 485 err++; 486 487 tmp = cmd->scan_begin_src; 488 cmd->scan_begin_src &= TRIG_OTHER; 489 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 490 err++; 491 492 tmp = cmd->convert_src; 493 cmd->convert_src &= TRIG_FOLLOW; 494 if (!cmd->convert_src || tmp != cmd->convert_src) 495 err++; 496 497 tmp = cmd->scan_end_src; 498 cmd->scan_end_src &= TRIG_COUNT; 499 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 500 err++; 501 502 tmp = cmd->stop_src; 503 cmd->stop_src &= TRIG_COUNT; 504 if (!cmd->stop_src || tmp != cmd->stop_src) 505 err++; 506 507 if (err) 508 return 1; 509 510 /* step 2: make sure trigger sources are unique and mutually compatible */ 511 512 if (err) 513 return 2; 514 515 /* step 3: make sure arguments are trivially compatible */ 516 517 if (cmd->start_arg != 0) { 518 cmd->start_arg = 0; 519 err++; 520 } 521 if (cmd->scan_begin_arg != 0) { 522 cmd->scan_begin_arg = 0; 523 err++; 524 } 525 if (cmd->convert_arg != 0) { 526 cmd->convert_arg = 0; 527 err++; 528 } 529 530 if (cmd->scan_end_arg != 1) { 531 cmd->scan_end_arg = 1; 532 err++; 533 } 534 if (cmd->stop_arg != 0) { 535 cmd->stop_arg = 0; 536 err++; 537 } 538 539 if (err) 540 return 3; 541 542 /* step 4: fix up any arguments */ 543 544 if (err) 545 return 4; 546 547 return 0; 548} 549 550static int ni_65xx_intr_cmd(struct comedi_device * dev, struct comedi_subdevice * s) 551{ 552 //struct comedi_cmd *cmd = &s->async->cmd; 553 554 writeb(ClrEdge | ClrOverflow, 555 private(dev)->mite->daq_io_addr + Clear_Register); 556 writeb(FallingEdgeIntEnable | RisingEdgeIntEnable | 557 MasterInterruptEnable | EdgeIntEnable, 558 private(dev)->mite->daq_io_addr + Master_Interrupt_Control); 559 560 return 0; 561} 562 563static int ni_65xx_intr_cancel(struct comedi_device * dev, struct comedi_subdevice * s) 564{ 565 writeb(0x00, 566 private(dev)->mite->daq_io_addr + Master_Interrupt_Control); 567 568 return 0; 569} 570 571static int ni_65xx_intr_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 572 struct comedi_insn * insn, unsigned int * data) 573{ 574 if (insn->n < 1) 575 return -EINVAL; 576 577 data[1] = 0; 578 return 2; 579} 580 581static int ni_65xx_intr_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, 582 struct comedi_insn * insn, unsigned int * data) 583{ 584 if (insn->n < 1) 585 return -EINVAL; 586 if (data[0] != INSN_CONFIG_CHANGE_NOTIFY) 587 return -EINVAL; 588 589 writeb(data[1], 590 private(dev)->mite->daq_io_addr + 591 Rising_Edge_Detection_Enable(0)); 592 writeb(data[1] >> 8, 593 private(dev)->mite->daq_io_addr + 594 Rising_Edge_Detection_Enable(0x10)); 595 writeb(data[1] >> 16, 596 private(dev)->mite->daq_io_addr + 597 Rising_Edge_Detection_Enable(0x20)); 598 writeb(data[1] >> 24, 599 private(dev)->mite->daq_io_addr + 600 Rising_Edge_Detection_Enable(0x30)); 601 602 writeb(data[2], 603 private(dev)->mite->daq_io_addr + 604 Falling_Edge_Detection_Enable(0)); 605 writeb(data[2] >> 8, 606 private(dev)->mite->daq_io_addr + 607 Falling_Edge_Detection_Enable(0x10)); 608 writeb(data[2] >> 16, 609 private(dev)->mite->daq_io_addr + 610 Falling_Edge_Detection_Enable(0x20)); 611 writeb(data[2] >> 24, 612 private(dev)->mite->daq_io_addr + 613 Falling_Edge_Detection_Enable(0x30)); 614 615 return 2; 616} 617 618static int ni_65xx_attach(struct comedi_device * dev, comedi_devconfig * it) 619{ 620 struct comedi_subdevice *s; 621 unsigned i; 622 int ret; 623 624 printk("comedi%d: ni_65xx:", dev->minor); 625 626 if ((ret = alloc_private(dev, sizeof(ni_65xx_private))) < 0) 627 return ret; 628 629 ret = ni_65xx_find_device(dev, it->options[0], it->options[1]); 630 if (ret < 0) 631 return ret; 632 633 ret = mite_setup(private(dev)->mite); 634 if (ret < 0) { 635 printk("error setting up mite\n"); 636 return ret; 637 } 638 639 dev->board_name = board(dev)->name; 640 dev->irq = mite_irq(private(dev)->mite); 641 printk(" %s", dev->board_name); 642 643 printk(" ID=0x%02x", 644 readb(private(dev)->mite->daq_io_addr + ID_Register)); 645 646 if ((ret = alloc_subdevices(dev, 4)) < 0) 647 return ret; 648 649 s = dev->subdevices + 0; 650 if (board(dev)->num_di_ports) { 651 s->type = COMEDI_SUBD_DI; 652 s->subdev_flags = SDF_READABLE; 653 s->n_chan = 654 board(dev)->num_di_ports * ni_65xx_channels_per_port; 655 s->range_table = &range_digital; 656 s->maxdata = 1; 657 s->insn_config = ni_65xx_dio_insn_config; 658 s->insn_bits = ni_65xx_dio_insn_bits; 659 s->private = ni_65xx_alloc_subdevice_private(); 660 if (s->private == NULL) 661 return -ENOMEM; 662 sprivate(s)->base_port = 0; 663 } else { 664 s->type = COMEDI_SUBD_UNUSED; 665 } 666 667 s = dev->subdevices + 1; 668 if (board(dev)->num_do_ports) { 669 s->type = COMEDI_SUBD_DO; 670 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 671 s->n_chan = 672 board(dev)->num_do_ports * ni_65xx_channels_per_port; 673 s->range_table = &range_digital; 674 s->maxdata = 1; 675 s->insn_bits = ni_65xx_dio_insn_bits; 676 s->private = ni_65xx_alloc_subdevice_private(); 677 if (s->private == NULL) 678 return -ENOMEM; 679 sprivate(s)->base_port = board(dev)->num_di_ports; 680 } else { 681 s->type = COMEDI_SUBD_UNUSED; 682 } 683 684 s = dev->subdevices + 2; 685 if (board(dev)->num_dio_ports) { 686 s->type = COMEDI_SUBD_DIO; 687 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 688 s->n_chan = 689 board(dev)->num_dio_ports * ni_65xx_channels_per_port; 690 s->range_table = &range_digital; 691 s->maxdata = 1; 692 s->insn_config = ni_65xx_dio_insn_config; 693 s->insn_bits = ni_65xx_dio_insn_bits; 694 s->private = ni_65xx_alloc_subdevice_private(); 695 if (s->private == NULL) 696 return -ENOMEM; 697 sprivate(s)->base_port = 0; 698 for (i = 0; i < board(dev)->num_dio_ports; ++i) { 699 // configure all ports for input 700 writeb(0x1, 701 private(dev)->mite->daq_io_addr + 702 Port_Select(i)); 703 } 704 } else { 705 s->type = COMEDI_SUBD_UNUSED; 706 } 707 708 s = dev->subdevices + 3; 709 dev->read_subdev = s; 710 s->type = COMEDI_SUBD_DI; 711 s->subdev_flags = SDF_READABLE | SDF_CMD_READ; 712 s->n_chan = 1; 713 s->range_table = &range_unknown; 714 s->maxdata = 1; 715 s->do_cmdtest = ni_65xx_intr_cmdtest; 716 s->do_cmd = ni_65xx_intr_cmd; 717 s->cancel = ni_65xx_intr_cancel; 718 s->insn_bits = ni_65xx_intr_insn_bits; 719 s->insn_config = ni_65xx_intr_insn_config; 720 721 for (i = 0; i < ni_65xx_total_num_ports(board(dev)); ++i) { 722 writeb(0x00, 723 private(dev)->mite->daq_io_addr + Filter_Enable(i)); 724 if (board(dev)->invert_outputs) 725 writeb(0x01, 726 private(dev)->mite->daq_io_addr + Port_Data(i)); 727 else 728 writeb(0x00, 729 private(dev)->mite->daq_io_addr + Port_Data(i)); 730 } 731 writeb(ClrEdge | ClrOverflow, 732 private(dev)->mite->daq_io_addr + Clear_Register); 733 writeb(0x00, 734 private(dev)->mite->daq_io_addr + Master_Interrupt_Control); 735 736 /* Set filter interval to 0 (32bit reg) */ 737 writeb(0x00000000, private(dev)->mite->daq_io_addr + Filter_Interval); 738 739 ret = comedi_request_irq(dev->irq, ni_65xx_interrupt, IRQF_SHARED, 740 "ni_65xx", dev); 741 if (ret < 0) { 742 dev->irq = 0; 743 printk(" irq not available"); 744 } 745 746 printk("\n"); 747 748 return 0; 749} 750 751static int ni_65xx_detach(struct comedi_device * dev) 752{ 753 if (private(dev) && private(dev)->mite 754 && private(dev)->mite->daq_io_addr) { 755 writeb(0x00, 756 private(dev)->mite->daq_io_addr + 757 Master_Interrupt_Control); 758 } 759 760 if (dev->irq) { 761 comedi_free_irq(dev->irq, dev); 762 } 763 764 if (private(dev)) { 765 unsigned i; 766 for (i = 0; i < dev->n_subdevices; ++i) { 767 if (dev->subdevices[i].private) { 768 kfree(dev->subdevices[i].private); 769 dev->subdevices[i].private = NULL; 770 } 771 } 772 if (private(dev)->mite) { 773 mite_unsetup(private(dev)->mite); 774 } 775 } 776 return 0; 777} 778 779static int ni_65xx_find_device(struct comedi_device * dev, int bus, int slot) 780{ 781 struct mite_struct *mite; 782 int i; 783 784 for (mite = mite_devices; mite; mite = mite->next) { 785 if (mite->used) 786 continue; 787 if (bus || slot) { 788 if (bus != mite->pcidev->bus->number || 789 slot != PCI_SLOT(mite->pcidev->devfn)) 790 continue; 791 } 792 for (i = 0; i < n_ni_65xx_boards; i++) { 793 if (mite_device_id(mite) == ni_65xx_boards[i].dev_id) { 794 dev->board_ptr = ni_65xx_boards + i; 795 private(dev)->mite = mite; 796 return 0; 797 } 798 } 799 } 800 printk("no device found\n"); 801 mite_list_devices(); 802 return -EIO; 803} 804 805COMEDI_PCI_INITCLEANUP(driver_ni_65xx, ni_65xx_pci_table); 806