ni_daq_700.c revision 2262054e74b4b26ed56a8535c1259f6c6c2862a4
1/* 2 * comedi/drivers/ni_daq_700.c 3 * Driver for DAQCard-700 DIO only 4 * copied from 8255 5 * 6 * COMEDI - Linux Control and Measurement Device Interface 7 * Copyright (C) 1998 David A. Schleef <ds@schleef.org> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 * 23 */ 24 25/* 26Driver: ni_daq_700 27Description: National Instruments PCMCIA DAQCard-700 DIO only 28Author: Fred Brooks <nsaspook@nsaspook.com>, 29 based on ni_daq_dio24 by Daniel Vecino Castel <dvecino@able.es> 30Devices: [National Instruments] PCMCIA DAQ-Card-700 (ni_daq_700) 31Status: works 32Updated: Thu, 21 Feb 2008 12:07:20 +0000 33 34The daqcard-700 appears in Comedi as a single digital I/O subdevice with 3516 channels. The channel 0 corresponds to the daqcard-700's output 36port, bit 0; channel 8 corresponds to the input port, bit 0. 37 38Direction configuration: channels 0-7 output, 8-15 input (8225 device 39emu as port A output, port B input, port C N/A). 40 41IRQ is assigned but not used. 42*/ 43 44#include <linux/interrupt.h> 45#include <linux/slab.h> 46#include "../comedidev.h" 47 48#include <linux/ioport.h> 49 50#include <pcmcia/cistpl.h> 51#include <pcmcia/cisreg.h> 52#include <pcmcia/ds.h> 53 54static struct pcmcia_device *pcmcia_cur_dev = NULL; 55 56#define DIO700_SIZE 8 /* size of io region used by board */ 57 58static int dio700_attach(struct comedi_device *dev, 59 struct comedi_devconfig *it); 60static int dio700_detach(struct comedi_device *dev); 61 62enum dio700_bustype { pcmcia_bustype }; 63 64struct dio700_board { 65 const char *name; 66 int device_id; /* device id for pcmcia board */ 67 enum dio700_bustype bustype; /* PCMCIA */ 68 int have_dio; /* have daqcard-700 dio */ 69 /* function pointers so we can use inb/outb or readb/writeb */ 70 /* as appropriate */ 71 unsigned int (*read_byte) (unsigned int address); 72 void (*write_byte) (unsigned int byte, unsigned int address); 73}; 74 75static const struct dio700_board dio700_boards[] = { 76 { 77 .name = "daqcard-700", 78 /* 0x10b is manufacturer id, 0x4743 is device id */ 79 .device_id = 0x4743, 80 .bustype = pcmcia_bustype, 81 .have_dio = 1, 82 }, 83 { 84 .name = "ni_daq_700", 85 /* 0x10b is manufacturer id, 0x4743 is device id */ 86 .device_id = 0x4743, 87 .bustype = pcmcia_bustype, 88 .have_dio = 1, 89 }, 90}; 91 92/* 93 * Useful for shorthand access to the particular board structure 94 */ 95#define thisboard ((const struct dio700_board *)dev->board_ptr) 96 97struct dio700_private { 98 99 int data; /* number of data points left to be taken */ 100}; 101 102#define devpriv ((struct dio700_private *)dev->private) 103 104static struct comedi_driver driver_dio700 = { 105 .driver_name = "ni_daq_700", 106 .module = THIS_MODULE, 107 .attach = dio700_attach, 108 .detach = dio700_detach, 109 .num_names = ARRAY_SIZE(dio700_boards), 110 .board_name = &dio700_boards[0].name, 111 .offset = sizeof(struct dio700_board), 112}; 113 114/* the real driver routines */ 115 116#define _700_SIZE 8 117 118#define _700_DATA 0 119 120#define DIO_W 0x04 121#define DIO_R 0x05 122 123struct subdev_700_struct { 124 unsigned long cb_arg; 125 int (*cb_func) (int, int, int, unsigned long); 126 int have_irq; 127}; 128 129#define CALLBACK_ARG (((struct subdev_700_struct *)s->private)->cb_arg) 130#define CALLBACK_FUNC (((struct subdev_700_struct *)s->private)->cb_func) 131#define subdevpriv ((struct subdev_700_struct *)s->private) 132 133static void do_config(struct comedi_device *dev, struct comedi_subdevice *s); 134 135void subdev_700_interrupt(struct comedi_device *dev, struct comedi_subdevice *s) 136{ 137 short d; 138 139 d = CALLBACK_FUNC(0, _700_DATA, 0, CALLBACK_ARG); 140 141 comedi_buf_put(s->async, d); 142 s->async->events |= COMEDI_CB_EOS; 143 144 comedi_event(dev, s); 145} 146EXPORT_SYMBOL(subdev_700_interrupt); 147 148static int subdev_700_cb(int dir, int port, int data, unsigned long arg) 149{ 150 /* port is always A for output and B for input (8255 emu) */ 151 unsigned long iobase = arg; 152 153 if (dir) { 154 outb(data, iobase + DIO_W); 155 return 0; 156 } else { 157 return inb(iobase + DIO_R); 158 } 159} 160 161static int subdev_700_insn(struct comedi_device *dev, 162 struct comedi_subdevice *s, struct comedi_insn *insn, 163 unsigned int *data) 164{ 165 if (data[0]) { 166 s->state &= ~data[0]; 167 s->state |= (data[0] & data[1]); 168 169 if (data[0] & 0xff) 170 CALLBACK_FUNC(1, _700_DATA, s->state & 0xff, 171 CALLBACK_ARG); 172 } 173 174 data[1] = s->state & 0xff; 175 data[1] |= CALLBACK_FUNC(0, _700_DATA, 0, CALLBACK_ARG) << 8; 176 177 return 2; 178} 179 180static int subdev_700_insn_config(struct comedi_device *dev, 181 struct comedi_subdevice *s, 182 struct comedi_insn *insn, unsigned int *data) 183{ 184 185 switch (data[0]) { 186 case INSN_CONFIG_DIO_INPUT: 187 break; 188 case INSN_CONFIG_DIO_OUTPUT: 189 break; 190 case INSN_CONFIG_DIO_QUERY: 191 data[1] = 192 (s-> 193 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : 194 COMEDI_INPUT; 195 return insn->n; 196 break; 197 default: 198 return -EINVAL; 199 } 200 201 return 1; 202} 203 204static void do_config(struct comedi_device *dev, struct comedi_subdevice *s) 205{ /* use powerup defaults */ 206 return; 207} 208 209static int subdev_700_cmdtest(struct comedi_device *dev, 210 struct comedi_subdevice *s, 211 struct comedi_cmd *cmd) 212{ 213 int err = 0; 214 unsigned int tmp; 215 216 /* step 1 */ 217 218 tmp = cmd->start_src; 219 cmd->start_src &= TRIG_NOW; 220 if (!cmd->start_src || tmp != cmd->start_src) 221 err++; 222 223 tmp = cmd->scan_begin_src; 224 cmd->scan_begin_src &= TRIG_EXT; 225 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 226 err++; 227 228 tmp = cmd->convert_src; 229 cmd->convert_src &= TRIG_FOLLOW; 230 if (!cmd->convert_src || tmp != cmd->convert_src) 231 err++; 232 233 tmp = cmd->scan_end_src; 234 cmd->scan_end_src &= TRIG_COUNT; 235 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 236 err++; 237 238 tmp = cmd->stop_src; 239 cmd->stop_src &= TRIG_NONE; 240 if (!cmd->stop_src || tmp != cmd->stop_src) 241 err++; 242 243 if (err) 244 return 1; 245 246 /* step 2 */ 247 248 if (err) 249 return 2; 250 251 /* step 3 */ 252 253 if (cmd->start_arg != 0) { 254 cmd->start_arg = 0; 255 err++; 256 } 257 if (cmd->scan_begin_arg != 0) { 258 cmd->scan_begin_arg = 0; 259 err++; 260 } 261 if (cmd->convert_arg != 0) { 262 cmd->convert_arg = 0; 263 err++; 264 } 265 if (cmd->scan_end_arg != 1) { 266 cmd->scan_end_arg = 1; 267 err++; 268 } 269 if (cmd->stop_arg != 0) { 270 cmd->stop_arg = 0; 271 err++; 272 } 273 274 if (err) 275 return 3; 276 277 /* step 4 */ 278 279 if (err) 280 return 4; 281 282 return 0; 283} 284 285static int subdev_700_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 286{ 287 /* FIXME */ 288 289 return 0; 290} 291 292static int subdev_700_cancel(struct comedi_device *dev, 293 struct comedi_subdevice *s) 294{ 295 /* FIXME */ 296 297 return 0; 298} 299 300int subdev_700_init(struct comedi_device *dev, struct comedi_subdevice *s, 301 int (*cb) (int, int, int, unsigned long), unsigned long arg) 302{ 303 s->type = COMEDI_SUBD_DIO; 304 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 305 s->n_chan = 16; 306 s->range_table = &range_digital; 307 s->maxdata = 1; 308 309 s->private = kmalloc(sizeof(struct subdev_700_struct), GFP_KERNEL); 310 if (!s->private) 311 return -ENOMEM; 312 313 CALLBACK_ARG = arg; 314 if (cb == NULL) 315 CALLBACK_FUNC = subdev_700_cb; 316 else 317 CALLBACK_FUNC = cb; 318 319 s->insn_bits = subdev_700_insn; 320 s->insn_config = subdev_700_insn_config; 321 322 s->state = 0; 323 s->io_bits = 0x00ff; 324 do_config(dev, s); 325 326 return 0; 327} 328EXPORT_SYMBOL(subdev_700_init); 329 330int subdev_700_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, 331 int (*cb) (int, int, int, unsigned long), 332 unsigned long arg) 333{ 334 int ret; 335 336 ret = subdev_700_init(dev, s, cb, arg); 337 if (ret < 0) 338 return ret; 339 340 s->do_cmdtest = subdev_700_cmdtest; 341 s->do_cmd = subdev_700_cmd; 342 s->cancel = subdev_700_cancel; 343 344 subdevpriv->have_irq = 1; 345 346 return 0; 347} 348EXPORT_SYMBOL(subdev_700_init_irq); 349 350void subdev_700_cleanup(struct comedi_device *dev, struct comedi_subdevice *s) 351{ 352 if (s->private) 353 if (subdevpriv->have_irq) 354 355 kfree(s->private); 356} 357EXPORT_SYMBOL(subdev_700_cleanup); 358 359static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it) 360{ 361 struct comedi_subdevice *s; 362 unsigned long iobase = 0; 363#ifdef incomplete 364 unsigned int irq = 0; 365#endif 366 struct pcmcia_device *link; 367 368 /* allocate and initialize dev->private */ 369 if (alloc_private(dev, sizeof(struct dio700_private)) < 0) 370 return -ENOMEM; 371 372 /* get base address, irq etc. based on bustype */ 373 switch (thisboard->bustype) { 374 case pcmcia_bustype: 375 link = pcmcia_cur_dev; /* XXX hack */ 376 if (!link) 377 return -EIO; 378 iobase = link->resource[0]->start; 379#ifdef incomplete 380 irq = link->irq; 381#endif 382 break; 383 default: 384 printk("bug! couldn't determine board type\n"); 385 return -EINVAL; 386 break; 387 } 388 printk("comedi%d: ni_daq_700: %s, io 0x%lx", dev->minor, 389 thisboard->name, iobase); 390#ifdef incomplete 391 if (irq) 392 printk(", irq %u", irq); 393 394#endif 395 396 printk("\n"); 397 398 if (iobase == 0) { 399 printk("io base address is zero!\n"); 400 return -EINVAL; 401 } 402 403 dev->iobase = iobase; 404 405#ifdef incomplete 406 /* grab our IRQ */ 407 dev->irq = irq; 408#endif 409 410 dev->board_name = thisboard->name; 411 412 if (alloc_subdevices(dev, 1) < 0) 413 return -ENOMEM; 414 415 /* DAQCard-700 dio */ 416 s = dev->subdevices + 0; 417 subdev_700_init(dev, s, NULL, dev->iobase); 418 419 return 0; 420}; 421 422static int dio700_detach(struct comedi_device *dev) 423{ 424 printk("comedi%d: ni_daq_700: cs-remove\n", dev->minor); 425 426 if (dev->subdevices) 427 subdev_700_cleanup(dev, dev->subdevices + 0); 428 429 if (thisboard->bustype != pcmcia_bustype && dev->iobase) 430 release_region(dev->iobase, DIO700_SIZE); 431 if (dev->irq) 432 free_irq(dev->irq, dev); 433 434 return 0; 435}; 436 437static void dio700_config(struct pcmcia_device *link); 438static void dio700_release(struct pcmcia_device *link); 439static int dio700_cs_suspend(struct pcmcia_device *p_dev); 440static int dio700_cs_resume(struct pcmcia_device *p_dev); 441 442static int dio700_cs_attach(struct pcmcia_device *); 443static void dio700_cs_detach(struct pcmcia_device *); 444 445struct local_info_t { 446 struct pcmcia_device *link; 447 int stop; 448 struct bus_operations *bus; 449}; 450 451static int dio700_cs_attach(struct pcmcia_device *link) 452{ 453 struct local_info_t *local; 454 455 printk(KERN_INFO "ni_daq_700: cs-attach\n"); 456 457 dev_dbg(&link->dev, "dio700_cs_attach()\n"); 458 459 /* Allocate space for private device-specific data */ 460 local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); 461 if (!local) 462 return -ENOMEM; 463 local->link = link; 464 link->priv = local; 465 466 pcmcia_cur_dev = link; 467 468 dio700_config(link); 469 470 return 0; 471} /* dio700_cs_attach */ 472 473static void dio700_cs_detach(struct pcmcia_device *link) 474{ 475 476 printk(KERN_INFO "ni_daq_700: cs-detach!\n"); 477 478 dev_dbg(&link->dev, "dio700_cs_detach\n"); 479 480 ((struct local_info_t *)link->priv)->stop = 1; 481 dio700_release(link); 482 483 /* This points to the parent struct local_info_t struct */ 484 kfree(link->priv); 485 486} /* dio700_cs_detach */ 487 488static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev, 489 void *priv_data) 490{ 491 if (p_dev->config_index == 0) 492 return -EINVAL; 493 494 return pcmcia_request_io(p_dev); 495} 496 497static void dio700_config(struct pcmcia_device *link) 498{ 499 win_req_t req; 500 int ret; 501 502 printk(KERN_INFO "ni_daq_700: cs-config\n"); 503 504 dev_dbg(&link->dev, "dio700_config\n"); 505 506 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO | 507 CONF_AUTO_SET_IO; 508 509 ret = pcmcia_loop_config(link, dio700_pcmcia_config_loop, NULL); 510 if (ret) { 511 dev_warn(&link->dev, "no configuration found\n"); 512 goto failed; 513 } 514 515 if (!link->irq) 516 goto failed; 517 518 ret = pcmcia_enable_device(link); 519 if (ret != 0) 520 goto failed; 521 522 return; 523 524failed: 525 printk(KERN_INFO "ni_daq_700 cs failed"); 526 dio700_release(link); 527 528} /* dio700_config */ 529 530static void dio700_release(struct pcmcia_device *link) 531{ 532 dev_dbg(&link->dev, "dio700_release\n"); 533 534 pcmcia_disable_device(link); 535} /* dio700_release */ 536 537static int dio700_cs_suspend(struct pcmcia_device *link) 538{ 539 struct local_info_t *local = link->priv; 540 541 /* Mark the device as stopped, to block IO until later */ 542 local->stop = 1; 543 return 0; 544} /* dio700_cs_suspend */ 545 546static int dio700_cs_resume(struct pcmcia_device *link) 547{ 548 struct local_info_t *local = link->priv; 549 550 local->stop = 0; 551 return 0; 552} /* dio700_cs_resume */ 553 554/*====================================================================*/ 555 556static struct pcmcia_device_id dio700_cs_ids[] = { 557 /* N.B. These IDs should match those in dio700_boards */ 558 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743), /* daqcard-700 */ 559 PCMCIA_DEVICE_NULL 560}; 561 562 563MODULE_DEVICE_TABLE(pcmcia, dio700_cs_ids); 564MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>"); 565MODULE_DESCRIPTION("Comedi driver for National Instruments " 566 "PCMCIA DAQCard-700 DIO"); 567MODULE_LICENSE("GPL"); 568 569struct pcmcia_driver dio700_cs_driver = { 570 .probe = dio700_cs_attach, 571 .remove = dio700_cs_detach, 572 .suspend = dio700_cs_suspend, 573 .resume = dio700_cs_resume, 574 .id_table = dio700_cs_ids, 575 .owner = THIS_MODULE, 576 .name = "ni_daq_700", 577}; 578 579static int __init init_dio700_cs(void) 580{ 581 pcmcia_register_driver(&dio700_cs_driver); 582 return 0; 583} 584 585static void __exit exit_dio700_cs(void) 586{ 587 pr_debug("ni_daq_700: unloading\n"); 588 pcmcia_unregister_driver(&dio700_cs_driver); 589} 590 591int __init init_module(void) 592{ 593 int ret; 594 595 ret = init_dio700_cs(); 596 if (ret < 0) 597 return ret; 598 599 return comedi_driver_register(&driver_dio700); 600} 601 602void __exit cleanup_module(void) 603{ 604 exit_dio700_cs(); 605 comedi_driver_unregister(&driver_dio700); 606} 607