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