vmk80xx.c revision 3faad67335e16863b2a143a61eedb5ac055c74c6
1/* 2 comedi/drivers/vmk80xx.c 3 Velleman USB Interface Board Kernel-Space Driver 4 5 Copyright (C) 2009 Manuel Gebele <forensixs@gmx.de>, Germany 6 7 COMEDI - Linux Control and Measurement Device Interface 8 Copyright (C) 2000 David A. Schleef <ds@schleef.org> 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 2 of the License, or 13 (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program; if not, write to the Free Software 22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 24*/ 25/* 26Driver: vmk80xx 27Description: Velleman USB Interface Board Kernel-Space Driver 28Devices: K8055, K8061 (in development) 29Author: Manuel Gebele <forensixs@gmx.de> 30Updated: Tue, 21 Apr 2009 19:40:55 +0200 31Status: works 32*/ 33 34#include <linux/kernel.h> 35#include <linux/comedidev.h> /* comedi definitions */ 36#include <linux/module.h> 37#include <linux/mutex.h> 38#include <linux/errno.h> 39#include <linux/input.h> 40#include <linux/slab.h> 41#include <linux/poll.h> 42#include <linux/usb.h> 43#include <asm/uaccess.h> 44 45/* ------------------------------------------------------------------------ */ 46#define VMK80XX_MODULE_DESC "Velleman USB Interface Board Kernel-Space Driver" 47#define VMK80XX_MODULE_DEVICE "Velleman K8055/K8061 USB Interface Board" 48#define VMK80XX_MODULE_AUTHOR "Copyright (C) 2009 Manuel Gebele, Germany" 49#define VMK80XX_MODULE_LICENSE "GPL" 50#define VMK80XX_MODULE_VERSION "0.7.76" 51 52/* Module device ID's */ 53static struct usb_device_id vm_id_table[] = { 54 /* k8055 */ 55 { USB_DEVICE(0x10cf, 0x5500 + 0x00) }, /* @ddr. 0 */ 56 { USB_DEVICE(0x10cf, 0x5500 + 0x01) }, /* @ddr. 1 */ 57 { USB_DEVICE(0x10cf, 0x5500 + 0x02) }, /* @ddr. 2 */ 58 { USB_DEVICE(0x10cf, 0x5500 + 0x03) }, /* @ddr. 3 */ 59 /* k8061 */ 60 { USB_DEVICE(0x10cf, 0x8061 + 0x00) }, /* @ddr. 0 */ 61 { USB_DEVICE(0x10cf, 0x8061 + 0x01) }, /* @ddr. 1 */ 62 { USB_DEVICE(0x10cf, 0x8061 + 0x02) }, /* @ddr. 2 */ 63 { USB_DEVICE(0x10cf, 0x8061 + 0x03) }, /* @ddr. 3 */ 64 { USB_DEVICE(0x10cf, 0x8061 + 0x04) }, /* @ddr. 4 */ 65 { USB_DEVICE(0x10cf, 0x8061 + 0x05) }, /* @ddr. 5 */ 66 { USB_DEVICE(0x10cf, 0x8061 + 0x06) }, /* @ddr. 6 */ 67 { USB_DEVICE(0x10cf, 0x8061 + 0x07) }, /* @ddr. 7 */ 68 { } /* terminating entry */ 69}; 70MODULE_DEVICE_TABLE(usb, vm_id_table); 71 72MODULE_AUTHOR(VMK80XX_MODULE_AUTHOR); 73MODULE_DESCRIPTION(VMK80XX_MODULE_DESC); 74MODULE_SUPPORTED_DEVICE(VMK80XX_MODULE_DEVICE); 75MODULE_VERSION(VMK80XX_MODULE_VERSION); 76MODULE_LICENSE(VMK80XX_MODULE_LICENSE); 77/* ------------------------------------------------------------------------ */ 78 79#define CONFIG_VMK80XX_DEBUG 80 81//#undef CONFIG_COMEDI_DEBUG /* Uncommend this line to disable comedi debug */ 82#undef CONFIG_VMK80XX_DEBUG /* Commend this line to enable vmk80xx debug */ 83 84#ifdef CONFIG_COMEDI_DEBUG 85 static int cm_dbg = 1; 86#else /* !CONFIG_COMEDI_DEBUG */ 87 static int cm_dbg = 0; 88#endif /* !CONFIG_COMEDI_DEBUG */ 89 90#ifdef CONFIG_VMK80XX_DEBUG 91 static int vm_dbg = 1; 92#else /* !CONFIG_VMK80XX_DEBUG */ 93 static int vm_dbg = 0; 94#endif /* !CONFIG_VMK80XX_DEBUG */ 95 96/* Define our own debug macros */ 97#define DBGCM(fmt, arg...) do { if (cm_dbg) printk(fmt, ##arg); } while (0) 98#define DBGVM(fmt, arg...) do { if (vm_dbg) printk(fmt, ##arg); } while (0) 99 100/* Velleman K8055 specific stuff */ 101#define VMK8055_DI 0 /* digital input offset */ 102#define VMK8055_DO 1 /* digital output offset */ 103#define VMK8055_AO1 2 /* analog output channel 1 offset */ 104#define VMK8055_AO2 3 /* analog output channel 2 offset */ 105#define VMK8055_CNT1 4 /* counter 1 offset */ 106#define VMK8055_CNT2 6 /* counter 2 offset */ 107#define VMK8055_CMD_RST 0x00 /* reset device registers */ 108#define VMK8055_CMD_DEB1 0x01 /* debounce time for pulse counter 1 */ 109#define VMK8055_CMD_DEB2 0x02 /* debounce time for pulse counter 2 */ 110#define VMK8055_CMD_RST_CNT1 0x03 /* reset pulse counter 1 */ 111#define VMK8055_CMD_RST_CNT2 0x04 /* reset pulse counter 2 */ 112#define VMK8055_CMD_AD 0x05 /* write to analog or digital channel */ 113#define VMK8055_EP_OUT 0x01 /* out endpoint address */ 114#define VMK8055_EP_IN 0x81 /* in endpoint address */ 115#define VMK8055_EP_SIZE 8 /* endpoint max packet size */ 116#define VMK8055_EP_INTERVAL 20 /* general conversion time per command */ 117#define VMK8055_MAX_BOARDS 16 118 119/* Structure to hold all of our device specific stuff */ 120struct vmk80xx_usb { 121 struct usb_interface *intf; 122 struct semaphore limit_sem; 123 wait_queue_head_t read_wait; 124 wait_queue_head_t write_wait; 125 size_t irq_out_endpoint_size; 126 __u8 irq_out_endpoint; 127 int irq_out_interval; 128 unsigned char *irq_out_buf; 129 struct urb *irq_out_urb; 130 int irq_out_busy; 131 size_t irq_in_endpoint_size; 132 __u8 irq_in_endpoint; 133 int irq_in_interval; 134 unsigned char *irq_in_buf; 135 struct urb *irq_in_urb; 136 int irq_in_busy; 137 int irq_in_running; 138 int probed; 139 int attached; 140 int id; 141}; 142 143static struct vmk80xx_usb vm_boards[VMK8055_MAX_BOARDS]; 144 145/* --------------------------------------------------------------------------- 146 * Abort active transfers and tidy up allocated resources. 147--------------------------------------------------------------------------- */ 148static void vm_abort_transfers(struct vmk80xx_usb *vm) 149{ 150 DBGVM("comedi#: vmk80xx: %s\n", __func__); 151 152 if (vm->irq_in_running) { 153 vm->irq_in_running = 0; 154 if (vm->intf) 155 usb_kill_urb(vm->irq_in_urb); 156 } 157 158 if (vm->irq_out_busy && vm->intf) 159 usb_kill_urb(vm->irq_out_urb); 160} 161 162static void vm_delete(struct vmk80xx_usb *vm) 163{ 164 DBGVM("comedi#: vmk80xx: %s\n", __func__); 165 166 vm_abort_transfers(vm); 167 168 /* Deallocate usb urbs and kernel buffers */ 169 if (vm->irq_in_urb) 170 usb_free_urb(vm->irq_in_urb); 171 172 if (vm->irq_out_urb); 173 usb_free_urb(vm->irq_out_urb); 174 175 if (vm->irq_in_buf) 176 kfree(vm->irq_in_buf); 177 178 if (vm->irq_out_buf) 179 kfree(vm->irq_out_buf); 180} 181 182/* --------------------------------------------------------------------------- 183 * Interrupt in and interrupt out callback for usb data transfer. 184--------------------------------------------------------------------------- */ 185static void vm_irq_in_callback(struct urb *urb) 186{ 187 struct vmk80xx_usb *vm = (struct vmk80xx_usb *)urb->context; 188 int err; 189 190 DBGVM("comedi#: vmk80xx: %s\n", __func__); 191 192 switch (urb->status) { 193 case 0: /* success */ 194 break; 195 case -ENOENT: 196 case -ECONNRESET: 197 case -ESHUTDOWN: 198 break; 199 default: 200 DBGCM("comedi#: vmk80xx: %s - nonzero urb status (%d)\n", 201 __func__, urb->status); 202 goto resubmit; /* maybe we can recover */ 203 } 204 205 goto exit; 206resubmit: 207 if (vm->irq_in_running && vm->intf) { 208 err = usb_submit_urb(vm->irq_in_urb, GFP_ATOMIC); 209 if (!err) goto exit; 210 /* FALL THROUGH */ 211 DBGCM("comedi#: vmk80xx: %s - submit urb failed (err# %d)\n", 212 __func__, err); 213 } 214exit: 215 vm->irq_in_busy = 0; 216 217 /* interrupt-in pipe is available again */ 218 wake_up_interruptible(&vm->read_wait); 219} 220 221static void vm_irq_out_callback(struct urb *urb) 222{ 223 struct vmk80xx_usb *vm; 224 225 DBGVM("comedi#: vmk80xx: %s\n", __func__); 226 227 /* sync/async unlink (hardware going away) faults aren't errors */ 228 if (urb->status && !(urb->status == -ENOENT 229 || urb->status == -ECONNRESET 230 || urb->status == -ESHUTDOWN)) 231 DBGCM("comedi#: vmk80xx: %s - nonzero urb status (%d)\n", 232 __func__, urb->status); 233 234 vm = (struct vmk80xx_usb *)urb->context; 235 vm->irq_out_busy = 0; 236 237 /* interrupt-out pipe is available again */ 238 wake_up_interruptible(&vm->write_wait); 239} 240 241/* --------------------------------------------------------------------------- 242 * Interface for digital/analog input/output and counter funcs (see below). 243--------------------------------------------------------------------------- */ 244static int vm_read(struct vmk80xx_usb *vm) 245{ 246 struct usb_device *udev; 247 int retval = -ENODEV; 248 249 DBGVM("comedi#: vmk80xx: %s\n", __func__); 250 251 /* Verify that the device wasn't un-plugged */ 252 if (!vm->intf) { 253 DBGCM("comedi#: vmk80xx: %s - No dev or dev un-plugged\n", 254 __func__); 255 goto exit; 256 } 257 258 if (vm->irq_in_busy) { 259 retval = wait_event_interruptible(vm->read_wait, 260 !vm->irq_in_busy); 261 if (retval < 0) { /* we were interrupted by a signal */ 262 retval = -ERESTART; 263 goto exit; 264 } 265 } 266 267 udev = interface_to_usbdev(vm->intf); 268 269 /* Fill the urb and send off */ 270 usb_fill_int_urb(vm->irq_in_urb, 271 udev, 272 usb_rcvintpipe(udev, vm->irq_in_endpoint), 273 vm->irq_in_buf, 274 vm->irq_in_endpoint_size, 275 vm_irq_in_callback, 276 vm, 277 vm->irq_in_interval); 278 279 vm->irq_in_running = 1; 280 vm->irq_in_busy = 1; /* disallow following read request's */ 281 282 retval = usb_submit_urb(vm->irq_in_urb, GFP_KERNEL); 283 if (!retval) goto exit; /* success */ 284 /* FALL TROUGH */ 285 vm->irq_in_running = 0; 286 DBGCM("comedi#: vmk80xx: %s - submit urb failed (err# %d)\n", 287 __func__, retval); 288 289exit: 290 return retval; 291} 292 293static int vm_write(struct vmk80xx_usb *vm, unsigned char cmd) 294{ 295 struct usb_device *udev; 296 int retval = -ENODEV; 297 298 DBGVM("comedi#: vmk80xx: %s\n", __func__); 299 300 /* Verify that the device wasn't un-plugged */ 301 if (!vm->intf) { 302 DBGCM("comedi#: vmk80xx: %s - No dev or dev un-plugged\n", 303 __func__); 304 goto exit; 305 } 306 307 if (vm->irq_out_busy) { 308 retval = wait_event_interruptible(vm->write_wait, 309 !vm->irq_out_busy); 310 if (retval < 0) { /* we were interrupted by a signal */ 311 retval = -ERESTART; 312 goto exit; 313 } 314 } 315 316 udev = interface_to_usbdev(vm->intf); 317 318 /* Set the command which should send to the device */ 319 vm->irq_out_buf[0] = cmd; 320 321 /* Fill the urb and send off */ 322 usb_fill_int_urb(vm->irq_out_urb, 323 udev, 324 usb_sndintpipe(udev, vm->irq_out_endpoint), 325 vm->irq_out_buf, 326 vm->irq_out_endpoint_size, 327 vm_irq_out_callback, 328 vm, 329 vm->irq_out_interval); 330 331 vm->irq_out_busy = 1; /* disallow following write request's */ 332 333 wmb(); 334 335 retval = usb_submit_urb(vm->irq_out_urb, GFP_KERNEL); 336 if (!retval) goto exit; /* success */ 337 /* FALL THROUGH */ 338 vm->irq_out_busy = 0; 339 DBGCM("comedi#: vmk80xx: %s - submit urb failed (err# %d)\n", 340 __func__, retval); 341 342exit: 343 return retval; 344} 345 346/* --------------------------------------------------------------------------- 347 * COMEDI-Interface (callback functions for the userspacs apps). 348--------------------------------------------------------------------------- */ 349static int vm_ai_rinsn(comedi_device *dev, comedi_subdevice *s, 350 comedi_insn *insn, unsigned int *data) 351{ 352 struct vmk80xx_usb *vm; 353 int minor = dev->minor; 354 int ch, ch_offs, i; 355 int retval = -EFAULT; 356 357 DBGVM("comedi%d: vmk80xx: %s\n", minor, __func__); 358 359 if (!(vm = (struct vmk80xx_usb *)dev->private)) 360 return retval; 361 362 down(&vm->limit_sem); 363 364 /* We have an attached board ? */ 365 if (!vm->probed) { 366 retval = -ENODEV; 367 goto error; 368 } 369 370 /* interrupt-in pipe busy ? */ 371 if (vm->irq_in_busy) { 372 retval = -EBUSY; 373 goto error; 374 } 375 376 ch = CR_CHAN(insn->chanspec); 377 ch_offs = (!ch) ? VMK8055_AO1 : VMK8055_AO2; 378 379 for (i = 0; i < insn->n; i++) { 380 retval = vm_read(vm); 381 if (retval) 382 goto error; 383 384 /* NOTE: 385 * The input voltage of the selected 8-bit AD channel 386 * is converted to a value which lies between 387 * 0 and 255. 388 */ 389 data[i] = vm->irq_in_buf[ch_offs]; 390 } 391 392 up(&vm->limit_sem); 393 394 /* Return the number of samples read */ 395 return i; 396error: 397 up(&vm->limit_sem); 398 399 return retval; 400} 401 402static int vm_ao_winsn(comedi_device *dev, comedi_subdevice *s, 403 comedi_insn *insn, unsigned int *data) 404{ 405 struct vmk80xx_usb *vm; 406 int minor = dev->minor; 407 int ch, ch_offs, i; 408 int retval = -EFAULT; 409 410 DBGVM("comedi%d: vmk80xx: %s\n", minor, __func__); 411 412 if (!(vm = (struct vmk80xx_usb *)dev->private)) 413 return retval; 414 415 down(&vm->limit_sem); 416 417 /* We have an attached board ? */ 418 if (!vm->probed) { 419 retval = -ENODEV; 420 goto error; 421 } 422 423 /* interrupt-out pipe busy ? */ 424 if (vm->irq_out_busy) { 425 retval = -EBUSY; 426 goto error; 427 } 428 429 ch = CR_CHAN(insn->chanspec); 430 ch_offs = (!ch) ? VMK8055_AO1 : VMK8055_AO2; 431 432 for (i = 0; i < insn->n; i++) { 433 /* NOTE: 434 * The indicated 8-bit DA channel is altered according 435 * to the new data. This means that the data corresponds 436 * to a specific voltage. The value 0 corresponds to a 437 * minimum output voltage (+-0 Volt) and the value 255 438 * corresponds to a maximum output voltage (+5 Volt). 439 */ 440 vm->irq_out_buf[ch_offs] = data[i]; 441 442 retval = vm_write(vm, VMK8055_CMD_AD); 443 if (retval) 444 goto error; 445 } 446 447 up(&vm->limit_sem); 448 449 /* Return the number of samples write */ 450 return i; 451error: 452 up(&vm->limit_sem); 453 454 return retval; 455} 456 457static int vm_di_rinsn(comedi_device *dev, comedi_subdevice *s, 458 comedi_insn *insn, unsigned int *data) 459{ 460 struct vmk80xx_usb *vm; 461 int minor = dev->minor; 462 int ch, i, inp; 463 int retval = -EFAULT; 464 465 DBGVM("comedi%d: vmk80xx: %s\n", minor, __func__); 466 467 if (!(vm = (struct vmk80xx_usb *)dev->private)) 468 return retval; 469 470 down(&vm->limit_sem); 471 472 /* We have an attached board ? */ 473 if (!vm->probed) { 474 retval = -ENODEV; 475 goto error; 476 } 477 478 /* interrupt-in pipe busy ? */ 479 if (vm->irq_in_busy) { 480 retval = -EBUSY; 481 goto error; 482 } 483 484 for (i = 0, ch = CR_CHAN(insn->chanspec); i < insn->n; i++) { 485 retval = vm_read(vm); 486 if (retval) 487 goto error; 488 489 /* NOTE: 490 * The status of the selected digital input channel is read. 491 */ 492 inp = (((vm->irq_in_buf[VMK8055_DI] >> 4) & 0x03) | 493 ((vm->irq_in_buf[VMK8055_DI] << 2) & 0x04) | 494 ((vm->irq_in_buf[VMK8055_DI] >> 3) & 0x18)); 495 data[i] = ((inp & (1 << ch)) > 0); 496 } 497 498 up(&vm->limit_sem); 499 500 return i; 501error: 502 up(&vm->limit_sem); 503 504 return retval; 505} 506 507static int vm_do_winsn(comedi_device *dev, comedi_subdevice *s, 508 comedi_insn *insn, unsigned int *data) 509{ 510 struct vmk80xx_usb *vm; 511 int minor = dev->minor; 512 int ch, i, mask; 513 int retval = -EFAULT; 514 515 DBGVM("comedi%d: vmk80xx: %s\n", minor, __func__); 516 517 if (!(vm = (struct vmk80xx_usb *)dev->private)) 518 return retval; 519 520 down(&vm->limit_sem); 521 522 /* We have an attached board ? */ 523 if (!vm->probed) { 524 retval = -ENODEV; 525 goto error; 526 } 527 528 /* interrupt-out pipe busy ? */ 529 if (vm->irq_out_busy) { 530 retval = -EBUSY; 531 goto error; 532 } 533 534 for (i = 0, ch = CR_CHAN(insn->chanspec); i < insn->n; i++) { 535 /* NOTE: 536 * The selected digital output channel is set or cleared. 537 */ 538 mask = (data[i] == 1) 539 ? vm->irq_out_buf[VMK8055_DO] | (1 << ch) 540 : vm->irq_out_buf[VMK8055_DO] ^ (1 << ch); 541 542 vm->irq_out_buf[VMK8055_DO] = mask; 543 544 retval = vm_write(vm, VMK8055_CMD_AD); 545 if (retval) 546 goto error; 547 } 548 549 up(&vm->limit_sem); 550 551 return i; 552error: 553 up(&vm->limit_sem); 554 555 return retval; 556} 557 558static int vm_cnt_rinsn(comedi_device *dev, comedi_subdevice *s, 559 comedi_insn *insn, unsigned int *data) 560{ 561 struct vmk80xx_usb *vm; 562 int minor = dev->minor; 563 int cnt, cnt_offs, i; 564 int retval = -EFAULT; 565 566 DBGVM("comedi%d: vmk80xx: %s\n", minor, __func__); 567 568 if (!(vm = (struct vmk80xx_usb *)dev->private)) 569 return retval; 570 571 down(&vm->limit_sem); 572 573 /* We have an attached board ? */ 574 if (!vm->probed) { 575 retval = -ENODEV; 576 goto error; 577 } 578 579 /* interrupt-in pipe busy ? */ 580 if (vm->irq_in_busy) { 581 retval = -EBUSY; 582 goto error; 583 } 584 585 cnt = CR_CHAN(insn->chanspec); 586 cnt_offs = (!cnt) ? VMK8055_CNT1 : VMK8055_CNT2; 587 588 for (i = 0; i < insn->n; i++) { 589 retval = vm_read(vm); 590 if (retval) 591 goto error; 592 593 /* NOTE: 594 * The status of the selected 16-bit pulse counter is 595 * read. The counter # 1 counts the pulses fed to the 596 * input Inp1 and the counter # 2 counts the pulses fed 597 * to the input Inp2. 598 */ 599 data[i] = vm->irq_in_buf[cnt_offs]; 600 } 601 602 up(&vm->limit_sem); 603 604 return i; 605error: 606 up(&vm->limit_sem); 607 608 return retval; 609} 610 611static int vm_cnt_winsn(comedi_device *dev, comedi_subdevice *s, 612 comedi_insn *insn, unsigned int *data) 613{ 614 struct vmk80xx_usb *vm; 615 int minor = dev->minor; 616 int cnt, cnt_offs, cmd, i; 617 int retval = -EFAULT; 618 619 DBGVM("comedi%d: vmk80xx: %s\n", minor, __func__); 620 621 if (!(vm = (struct vmk80xx_usb *)dev->private)) 622 return retval; 623 624 down(&vm->limit_sem); 625 626 /* We have an attached board ? */ 627 if (!vm->probed) { 628 retval = -ENODEV; 629 goto error; 630 } 631 632 /* interrupt-out pipe busy ? */ 633 if (vm->irq_out_busy) { 634 retval = -EBUSY; 635 goto error; 636 } 637 638 cnt = CR_CHAN(insn->chanspec); 639 cnt_offs = (!cnt) ? VMK8055_CNT1 : VMK8055_CNT2; 640 cmd = (!cnt) ? VMK8055_CMD_RST_CNT1 : VMK8055_CMD_RST_CNT2; 641 642 for (i = 0; i < insn->n; i++) { 643 /* NOTE: 644 * The selected 16-bit pulse counter is reset. 645 */ 646 vm->irq_out_buf[cnt_offs] = 0x00; 647 648 retval = vm_write(vm, cmd); 649 if (retval) 650 goto error; 651 } 652 653 up(&vm->limit_sem); 654 655 return i; 656error: 657 up(&vm->limit_sem); 658 659 return retval; 660} 661 662static int vm_cnt_cinsn(comedi_device *dev, comedi_subdevice *s, 663 comedi_insn *insn, unsigned int *data) 664{ 665 struct vmk80xx_usb *vm; 666 int minor = dev->minor; 667 int cnt, cmd, i; 668 unsigned int debtime, val; 669 int retval = -EFAULT; 670 671 DBGVM("comedi%d: vmk80xx: %s\n", minor, __func__); 672 673 if (!(vm = (struct vmk80xx_usb *)dev->private)) 674 return retval; 675 676 down(&vm->limit_sem); 677 678 /* We have an attached board ? */ 679 if (!vm->probed) { 680 retval = -ENODEV; 681 goto error; 682 } 683 684 /* interrupt-out pipe busy ? */ 685 if (vm->irq_out_busy) { 686 retval = -EBUSY; 687 goto error; 688 } 689 690 cnt = CR_CHAN(insn->chanspec); 691 cmd = (!cnt) ? VMK8055_CMD_DEB1 : VMK8055_CMD_DEB2; 692 693 /* NOTE: 694 * The counter inputs are debounced in the software to prevent 695 * false triggering when mechanical switches or relay inputs 696 * are used. The debounce time is equal for both falling and 697 * rising edges. The default debounce time is 2ms. This means 698 * the counter input must be stable for at least 2ms before it 699 * is recognised , giving the maximum count rate of about 200 700 * counts per second. If the debounce time is set to 0, then 701 * the maximum counting rate is about 2000 counts per second. 702 */ 703 for (i = 0; i < insn->n; i++) { 704 debtime = data[i]; 705 if (debtime == 0) 706 debtime = 1; 707 /* -------------------------------------------------- 708 * From libk8055.c 709 * --------------- 710 * Copyleft (C) 2005 by Sven Lindberg; 711 * Copyright (C) 2007 by Pjetur G. Hjaltason: 712 * By testing and measuring on the other hand I found 713 * the formula dbt=0.115*x^2......... 714 * 715 * I'm using here an adapted formula to avoid floating 716 * point operations inside the kernel. The time set 717 * with this formula is within +-4% +- 1. 718 * ------------------------------------------------ */ 719 val = int_sqrt(debtime * 1000 / 115); 720 if (((val + 1) * val) < debtime * 1000 / 115) 721 val += 1; 722 723 vm->irq_out_buf[cnt+6] = val; 724 725 retval = vm_write(vm, cmd); 726 if (retval) 727 goto error; 728 } 729 730 up(&vm->limit_sem); 731 732 return i; 733error: 734 up(&vm->limit_sem); 735 736 return retval; 737} 738 739/* Comedi subdevice offsets */ 740#define VMK8055_SUBD_AI_OFFSET 0 741#define VMK8055_SUBD_AO_OFFSET 1 742#define VMK8055_SUBD_DI_OFFSET 2 743#define VMK8055_SUBD_DO_OFFSET 3 744#define VMK8055_SUBD_CT_OFFSET 4 745 746static DEFINE_MUTEX(glb_mutex); 747 748/* --------------------------------------------------------------------------- 749 * Hook-up (or deallocate) the virtual device file '/dev/comedi[minor]' with 750 * the vmk80xx driver (comedi_config/rmmod). 751--------------------------------------------------------------------------- */ 752static int vm_attach(comedi_device *dev, comedi_devconfig *it) 753{ 754 comedi_subdevice *s; 755 int minor = dev->minor; 756 int idx, i; 757 758 DBGVM("comedi%d: vmk80xx: %s\n", minor, __func__); 759 760 mutex_lock(&glb_mutex); 761 762 /* Prepare user info... */ 763 printk("comedi%d: vmk80xx: ", minor); 764 765 idx = -1; 766 767 /* Find the last valid device which has been detected 768 * by the probe function */; 769 for (i = 0; i < VMK8055_MAX_BOARDS; i++) 770 if (vm_boards[i].probed && !vm_boards[i].attached) { 771 idx = i; 772 break; 773 } 774 775 if (idx == -1) { 776 printk("no boards attached\n"); 777 mutex_unlock(&glb_mutex); 778 return -ENODEV; 779 } 780 781 down(&vm_boards[idx].limit_sem); 782 783 /* OK, at that time we've an attached board and this is 784 * the first execution of the comedi_config command for 785 * this board */ 786 printk("board #%d is attached to comedi\n", vm_boards[idx].id); 787 788 dev->board_name = "vmk80xx"; 789 dev->private = vm_boards + idx; /* will be allocated in vm_probe */ 790 791 /* Subdevices section -> set properties */ 792 if (alloc_subdevices(dev, 5) < 0) { 793 printk("comedi%d: vmk80xx: couldn't allocate subdevs\n", 794 minor); 795 up(&vm_boards[idx].limit_sem); 796 mutex_unlock(&glb_mutex); 797 return -ENOMEM; 798 } 799 800 s = dev->subdevices + VMK8055_SUBD_AI_OFFSET; 801 s->type = COMEDI_SUBD_AI; 802 s->subdev_flags = SDF_READABLE | SDF_GROUND; 803 s->n_chan = 2; 804 s->maxdata = 0xff; /* +5 Volt */ 805 s->range_table = &range_unipolar5; /* +-0 Volt - +5 Volt */ 806 s->insn_read = vm_ai_rinsn; 807 808 s = dev->subdevices + VMK8055_SUBD_AO_OFFSET; 809 s->type = COMEDI_SUBD_AO; 810 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; 811 s->n_chan = 2; 812 s->maxdata = 0xff; 813 s->range_table = &range_unipolar5; 814 s->insn_write = vm_ao_winsn; 815 816 s = dev->subdevices + VMK8055_SUBD_DI_OFFSET; 817 s->type = COMEDI_SUBD_DI; 818 s->subdev_flags = SDF_READABLE | SDF_GROUND; 819 s->n_chan = 5; 820 s->insn_read = vm_di_rinsn; 821 822 s = dev->subdevices + VMK8055_SUBD_DO_OFFSET; 823 s->type = COMEDI_SUBD_DO; 824 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; 825 s->n_chan = 8; 826 s->maxdata = 1; 827 s->insn_write = vm_do_winsn; 828 829 s = dev->subdevices + VMK8055_SUBD_CT_OFFSET; 830 s->type = COMEDI_SUBD_COUNTER; 831 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; 832 s->n_chan = 2; 833 s->insn_read = vm_cnt_rinsn; 834 s->insn_write = vm_cnt_winsn; /* accept only a channel # as arg */ 835 s->insn_config = vm_cnt_cinsn; 836 837 /* Register the comedi board connection */ 838 vm_boards[idx].attached = 1; 839 840 up(&vm_boards[idx].limit_sem); 841 842 mutex_unlock(&glb_mutex); 843 844 return 0; 845} 846 847static int vm_detach(comedi_device *dev) 848{ 849 struct vmk80xx_usb *vm; 850 int minor = dev->minor; 851 852 DBGVM("comedi%d: vmk80xx: %s\n", minor, __func__); 853 854 if (!dev) { /* FIXME: I don't know if i need that here */ 855 printk("comedi%d: vmk80xx: %s - dev is NULL\n", 856 minor, __func__); 857 return -EFAULT; 858 } 859 860 if (!(vm = (struct vmk80xx_usb *)dev->private)) { 861 printk("comedi%d: vmk80xx: %s - dev->private is NULL\n", 862 minor, __func__); 863 return -EFAULT; 864 } 865 866 /* NOTE: dev->private and dev->subdevices are deallocated 867 * automatically by the comedi core */ 868 869 down(&vm->limit_sem); 870 871 dev->private = NULL; 872 vm->attached = 0; 873 874 printk("comedi%d: vmk80xx: board #%d removed from comedi core\n", 875 minor, vm->id); 876 877 up(&vm->limit_sem); 878 879 return 0; 880} 881 882/* --------------------------------------------------------------------------- 883 * Hook-up or remove the Velleman board from the usb. 884--------------------------------------------------------------------------- */ 885static int vm_probe(struct usb_interface *itf, const struct usb_device_id *id) 886{ 887 struct usb_device *udev; 888 int idx, i; 889 u16 product_id; 890 int retval = -ENOMEM; 891 892 DBGVM("comedi#: vmk80xx: %s\n", __func__); 893 894 mutex_lock(&glb_mutex); 895 896 udev = interface_to_usbdev(itf); 897 898 idx = -1; 899 900 /* TODO: k8061 only theoretically supported yet */ 901 product_id = le16_to_cpu(udev->descriptor.idProduct); 902 if (product_id == 0x8061) { 903 printk("comedi#: vmk80xx: Velleman K8061 detected " 904 "(no COMEDI support available yet)\n"); 905 mutex_unlock(&glb_mutex); 906 return -ENODEV; 907 } 908 909 /* Look for a free place to put the board into the array */ 910 for (i = 0; i < VMK8055_MAX_BOARDS; i++) { 911 if (!vm_boards[i].probed) { 912 idx = i; 913 i = VMK8055_MAX_BOARDS; 914 } 915 } 916 917 if (idx == -1) { 918 printk("comedi#: vmk80xx: only FOUR boards supported\n"); 919 mutex_unlock(&glb_mutex); 920 return -EMFILE; 921 } 922 923 /* Initialize device states (hard coded) */ 924 vm_boards[idx].intf = itf; 925 926 /* interrupt-in context */ 927 vm_boards[idx].irq_in_endpoint = VMK8055_EP_IN; 928 vm_boards[idx].irq_in_interval = VMK8055_EP_INTERVAL; 929 vm_boards[idx].irq_in_endpoint_size = VMK8055_EP_SIZE; 930 vm_boards[idx].irq_in_buf = kmalloc(VMK8055_EP_SIZE, GFP_KERNEL); 931 if (!vm_boards[idx].irq_in_buf) { 932 err("comedi#: vmk80xx: couldn't alloc irq_in_buf\n"); 933 goto error; 934 } 935 936 /* interrupt-out context */ 937 vm_boards[idx].irq_out_endpoint = VMK8055_EP_OUT; 938 vm_boards[idx].irq_out_interval = VMK8055_EP_INTERVAL; 939 vm_boards[idx].irq_out_endpoint_size = VMK8055_EP_SIZE; 940 vm_boards[idx].irq_out_buf = kmalloc(VMK8055_EP_SIZE, GFP_KERNEL); 941 if (!vm_boards[idx].irq_out_buf) { 942 err("comedi#: vmk80xx: couldn't alloc irq_out_buf\n"); 943 goto error; 944 } 945 946 /* Endpoints located ? */ 947 if (!vm_boards[idx].irq_in_endpoint) { 948 err("comedi#: vmk80xx: int-in endpoint not found\n"); 949 goto error; 950 } 951 952 if (!vm_boards[idx].irq_out_endpoint) { 953 err("comedi#: vmk80xx: int-out endpoint not found\n"); 954 goto error; 955 } 956 957 /* Try to allocate in/out urbs */ 958 vm_boards[idx].irq_in_urb = usb_alloc_urb(0, GFP_KERNEL); 959 if (!vm_boards[idx].irq_in_urb) { 960 err("comedi#: vmk80xx: couldn't alloc irq_in_urb\n"); 961 goto error; 962 } 963 964 vm_boards[idx].irq_out_urb = usb_alloc_urb(0, GFP_KERNEL); 965 if (!vm_boards[idx].irq_out_urb) { 966 err("comedi#: vmk80xx: couldn't alloc irq_out_urb\n"); 967 goto error; 968 } 969 970 /* Reset the device */ 971 vm_boards[idx].irq_out_buf[0] = VMK8055_CMD_RST; 972 vm_boards[idx].irq_out_buf[1] = 0x00; 973 vm_boards[idx].irq_out_buf[2] = 0x00; 974 vm_boards[idx].irq_out_buf[3] = 0x00; 975 vm_boards[idx].irq_out_buf[4] = 0x00; 976 vm_boards[idx].irq_out_buf[5] = 0x00; 977 vm_boards[idx].irq_out_buf[6] = 0x00; 978 vm_boards[idx].irq_out_buf[7] = 0x00; 979 980 usb_fill_int_urb(vm_boards[idx].irq_out_urb, 981 udev, 982 usb_sndintpipe(udev, 983 vm_boards[idx].irq_out_endpoint), 984 vm_boards[idx].irq_out_buf, 985 vm_boards[idx].irq_out_endpoint_size, 986 vm_irq_out_callback, 987 &vm_boards[idx], 988 vm_boards[idx].irq_out_interval); 989 990 retval = usb_submit_urb(vm_boards[idx].irq_out_urb, GFP_KERNEL); 991 if (retval) 992 DBGCM("comedi#: vmk80xx: device reset failed (err #%d)\n", 993 retval); 994 else 995 DBGCM("comedi#: vmk80xx: device reset success\n"); 996 997 998 usb_set_intfdata(itf, &vm_boards[idx]); 999 1000 /* Show some debugging messages if required */ 1001 DBGCM("comedi#: vmk80xx: [<-] ep addr 0x%02x size %d interval %d\n", 1002 vm_boards[idx].irq_in_endpoint, 1003 vm_boards[idx].irq_in_endpoint_size, 1004 vm_boards[idx].irq_in_interval); 1005 DBGCM("comedi#: vmk80xx: [->] ep addr 0x%02x size %d interval %d\n", 1006 vm_boards[idx].irq_out_endpoint, 1007 vm_boards[idx].irq_out_endpoint_size, 1008 vm_boards[idx].irq_out_interval); 1009 1010 vm_boards[idx].id = idx; 1011 1012 /* Let the user know that the device is now attached */ 1013 printk("comedi#: vmk80xx: K8055 board #%d now attached\n", 1014 vm_boards[idx].id); 1015 1016 /* We have an attached velleman board */ 1017 vm_boards[idx].probed = 1; 1018 1019 mutex_unlock(&glb_mutex); 1020 1021 return retval; 1022error: 1023 vm_delete(&vm_boards[idx]); 1024 1025 mutex_unlock(&glb_mutex); 1026 1027 return retval; 1028} 1029 1030static void vm_disconnect(struct usb_interface *intf) 1031{ 1032 struct vmk80xx_usb *vm; 1033 1034 DBGVM("comedi#: vmk80xx: %s\n", __func__); 1035 1036 vm = (struct vmk80xx_usb *)usb_get_intfdata(intf); 1037 if (!vm) { 1038 printk("comedi#: vmk80xx: %s - vm is NULL\n", __func__); 1039 return; /* -EFAULT */ 1040 } 1041 1042 mutex_lock(&glb_mutex); 1043 /* Twill be needed if the driver supports more than one board */ 1044 down(&vm->limit_sem); 1045 1046 vm->probed = 0; /* we have -1 attached boards */ 1047 usb_set_intfdata(vm->intf, NULL); 1048 1049 vm_delete(vm); /* tidy up */ 1050 1051 /* Twill be needed if the driver supports more than one board */ 1052 up(&vm->limit_sem); 1053 mutex_unlock(&glb_mutex); 1054 1055 printk("comedi#: vmk80xx: Velleman board #%d now detached\n", 1056 vm->id); 1057} 1058 1059/* --------------------------------------------------------------------------- 1060 * Register/Deregister this driver with/from the usb subsystem and the comedi. 1061--------------------------------------------------------------------------- */ 1062static struct usb_driver vm_driver = { 1063#ifdef COMEDI_HAVE_USB_DRIVER_OWNER 1064 .owner = THIS_MODULE, 1065#endif 1066 .name = "vmk80xx", 1067 .probe = vm_probe, 1068 .disconnect = vm_disconnect, 1069 .id_table = vm_id_table, 1070}; 1071 1072static comedi_driver driver_vm = { 1073 .module = THIS_MODULE, 1074 .driver_name = "vmk80xx", 1075 .attach = vm_attach, 1076 .detach = vm_detach, 1077}; 1078 1079static int __init vm_init(void) 1080{ 1081 int retval, idx; 1082 1083 printk("vmk80xx: version " VMK80XX_MODULE_VERSION " -" 1084 " Manuel Gebele <forensixs@gmx.de>\n"); 1085 1086 for (idx = 0; idx < VMK8055_MAX_BOARDS; idx++) { 1087 memset(&vm_boards[idx], 0x00, sizeof(vm_boards[idx])); 1088 init_MUTEX(&vm_boards[idx].limit_sem); 1089 init_waitqueue_head(&vm_boards[idx].read_wait); 1090 init_waitqueue_head(&vm_boards[idx].write_wait); 1091 } 1092 1093 /* Register with the usb subsystem */ 1094 retval = usb_register(&vm_driver); 1095 if (retval) { 1096 err("vmk80xx: usb subsystem registration failed (err #%d)\n", 1097 retval); 1098 return retval; 1099 } 1100 1101 /* Register with the comedi core */ 1102 retval = comedi_driver_register(&driver_vm); 1103 if (retval) { 1104 err("vmk80xx: comedi core registration failed (err #%d)\n", 1105 retval); 1106 usb_deregister(&vm_driver); 1107 } 1108 1109 return retval; 1110} 1111 1112static void __exit vm_exit(void) 1113{ 1114 comedi_driver_unregister(&driver_vm); 1115 usb_deregister(&vm_driver); 1116} 1117module_init(vm_init); 1118module_exit(vm_exit); 1119