vmk80xx.c revision 8ba69ce4b3567de881514c61ea8b04b14d8e68ae
1/* 2 comedi/drivers/vmk80xx.c 3 Velleman USB Board Low-Level 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 Board Low-Level Driver 28Devices: K8055/K8061 aka VM110/VM140 29Author: Manuel Gebele <forensixs@gmx.de> 30Updated: Sun, 10 May 2009 11:14:59 +0200 31Status: works 32 33Supports: 34 - analog input 35 - analog output 36 - digital input 37 - digital output 38 - counter 39 - pwm 40*/ 41/* 42Changelog: 43 440.8.81 -3- code completely rewritten (adjust driver logic) 450.8.81 -2- full support for K8061 460.8.81 -1- fix some mistaken among others the number of 47 supported boards and I/O handling 48 490.7.76 -4- renamed to vmk80xx 500.7.76 -3- detect K8061 (only theoretically supported) 510.7.76 -2- code completely rewritten (adjust driver logic) 520.7.76 -1- support for digital and counter subdevice 53*/ 54 55#include <linux/kernel.h> 56#include <linux/module.h> 57#include <linux/mutex.h> 58#include <linux/errno.h> 59#include <linux/input.h> 60#include <linux/slab.h> 61#include <linux/poll.h> 62#include <linux/usb.h> 63#include <linux/uaccess.h> 64 65#include "../comedidev.h" 66 67#define BOARDNAME "vmk80xx" 68 69MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>"); 70MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver"); 71MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140"); 72MODULE_VERSION("0.8.01"); 73MODULE_LICENSE("GPL"); 74 75enum { 76 DEVICE_VMK8055, 77 DEVICE_VMK8061 78}; 79 80static const struct usb_device_id vmk80xx_id_table[] = { 81 {USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055}, 82 {USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055}, 83 {USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055}, 84 {USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055}, 85 {USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061}, 86 {USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061}, 87 {USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061}, 88 {USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061}, 89 {USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061}, 90 {USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061}, 91 {USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061}, 92 {USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061}, 93 {} /* terminating entry */ 94}; 95 96MODULE_DEVICE_TABLE(usb, vmk80xx_id_table); 97 98#define VMK8055_DI_REG 0x00 99#define VMK8055_DO_REG 0x01 100#define VMK8055_AO1_REG 0x02 101#define VMK8055_AO2_REG 0x03 102#define VMK8055_AI1_REG 0x02 103#define VMK8055_AI2_REG 0x03 104#define VMK8055_CNT1_REG 0x04 105#define VMK8055_CNT2_REG 0x06 106 107#define VMK8061_CH_REG 0x01 108#define VMK8061_DI_REG 0x01 109#define VMK8061_DO_REG 0x01 110#define VMK8061_PWM_REG1 0x01 111#define VMK8061_PWM_REG2 0x02 112#define VMK8061_CNT_REG 0x02 113#define VMK8061_AO_REG 0x02 114#define VMK8061_AI_REG1 0x02 115#define VMK8061_AI_REG2 0x03 116 117#define VMK8055_CMD_RST 0x00 118#define VMK8055_CMD_DEB1_TIME 0x01 119#define VMK8055_CMD_DEB2_TIME 0x02 120#define VMK8055_CMD_RST_CNT1 0x03 121#define VMK8055_CMD_RST_CNT2 0x04 122#define VMK8055_CMD_WRT_AD 0x05 123 124#define VMK8061_CMD_RD_AI 0x00 125#define VMK8061_CMR_RD_ALL_AI 0x01 /* !non-active! */ 126#define VMK8061_CMD_SET_AO 0x02 127#define VMK8061_CMD_SET_ALL_AO 0x03 /* !non-active! */ 128#define VMK8061_CMD_OUT_PWM 0x04 129#define VMK8061_CMD_RD_DI 0x05 130#define VMK8061_CMD_DO 0x06 /* !non-active! */ 131#define VMK8061_CMD_CLR_DO 0x07 132#define VMK8061_CMD_SET_DO 0x08 133#define VMK8061_CMD_RD_CNT 0x09 /* TODO: completely pointless? */ 134#define VMK8061_CMD_RST_CNT 0x0a /* TODO: completely pointless? */ 135#define VMK8061_CMD_RD_VERSION 0x0b /* internal usage */ 136#define VMK8061_CMD_RD_JMP_STAT 0x0c /* TODO: not implemented yet */ 137#define VMK8061_CMD_RD_PWR_STAT 0x0d /* internal usage */ 138#define VMK8061_CMD_RD_DO 0x0e 139#define VMK8061_CMD_RD_AO 0x0f 140#define VMK8061_CMD_RD_PWM 0x10 141 142#define VMK80XX_MAX_BOARDS COMEDI_NUM_BOARD_MINORS 143 144#define TRANS_OUT_BUSY 1 145#define TRANS_IN_BUSY 2 146#define TRANS_IN_RUNNING 3 147 148#define IC3_VERSION (1 << 0) 149#define IC6_VERSION (1 << 1) 150 151#define URB_RCV_FLAG (1 << 0) 152#define URB_SND_FLAG (1 << 1) 153 154#define CONFIG_VMK80XX_DEBUG 155#undef CONFIG_VMK80XX_DEBUG 156 157#ifdef CONFIG_VMK80XX_DEBUG 158static int dbgvm = 1; 159#else 160static int dbgvm; 161#endif 162 163#ifdef CONFIG_COMEDI_DEBUG 164static int dbgcm = 1; 165#else 166static int dbgcm; 167#endif 168 169#define dbgvm(fmt, arg...) \ 170do { \ 171 if (dbgvm) \ 172 printk(KERN_DEBUG fmt, ##arg); \ 173} while (0) 174 175#define dbgcm(fmt, arg...) \ 176do { \ 177 if (dbgcm) \ 178 printk(KERN_DEBUG fmt, ##arg); \ 179} while (0) 180 181enum vmk80xx_model { 182 VMK8055_MODEL, 183 VMK8061_MODEL 184}; 185 186struct firmware_version { 187 unsigned char ic3_vers[32]; /* USB-Controller */ 188 unsigned char ic6_vers[32]; /* CPU */ 189}; 190 191static const struct comedi_lrange vmk8055_range = { 192 1, {UNI_RANGE(5)} 193}; 194 195static const struct comedi_lrange vmk8061_range = { 196 2, {UNI_RANGE(5), UNI_RANGE(10)} 197}; 198 199struct vmk80xx_board { 200 const char *name; 201 enum vmk80xx_model model; 202 const struct comedi_lrange *range; 203 __u8 ai_chans; 204 __le16 ai_bits; 205 __u8 ao_chans; 206 __le16 ao_bits; 207 __u8 di_chans; 208 __le16 di_bits; 209 __u8 do_chans; 210 __le16 do_bits; 211 __u8 cnt_chans; 212 __le16 cnt_bits; 213 __u8 pwm_chans; 214 __le16 pwm_bits; 215}; 216 217enum { 218 VMK80XX_SUBD_AI, 219 VMK80XX_SUBD_AO, 220 VMK80XX_SUBD_DI, 221 VMK80XX_SUBD_DO, 222 VMK80XX_SUBD_CNT, 223 VMK80XX_SUBD_PWM, 224}; 225 226struct vmk80xx_usb { 227 struct usb_device *udev; 228 struct usb_interface *intf; 229 struct usb_endpoint_descriptor *ep_rx; 230 struct usb_endpoint_descriptor *ep_tx; 231 struct usb_anchor rx_anchor; 232 struct usb_anchor tx_anchor; 233 struct vmk80xx_board board; 234 struct firmware_version fw; 235 struct semaphore limit_sem; 236 wait_queue_head_t read_wait; 237 wait_queue_head_t write_wait; 238 unsigned char *usb_rx_buf; 239 unsigned char *usb_tx_buf; 240 unsigned long flags; 241 int probed; 242 int attached; 243 int count; 244}; 245 246static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS]; 247 248static DEFINE_MUTEX(glb_mutex); 249 250static void vmk80xx_tx_callback(struct urb *urb) 251{ 252 struct vmk80xx_usb *dev = urb->context; 253 int stat = urb->status; 254 255 dbgvm("vmk80xx: %s\n", __func__); 256 257 if (stat && !(stat == -ENOENT 258 || stat == -ECONNRESET || stat == -ESHUTDOWN)) 259 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n", 260 __func__, stat); 261 262 if (!test_bit(TRANS_OUT_BUSY, &dev->flags)) 263 return; 264 265 clear_bit(TRANS_OUT_BUSY, &dev->flags); 266 267 wake_up_interruptible(&dev->write_wait); 268} 269 270static void vmk80xx_rx_callback(struct urb *urb) 271{ 272 struct vmk80xx_usb *dev = urb->context; 273 int stat = urb->status; 274 275 dbgvm("vmk80xx: %s\n", __func__); 276 277 switch (stat) { 278 case 0: 279 break; 280 case -ENOENT: 281 case -ECONNRESET: 282 case -ESHUTDOWN: 283 break; 284 default: 285 dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n", 286 __func__, stat); 287 goto resubmit; 288 } 289 290 goto exit; 291resubmit: 292 if (test_bit(TRANS_IN_RUNNING, &dev->flags) && dev->intf) { 293 usb_anchor_urb(urb, &dev->rx_anchor); 294 295 if (!usb_submit_urb(urb, GFP_KERNEL)) 296 goto exit; 297 298 err("comedi#: vmk80xx: %s - submit urb failed\n", __func__); 299 300 usb_unanchor_urb(urb); 301 } 302exit: 303 clear_bit(TRANS_IN_BUSY, &dev->flags); 304 305 wake_up_interruptible(&dev->read_wait); 306} 307 308static int vmk80xx_check_data_link(struct vmk80xx_usb *dev) 309{ 310 unsigned int tx_pipe; 311 unsigned int rx_pipe; 312 unsigned char tx[1]; 313 unsigned char rx[2]; 314 315 dbgvm("vmk80xx: %s\n", __func__); 316 317 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01); 318 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81); 319 320 tx[0] = VMK8061_CMD_RD_PWR_STAT; 321 322 /* 323 * Check that IC6 (PIC16F871) is powered and 324 * running and the data link between IC3 and 325 * IC6 is working properly 326 */ 327 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval); 328 usb_bulk_msg(dev->udev, rx_pipe, rx, 2, NULL, HZ * 10); 329 330 return (int)rx[1]; 331} 332 333static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag) 334{ 335 unsigned int tx_pipe; 336 unsigned int rx_pipe; 337 unsigned char tx[1]; 338 unsigned char rx[64]; 339 int cnt; 340 341 dbgvm("vmk80xx: %s\n", __func__); 342 343 tx_pipe = usb_sndbulkpipe(dev->udev, 0x01); 344 rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81); 345 346 tx[0] = VMK8061_CMD_RD_VERSION; 347 348 /* 349 * Read the firmware version info of IC3 and 350 * IC6 from the internal EEPROM of the IC 351 */ 352 usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval); 353 usb_bulk_msg(dev->udev, rx_pipe, rx, 64, &cnt, HZ * 10); 354 355 rx[cnt] = '\0'; 356 357 if (flag & IC3_VERSION) 358 strncpy(dev->fw.ic3_vers, rx + 1, 24); 359 else /* IC6_VERSION */ 360 strncpy(dev->fw.ic6_vers, rx + 25, 24); 361} 362 363static int vmk80xx_reset_device(struct vmk80xx_usb *dev) 364{ 365 struct urb *urb; 366 unsigned int tx_pipe; 367 int ival; 368 size_t size; 369 370 dbgvm("vmk80xx: %s\n", __func__); 371 372 urb = usb_alloc_urb(0, GFP_KERNEL); 373 if (!urb) 374 return -ENOMEM; 375 376 tx_pipe = usb_sndintpipe(dev->udev, 0x01); 377 378 ival = dev->ep_tx->bInterval; 379 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); 380 381 dev->usb_tx_buf[0] = VMK8055_CMD_RST; 382 dev->usb_tx_buf[1] = 0x00; 383 dev->usb_tx_buf[2] = 0x00; 384 dev->usb_tx_buf[3] = 0x00; 385 dev->usb_tx_buf[4] = 0x00; 386 dev->usb_tx_buf[5] = 0x00; 387 dev->usb_tx_buf[6] = 0x00; 388 dev->usb_tx_buf[7] = 0x00; 389 390 usb_fill_int_urb(urb, dev->udev, tx_pipe, dev->usb_tx_buf, 391 size, vmk80xx_tx_callback, dev, ival); 392 393 usb_anchor_urb(urb, &dev->tx_anchor); 394 395 return usb_submit_urb(urb, GFP_KERNEL); 396} 397 398static void vmk80xx_build_int_urb(struct urb *urb, int flag) 399{ 400 struct vmk80xx_usb *dev = urb->context; 401 __u8 rx_addr; 402 __u8 tx_addr; 403 unsigned int pipe; 404 unsigned char *buf; 405 size_t size; 406 void (*callback) (struct urb *); 407 int ival; 408 409 dbgvm("vmk80xx: %s\n", __func__); 410 411 if (flag & URB_RCV_FLAG) { 412 rx_addr = dev->ep_rx->bEndpointAddress; 413 pipe = usb_rcvintpipe(dev->udev, rx_addr); 414 buf = dev->usb_rx_buf; 415 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize); 416 callback = vmk80xx_rx_callback; 417 ival = dev->ep_rx->bInterval; 418 } else { /* URB_SND_FLAG */ 419 tx_addr = dev->ep_tx->bEndpointAddress; 420 pipe = usb_sndintpipe(dev->udev, tx_addr); 421 buf = dev->usb_tx_buf; 422 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); 423 callback = vmk80xx_tx_callback; 424 ival = dev->ep_tx->bInterval; 425 } 426 427 usb_fill_int_urb(urb, dev->udev, pipe, buf, size, callback, dev, ival); 428} 429 430static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev) 431{ 432 __u8 tx_addr; 433 __u8 rx_addr; 434 unsigned int tx_pipe; 435 unsigned int rx_pipe; 436 size_t size; 437 438 dbgvm("vmk80xx: %s\n", __func__); 439 440 set_bit(TRANS_IN_BUSY, &dev->flags); 441 set_bit(TRANS_OUT_BUSY, &dev->flags); 442 443 tx_addr = dev->ep_tx->bEndpointAddress; 444 rx_addr = dev->ep_rx->bEndpointAddress; 445 tx_pipe = usb_sndbulkpipe(dev->udev, tx_addr); 446 rx_pipe = usb_rcvbulkpipe(dev->udev, rx_addr); 447 448 /* 449 * The max packet size attributes of the K8061 450 * input/output endpoints are identical 451 */ 452 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); 453 454 usb_bulk_msg(dev->udev, tx_pipe, dev->usb_tx_buf, 455 size, NULL, dev->ep_tx->bInterval); 456 usb_bulk_msg(dev->udev, rx_pipe, dev->usb_rx_buf, size, NULL, HZ * 10); 457 458 clear_bit(TRANS_OUT_BUSY, &dev->flags); 459 clear_bit(TRANS_IN_BUSY, &dev->flags); 460} 461 462static int vmk80xx_read_packet(struct vmk80xx_usb *dev) 463{ 464 struct urb *urb; 465 int retval; 466 467 dbgvm("vmk80xx: %s\n", __func__); 468 469 if (!dev->intf) 470 return -ENODEV; 471 472 /* Only useful for interrupt transfers */ 473 if (test_bit(TRANS_IN_BUSY, &dev->flags)) 474 if (wait_event_interruptible(dev->read_wait, 475 !test_bit(TRANS_IN_BUSY, 476 &dev->flags))) 477 return -ERESTART; 478 479 if (dev->board.model == VMK8061_MODEL) { 480 vmk80xx_do_bulk_msg(dev); 481 482 return 0; 483 } 484 485 urb = usb_alloc_urb(0, GFP_KERNEL); 486 if (!urb) 487 return -ENOMEM; 488 489 urb->context = dev; 490 vmk80xx_build_int_urb(urb, URB_RCV_FLAG); 491 492 set_bit(TRANS_IN_RUNNING, &dev->flags); 493 set_bit(TRANS_IN_BUSY, &dev->flags); 494 495 usb_anchor_urb(urb, &dev->rx_anchor); 496 497 retval = usb_submit_urb(urb, GFP_KERNEL); 498 if (!retval) 499 goto exit; 500 501 clear_bit(TRANS_IN_RUNNING, &dev->flags); 502 usb_unanchor_urb(urb); 503 504exit: 505 usb_free_urb(urb); 506 507 return retval; 508} 509 510static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd) 511{ 512 struct urb *urb; 513 int retval; 514 515 dbgvm("vmk80xx: %s\n", __func__); 516 517 if (!dev->intf) 518 return -ENODEV; 519 520 if (test_bit(TRANS_OUT_BUSY, &dev->flags)) 521 if (wait_event_interruptible(dev->write_wait, 522 !test_bit(TRANS_OUT_BUSY, 523 &dev->flags))) 524 return -ERESTART; 525 526 if (dev->board.model == VMK8061_MODEL) { 527 dev->usb_tx_buf[0] = cmd; 528 vmk80xx_do_bulk_msg(dev); 529 530 return 0; 531 } 532 533 urb = usb_alloc_urb(0, GFP_KERNEL); 534 if (!urb) 535 return -ENOMEM; 536 537 urb->context = dev; 538 vmk80xx_build_int_urb(urb, URB_SND_FLAG); 539 540 set_bit(TRANS_OUT_BUSY, &dev->flags); 541 542 usb_anchor_urb(urb, &dev->tx_anchor); 543 544 dev->usb_tx_buf[0] = cmd; 545 546 retval = usb_submit_urb(urb, GFP_KERNEL); 547 if (!retval) 548 goto exit; 549 550 clear_bit(TRANS_OUT_BUSY, &dev->flags); 551 usb_unanchor_urb(urb); 552 553exit: 554 usb_free_urb(urb); 555 556 return retval; 557} 558 559#define DIR_IN 1 560#define DIR_OUT 2 561 562static int rudimentary_check(struct vmk80xx_usb *dev, int dir) 563{ 564 if (!dev) 565 return -EFAULT; 566 if (!dev->probed) 567 return -ENODEV; 568 if (!dev->attached) 569 return -ENODEV; 570 if (dir & DIR_IN) { 571 if (test_bit(TRANS_IN_BUSY, &dev->flags)) 572 return -EBUSY; 573 } 574 if (dir & DIR_OUT) { 575 if (test_bit(TRANS_OUT_BUSY, &dev->flags)) 576 return -EBUSY; 577 } 578 579 return 0; 580} 581 582static int vmk80xx_ai_rinsn(struct comedi_device *cdev, 583 struct comedi_subdevice *s, 584 struct comedi_insn *insn, unsigned int *data) 585{ 586 struct vmk80xx_usb *dev = cdev->private; 587 int chan; 588 int reg[2]; 589 int n; 590 591 dbgvm("vmk80xx: %s\n", __func__); 592 593 n = rudimentary_check(dev, DIR_IN); 594 if (n) 595 return n; 596 597 down(&dev->limit_sem); 598 chan = CR_CHAN(insn->chanspec); 599 600 switch (dev->board.model) { 601 case VMK8055_MODEL: 602 if (!chan) 603 reg[0] = VMK8055_AI1_REG; 604 else 605 reg[0] = VMK8055_AI2_REG; 606 break; 607 case VMK8061_MODEL: 608 reg[0] = VMK8061_AI_REG1; 609 reg[1] = VMK8061_AI_REG2; 610 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI; 611 dev->usb_tx_buf[VMK8061_CH_REG] = chan; 612 break; 613 } 614 615 for (n = 0; n < insn->n; n++) { 616 if (vmk80xx_read_packet(dev)) 617 break; 618 619 if (dev->board.model == VMK8055_MODEL) { 620 data[n] = dev->usb_rx_buf[reg[0]]; 621 continue; 622 } 623 624 /* VMK8061_MODEL */ 625 data[n] = dev->usb_rx_buf[reg[0]] + 256 * 626 dev->usb_rx_buf[reg[1]]; 627 } 628 629 up(&dev->limit_sem); 630 631 return n; 632} 633 634static int vmk80xx_ao_winsn(struct comedi_device *cdev, 635 struct comedi_subdevice *s, 636 struct comedi_insn *insn, unsigned int *data) 637{ 638 struct vmk80xx_usb *dev = cdev->private; 639 int chan; 640 int cmd; 641 int reg; 642 int n; 643 644 dbgvm("vmk80xx: %s\n", __func__); 645 646 n = rudimentary_check(dev, DIR_OUT); 647 if (n) 648 return n; 649 650 down(&dev->limit_sem); 651 chan = CR_CHAN(insn->chanspec); 652 653 switch (dev->board.model) { 654 case VMK8055_MODEL: 655 cmd = VMK8055_CMD_WRT_AD; 656 if (!chan) 657 reg = VMK8055_AO1_REG; 658 else 659 reg = VMK8055_AO2_REG; 660 break; 661 default: /* NOTE: avoid compiler warnings */ 662 cmd = VMK8061_CMD_SET_AO; 663 reg = VMK8061_AO_REG; 664 dev->usb_tx_buf[VMK8061_CH_REG] = chan; 665 break; 666 } 667 668 for (n = 0; n < insn->n; n++) { 669 dev->usb_tx_buf[reg] = data[n]; 670 671 if (vmk80xx_write_packet(dev, cmd)) 672 break; 673 } 674 675 up(&dev->limit_sem); 676 677 return n; 678} 679 680static int vmk80xx_ao_rinsn(struct comedi_device *cdev, 681 struct comedi_subdevice *s, 682 struct comedi_insn *insn, unsigned int *data) 683{ 684 struct vmk80xx_usb *dev = cdev->private; 685 int chan; 686 int reg; 687 int n; 688 689 dbgvm("vmk80xx: %s\n", __func__); 690 691 n = rudimentary_check(dev, DIR_IN); 692 if (n) 693 return n; 694 695 down(&dev->limit_sem); 696 chan = CR_CHAN(insn->chanspec); 697 698 reg = VMK8061_AO_REG - 1; 699 700 dev->usb_tx_buf[0] = VMK8061_CMD_RD_AO; 701 702 for (n = 0; n < insn->n; n++) { 703 if (vmk80xx_read_packet(dev)) 704 break; 705 706 data[n] = dev->usb_rx_buf[reg + chan]; 707 } 708 709 up(&dev->limit_sem); 710 711 return n; 712} 713 714static int vmk80xx_di_bits(struct comedi_device *cdev, 715 struct comedi_subdevice *s, 716 struct comedi_insn *insn, unsigned int *data) 717{ 718 struct vmk80xx_usb *dev = cdev->private; 719 unsigned char *rx_buf; 720 int reg; 721 int retval; 722 723 dbgvm("vmk80xx: %s\n", __func__); 724 725 retval = rudimentary_check(dev, DIR_IN); 726 if (retval) 727 return retval; 728 729 down(&dev->limit_sem); 730 731 rx_buf = dev->usb_rx_buf; 732 733 if (dev->board.model == VMK8061_MODEL) { 734 reg = VMK8061_DI_REG; 735 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI; 736 } else { 737 reg = VMK8055_DI_REG; 738 } 739 740 retval = vmk80xx_read_packet(dev); 741 742 if (!retval) { 743 if (dev->board.model == VMK8055_MODEL) 744 data[1] = (((rx_buf[reg] >> 4) & 0x03) | 745 ((rx_buf[reg] << 2) & 0x04) | 746 ((rx_buf[reg] >> 3) & 0x18)); 747 else 748 data[1] = rx_buf[reg]; 749 750 retval = 2; 751 } 752 753 up(&dev->limit_sem); 754 755 return retval; 756} 757 758static int vmk80xx_di_rinsn(struct comedi_device *cdev, 759 struct comedi_subdevice *s, 760 struct comedi_insn *insn, unsigned int *data) 761{ 762 struct vmk80xx_usb *dev = cdev->private; 763 int chan; 764 unsigned char *rx_buf; 765 int reg; 766 int inp; 767 int n; 768 769 dbgvm("vmk80xx: %s\n", __func__); 770 771 n = rudimentary_check(dev, DIR_IN); 772 if (n) 773 return n; 774 775 down(&dev->limit_sem); 776 chan = CR_CHAN(insn->chanspec); 777 778 rx_buf = dev->usb_rx_buf; 779 780 if (dev->board.model == VMK8061_MODEL) { 781 reg = VMK8061_DI_REG; 782 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI; 783 } else { 784 reg = VMK8055_DI_REG; 785 } 786 for (n = 0; n < insn->n; n++) { 787 if (vmk80xx_read_packet(dev)) 788 break; 789 790 if (dev->board.model == VMK8055_MODEL) 791 inp = (((rx_buf[reg] >> 4) & 0x03) | 792 ((rx_buf[reg] << 2) & 0x04) | 793 ((rx_buf[reg] >> 3) & 0x18)); 794 else 795 inp = rx_buf[reg]; 796 797 data[n] = (inp >> chan) & 1; 798 } 799 800 up(&dev->limit_sem); 801 802 return n; 803} 804 805static int vmk80xx_do_winsn(struct comedi_device *cdev, 806 struct comedi_subdevice *s, 807 struct comedi_insn *insn, unsigned int *data) 808{ 809 struct vmk80xx_usb *dev = cdev->private; 810 int chan; 811 unsigned char *tx_buf; 812 int reg; 813 int cmd; 814 int n; 815 816 dbgvm("vmk80xx: %s\n", __func__); 817 818 n = rudimentary_check(dev, DIR_OUT); 819 if (n) 820 return n; 821 822 down(&dev->limit_sem); 823 chan = CR_CHAN(insn->chanspec); 824 825 tx_buf = dev->usb_tx_buf; 826 827 for (n = 0; n < insn->n; n++) { 828 if (dev->board.model == VMK8055_MODEL) { 829 reg = VMK8055_DO_REG; 830 cmd = VMK8055_CMD_WRT_AD; 831 if (data[n] == 1) 832 tx_buf[reg] |= (1 << chan); 833 else 834 tx_buf[reg] ^= (1 << chan); 835 } else { /* VMK8061_MODEL */ 836 reg = VMK8061_DO_REG; 837 if (data[n] == 1) { 838 cmd = VMK8061_CMD_SET_DO; 839 tx_buf[reg] = 1 << chan; 840 } else { 841 cmd = VMK8061_CMD_CLR_DO; 842 tx_buf[reg] = 0xff - (1 << chan); 843 } 844 } 845 846 if (vmk80xx_write_packet(dev, cmd)) 847 break; 848 } 849 850 up(&dev->limit_sem); 851 852 return n; 853} 854 855static int vmk80xx_do_rinsn(struct comedi_device *cdev, 856 struct comedi_subdevice *s, 857 struct comedi_insn *insn, unsigned int *data) 858{ 859 struct vmk80xx_usb *dev = cdev->private; 860 int chan; 861 int reg; 862 int n; 863 864 dbgvm("vmk80xx: %s\n", __func__); 865 866 n = rudimentary_check(dev, DIR_IN); 867 if (n) 868 return n; 869 870 down(&dev->limit_sem); 871 chan = CR_CHAN(insn->chanspec); 872 873 reg = VMK8061_DO_REG; 874 875 dev->usb_tx_buf[0] = VMK8061_CMD_RD_DO; 876 877 for (n = 0; n < insn->n; n++) { 878 if (vmk80xx_read_packet(dev)) 879 break; 880 881 data[n] = (dev->usb_rx_buf[reg] >> chan) & 1; 882 } 883 884 up(&dev->limit_sem); 885 886 return n; 887} 888 889static int vmk80xx_do_bits(struct comedi_device *cdev, 890 struct comedi_subdevice *s, 891 struct comedi_insn *insn, unsigned int *data) 892{ 893 struct vmk80xx_usb *dev = cdev->private; 894 unsigned char *rx_buf, *tx_buf; 895 int dir, reg, cmd; 896 int retval; 897 898 dbgvm("vmk80xx: %s\n", __func__); 899 900 dir = 0; 901 902 if (data[0]) 903 dir |= DIR_OUT; 904 905 if (dev->board.model == VMK8061_MODEL) 906 dir |= DIR_IN; 907 908 retval = rudimentary_check(dev, dir); 909 if (retval) 910 return retval; 911 912 down(&dev->limit_sem); 913 914 rx_buf = dev->usb_rx_buf; 915 tx_buf = dev->usb_tx_buf; 916 917 if (data[0]) { 918 if (dev->board.model == VMK8055_MODEL) { 919 reg = VMK8055_DO_REG; 920 cmd = VMK8055_CMD_WRT_AD; 921 } else { /* VMK8061_MODEL */ 922 reg = VMK8061_DO_REG; 923 cmd = VMK8061_CMD_DO; 924 } 925 926 tx_buf[reg] &= ~data[0]; 927 tx_buf[reg] |= (data[0] & data[1]); 928 929 retval = vmk80xx_write_packet(dev, cmd); 930 931 if (retval) 932 goto out; 933 } 934 935 if (dev->board.model == VMK8061_MODEL) { 936 reg = VMK8061_DO_REG; 937 tx_buf[0] = VMK8061_CMD_RD_DO; 938 939 retval = vmk80xx_read_packet(dev); 940 941 if (!retval) { 942 data[1] = rx_buf[reg]; 943 retval = 2; 944 } 945 } else { 946 data[1] = tx_buf[reg]; 947 retval = 2; 948 } 949 950out: 951 up(&dev->limit_sem); 952 953 return retval; 954} 955 956static int vmk80xx_cnt_rinsn(struct comedi_device *cdev, 957 struct comedi_subdevice *s, 958 struct comedi_insn *insn, unsigned int *data) 959{ 960 struct vmk80xx_usb *dev = cdev->private; 961 int chan; 962 int reg[2]; 963 int n; 964 965 dbgvm("vmk80xx: %s\n", __func__); 966 967 n = rudimentary_check(dev, DIR_IN); 968 if (n) 969 return n; 970 971 down(&dev->limit_sem); 972 chan = CR_CHAN(insn->chanspec); 973 974 switch (dev->board.model) { 975 case VMK8055_MODEL: 976 if (!chan) 977 reg[0] = VMK8055_CNT1_REG; 978 else 979 reg[0] = VMK8055_CNT2_REG; 980 break; 981 case VMK8061_MODEL: 982 reg[0] = VMK8061_CNT_REG; 983 reg[1] = VMK8061_CNT_REG; 984 dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT; 985 break; 986 } 987 988 for (n = 0; n < insn->n; n++) { 989 if (vmk80xx_read_packet(dev)) 990 break; 991 992 if (dev->board.model == VMK8055_MODEL) 993 data[n] = dev->usb_rx_buf[reg[0]]; 994 else /* VMK8061_MODEL */ 995 data[n] = dev->usb_rx_buf[reg[0] * (chan + 1) + 1] 996 + 256 * dev->usb_rx_buf[reg[1] * 2 + 2]; 997 } 998 999 up(&dev->limit_sem); 1000 1001 return n; 1002} 1003 1004static int vmk80xx_cnt_cinsn(struct comedi_device *cdev, 1005 struct comedi_subdevice *s, 1006 struct comedi_insn *insn, unsigned int *data) 1007{ 1008 struct vmk80xx_usb *dev = cdev->private; 1009 unsigned int insn_cmd; 1010 int chan; 1011 int cmd; 1012 int reg; 1013 int n; 1014 1015 dbgvm("vmk80xx: %s\n", __func__); 1016 1017 n = rudimentary_check(dev, DIR_OUT); 1018 if (n) 1019 return n; 1020 1021 down(&dev->limit_sem); 1022 1023 insn_cmd = data[0]; 1024 if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET) 1025 return -EINVAL; 1026 1027 chan = CR_CHAN(insn->chanspec); 1028 1029 if (dev->board.model == VMK8055_MODEL) { 1030 if (!chan) { 1031 cmd = VMK8055_CMD_RST_CNT1; 1032 reg = VMK8055_CNT1_REG; 1033 } else { 1034 cmd = VMK8055_CMD_RST_CNT2; 1035 reg = VMK8055_CNT2_REG; 1036 } 1037 1038 dev->usb_tx_buf[reg] = 0x00; 1039 } else { 1040 cmd = VMK8061_CMD_RST_CNT; 1041 } 1042 1043 for (n = 0; n < insn->n; n++) 1044 if (vmk80xx_write_packet(dev, cmd)) 1045 break; 1046 1047 up(&dev->limit_sem); 1048 1049 return n; 1050} 1051 1052static int vmk80xx_cnt_winsn(struct comedi_device *cdev, 1053 struct comedi_subdevice *s, 1054 struct comedi_insn *insn, unsigned int *data) 1055{ 1056 struct vmk80xx_usb *dev = cdev->private; 1057 unsigned long debtime; 1058 unsigned long val; 1059 int chan; 1060 int cmd; 1061 int n; 1062 1063 dbgvm("vmk80xx: %s\n", __func__); 1064 1065 n = rudimentary_check(dev, DIR_OUT); 1066 if (n) 1067 return n; 1068 1069 down(&dev->limit_sem); 1070 chan = CR_CHAN(insn->chanspec); 1071 1072 if (!chan) 1073 cmd = VMK8055_CMD_DEB1_TIME; 1074 else 1075 cmd = VMK8055_CMD_DEB2_TIME; 1076 1077 for (n = 0; n < insn->n; n++) { 1078 debtime = data[n]; 1079 if (debtime == 0) 1080 debtime = 1; 1081 1082 /* TODO: Prevent overflows */ 1083 if (debtime > 7450) 1084 debtime = 7450; 1085 1086 val = int_sqrt(debtime * 1000 / 115); 1087 if (((val + 1) * val) < debtime * 1000 / 115) 1088 val += 1; 1089 1090 dev->usb_tx_buf[6 + chan] = val; 1091 1092 if (vmk80xx_write_packet(dev, cmd)) 1093 break; 1094 } 1095 1096 up(&dev->limit_sem); 1097 1098 return n; 1099} 1100 1101static int vmk80xx_pwm_rinsn(struct comedi_device *cdev, 1102 struct comedi_subdevice *s, 1103 struct comedi_insn *insn, unsigned int *data) 1104{ 1105 struct vmk80xx_usb *dev = cdev->private; 1106 int reg[2]; 1107 int n; 1108 1109 dbgvm("vmk80xx: %s\n", __func__); 1110 1111 n = rudimentary_check(dev, DIR_IN); 1112 if (n) 1113 return n; 1114 1115 down(&dev->limit_sem); 1116 1117 reg[0] = VMK8061_PWM_REG1; 1118 reg[1] = VMK8061_PWM_REG2; 1119 1120 dev->usb_tx_buf[0] = VMK8061_CMD_RD_PWM; 1121 1122 for (n = 0; n < insn->n; n++) { 1123 if (vmk80xx_read_packet(dev)) 1124 break; 1125 1126 data[n] = dev->usb_rx_buf[reg[0]] + 4 * dev->usb_rx_buf[reg[1]]; 1127 } 1128 1129 up(&dev->limit_sem); 1130 1131 return n; 1132} 1133 1134static int vmk80xx_pwm_winsn(struct comedi_device *cdev, 1135 struct comedi_subdevice *s, 1136 struct comedi_insn *insn, unsigned int *data) 1137{ 1138 struct vmk80xx_usb *dev = cdev->private; 1139 unsigned char *tx_buf; 1140 int reg[2]; 1141 int cmd; 1142 int n; 1143 1144 dbgvm("vmk80xx: %s\n", __func__); 1145 1146 n = rudimentary_check(dev, DIR_OUT); 1147 if (n) 1148 return n; 1149 1150 down(&dev->limit_sem); 1151 1152 tx_buf = dev->usb_tx_buf; 1153 1154 reg[0] = VMK8061_PWM_REG1; 1155 reg[1] = VMK8061_PWM_REG2; 1156 1157 cmd = VMK8061_CMD_OUT_PWM; 1158 1159 /* 1160 * The followin piece of code was translated from the inline 1161 * assembler code in the DLL source code. 1162 * 1163 * asm 1164 * mov eax, k ; k is the value (data[n]) 1165 * and al, 03h ; al are the lower 8 bits of eax 1166 * mov lo, al ; lo is the low part (tx_buf[reg[0]]) 1167 * mov eax, k 1168 * shr eax, 2 ; right shift eax register by 2 1169 * mov hi, al ; hi is the high part (tx_buf[reg[1]]) 1170 * end; 1171 */ 1172 for (n = 0; n < insn->n; n++) { 1173 tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03); 1174 tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff; 1175 1176 if (vmk80xx_write_packet(dev, cmd)) 1177 break; 1178 } 1179 1180 up(&dev->limit_sem); 1181 1182 return n; 1183} 1184 1185static int vmk80xx_attach(struct comedi_device *cdev, 1186 struct comedi_devconfig *it) 1187{ 1188 int i; 1189 struct vmk80xx_usb *dev; 1190 int n_subd; 1191 struct comedi_subdevice *s; 1192 int minor; 1193 1194 dbgvm("vmk80xx: %s\n", __func__); 1195 1196 mutex_lock(&glb_mutex); 1197 1198 for (i = 0; i < VMK80XX_MAX_BOARDS; i++) 1199 if (vmb[i].probed && !vmb[i].attached) 1200 break; 1201 1202 if (i == VMK80XX_MAX_BOARDS) { 1203 mutex_unlock(&glb_mutex); 1204 return -ENODEV; 1205 } 1206 1207 dev = &vmb[i]; 1208 1209 down(&dev->limit_sem); 1210 1211 cdev->board_name = dev->board.name; 1212 cdev->private = dev; 1213 1214 if (dev->board.model == VMK8055_MODEL) 1215 n_subd = 5; 1216 else 1217 n_subd = 6; 1218 1219 if (alloc_subdevices(cdev, n_subd) < 0) { 1220 up(&dev->limit_sem); 1221 mutex_unlock(&glb_mutex); 1222 return -ENOMEM; 1223 } 1224 1225 /* Analog input subdevice */ 1226 s = cdev->subdevices + VMK80XX_SUBD_AI; 1227 s->type = COMEDI_SUBD_AI; 1228 s->subdev_flags = SDF_READABLE | SDF_GROUND; 1229 s->n_chan = dev->board.ai_chans; 1230 s->maxdata = (1 << dev->board.ai_bits) - 1; 1231 s->range_table = dev->board.range; 1232 s->insn_read = vmk80xx_ai_rinsn; 1233 1234 /* Analog output subdevice */ 1235 s = cdev->subdevices + VMK80XX_SUBD_AO; 1236 s->type = COMEDI_SUBD_AO; 1237 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; 1238 s->n_chan = dev->board.ao_chans; 1239 s->maxdata = (1 << dev->board.ao_bits) - 1; 1240 s->range_table = dev->board.range; 1241 s->insn_write = vmk80xx_ao_winsn; 1242 1243 if (dev->board.model == VMK8061_MODEL) { 1244 s->subdev_flags |= SDF_READABLE; 1245 s->insn_read = vmk80xx_ao_rinsn; 1246 } 1247 1248 /* Digital input subdevice */ 1249 s = cdev->subdevices + VMK80XX_SUBD_DI; 1250 s->type = COMEDI_SUBD_DI; 1251 s->subdev_flags = SDF_READABLE | SDF_GROUND; 1252 s->n_chan = dev->board.di_chans; 1253 s->maxdata = 1; 1254 s->insn_read = vmk80xx_di_rinsn; 1255 s->insn_bits = vmk80xx_di_bits; 1256 1257 /* Digital output subdevice */ 1258 s = cdev->subdevices + VMK80XX_SUBD_DO; 1259 s->type = COMEDI_SUBD_DO; 1260 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; 1261 s->n_chan = dev->board.do_chans; 1262 s->maxdata = 1; 1263 s->insn_write = vmk80xx_do_winsn; 1264 s->insn_bits = vmk80xx_do_bits; 1265 1266 if (dev->board.model == VMK8061_MODEL) { 1267 s->subdev_flags |= SDF_READABLE; 1268 s->insn_read = vmk80xx_do_rinsn; 1269 } 1270 1271 /* Counter subdevice */ 1272 s = cdev->subdevices + VMK80XX_SUBD_CNT; 1273 s->type = COMEDI_SUBD_COUNTER; 1274 s->subdev_flags = SDF_READABLE; 1275 s->n_chan = dev->board.cnt_chans; 1276 s->insn_read = vmk80xx_cnt_rinsn; 1277 s->insn_config = vmk80xx_cnt_cinsn; 1278 1279 if (dev->board.model == VMK8055_MODEL) { 1280 s->subdev_flags |= SDF_WRITEABLE; 1281 s->maxdata = (1 << dev->board.cnt_bits) - 1; 1282 s->insn_write = vmk80xx_cnt_winsn; 1283 } 1284 1285 /* PWM subdevice */ 1286 if (dev->board.model == VMK8061_MODEL) { 1287 s = cdev->subdevices + VMK80XX_SUBD_PWM; 1288 s->type = COMEDI_SUBD_PWM; 1289 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; 1290 s->n_chan = dev->board.pwm_chans; 1291 s->maxdata = (1 << dev->board.pwm_bits) - 1; 1292 s->insn_read = vmk80xx_pwm_rinsn; 1293 s->insn_write = vmk80xx_pwm_winsn; 1294 } 1295 1296 dev->attached = 1; 1297 1298 minor = cdev->minor; 1299 1300 printk(KERN_INFO 1301 "comedi%d: vmk80xx: board #%d [%s] attached to comedi\n", 1302 minor, dev->count, dev->board.name); 1303 1304 up(&dev->limit_sem); 1305 mutex_unlock(&glb_mutex); 1306 1307 return 0; 1308} 1309 1310static int vmk80xx_detach(struct comedi_device *cdev) 1311{ 1312 struct vmk80xx_usb *dev; 1313 int minor; 1314 1315 dbgvm("vmk80xx: %s\n", __func__); 1316 1317 if (!cdev) 1318 return -EFAULT; 1319 1320 dev = cdev->private; 1321 if (!dev) 1322 return -EFAULT; 1323 1324 down(&dev->limit_sem); 1325 1326 cdev->private = NULL; 1327 dev->attached = 0; 1328 1329 minor = cdev->minor; 1330 1331 printk(KERN_INFO 1332 "comedi%d: vmk80xx: board #%d [%s] detached from comedi\n", 1333 minor, dev->count, dev->board.name); 1334 1335 up(&dev->limit_sem); 1336 1337 return 0; 1338} 1339 1340static int vmk80xx_probe(struct usb_interface *intf, 1341 const struct usb_device_id *id) 1342{ 1343 int i; 1344 struct vmk80xx_usb *dev; 1345 struct usb_host_interface *iface_desc; 1346 struct usb_endpoint_descriptor *ep_desc; 1347 size_t size; 1348 1349 dbgvm("vmk80xx: %s\n", __func__); 1350 1351 mutex_lock(&glb_mutex); 1352 1353 for (i = 0; i < VMK80XX_MAX_BOARDS; i++) 1354 if (!vmb[i].probed) 1355 break; 1356 1357 if (i == VMK80XX_MAX_BOARDS) { 1358 mutex_unlock(&glb_mutex); 1359 return -EMFILE; 1360 } 1361 1362 dev = &vmb[i]; 1363 1364 memset(dev, 0x00, sizeof(struct vmk80xx_usb)); 1365 dev->count = i; 1366 1367 iface_desc = intf->cur_altsetting; 1368 if (iface_desc->desc.bNumEndpoints != 2) 1369 goto error; 1370 1371 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { 1372 ep_desc = &iface_desc->endpoint[i].desc; 1373 1374 if (usb_endpoint_is_int_in(ep_desc)) { 1375 dev->ep_rx = ep_desc; 1376 continue; 1377 } 1378 1379 if (usb_endpoint_is_int_out(ep_desc)) { 1380 dev->ep_tx = ep_desc; 1381 continue; 1382 } 1383 1384 if (usb_endpoint_is_bulk_in(ep_desc)) { 1385 dev->ep_rx = ep_desc; 1386 continue; 1387 } 1388 1389 if (usb_endpoint_is_bulk_out(ep_desc)) { 1390 dev->ep_tx = ep_desc; 1391 continue; 1392 } 1393 } 1394 1395 if (!dev->ep_rx || !dev->ep_tx) 1396 goto error; 1397 1398 size = le16_to_cpu(dev->ep_rx->wMaxPacketSize); 1399 dev->usb_rx_buf = kmalloc(size, GFP_KERNEL); 1400 if (!dev->usb_rx_buf) { 1401 mutex_unlock(&glb_mutex); 1402 return -ENOMEM; 1403 } 1404 1405 size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); 1406 dev->usb_tx_buf = kmalloc(size, GFP_KERNEL); 1407 if (!dev->usb_tx_buf) { 1408 kfree(dev->usb_rx_buf); 1409 mutex_unlock(&glb_mutex); 1410 return -ENOMEM; 1411 } 1412 1413 dev->udev = interface_to_usbdev(intf); 1414 dev->intf = intf; 1415 1416 sema_init(&dev->limit_sem, 8); 1417 init_waitqueue_head(&dev->read_wait); 1418 init_waitqueue_head(&dev->write_wait); 1419 1420 init_usb_anchor(&dev->rx_anchor); 1421 init_usb_anchor(&dev->tx_anchor); 1422 1423 usb_set_intfdata(intf, dev); 1424 1425 switch (id->driver_info) { 1426 case DEVICE_VMK8055: 1427 dev->board.name = "K8055 (VM110)"; 1428 dev->board.model = VMK8055_MODEL; 1429 dev->board.range = &vmk8055_range; 1430 dev->board.ai_chans = 2; 1431 dev->board.ai_bits = 8; 1432 dev->board.ao_chans = 2; 1433 dev->board.ao_bits = 8; 1434 dev->board.di_chans = 5; 1435 dev->board.di_bits = 1; 1436 dev->board.do_chans = 8; 1437 dev->board.do_bits = 1; 1438 dev->board.cnt_chans = 2; 1439 dev->board.cnt_bits = 16; 1440 dev->board.pwm_chans = 0; 1441 dev->board.pwm_bits = 0; 1442 break; 1443 case DEVICE_VMK8061: 1444 dev->board.name = "K8061 (VM140)"; 1445 dev->board.model = VMK8061_MODEL; 1446 dev->board.range = &vmk8061_range; 1447 dev->board.ai_chans = 8; 1448 dev->board.ai_bits = 10; 1449 dev->board.ao_chans = 8; 1450 dev->board.ao_bits = 8; 1451 dev->board.di_chans = 8; 1452 dev->board.di_bits = 1; 1453 dev->board.do_chans = 8; 1454 dev->board.do_bits = 1; 1455 dev->board.cnt_chans = 2; 1456 dev->board.cnt_bits = 0; 1457 dev->board.pwm_chans = 1; 1458 dev->board.pwm_bits = 10; 1459 break; 1460 } 1461 1462 if (dev->board.model == VMK8061_MODEL) { 1463 vmk80xx_read_eeprom(dev, IC3_VERSION); 1464 printk(KERN_INFO "comedi#: vmk80xx: %s\n", dev->fw.ic3_vers); 1465 1466 if (vmk80xx_check_data_link(dev)) { 1467 vmk80xx_read_eeprom(dev, IC6_VERSION); 1468 printk(KERN_INFO "comedi#: vmk80xx: %s\n", 1469 dev->fw.ic6_vers); 1470 } else { 1471 dbgcm("comedi#: vmk80xx: no conn. to CPU\n"); 1472 } 1473 } 1474 1475 if (dev->board.model == VMK8055_MODEL) 1476 vmk80xx_reset_device(dev); 1477 1478 dev->probed = 1; 1479 1480 printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now attached\n", 1481 dev->count, dev->board.name); 1482 1483 mutex_unlock(&glb_mutex); 1484 1485 comedi_usb_auto_config(dev->udev, BOARDNAME); 1486 1487 return 0; 1488error: 1489 mutex_unlock(&glb_mutex); 1490 1491 return -ENODEV; 1492} 1493 1494static void vmk80xx_disconnect(struct usb_interface *intf) 1495{ 1496 struct vmk80xx_usb *dev = usb_get_intfdata(intf); 1497 1498 dbgvm("vmk80xx: %s\n", __func__); 1499 1500 if (!dev) 1501 return; 1502 1503 comedi_usb_auto_unconfig(dev->udev); 1504 1505 mutex_lock(&glb_mutex); 1506 down(&dev->limit_sem); 1507 1508 dev->probed = 0; 1509 usb_set_intfdata(dev->intf, NULL); 1510 1511 usb_kill_anchored_urbs(&dev->rx_anchor); 1512 usb_kill_anchored_urbs(&dev->tx_anchor); 1513 1514 kfree(dev->usb_rx_buf); 1515 kfree(dev->usb_tx_buf); 1516 1517 printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now detached\n", 1518 dev->count, dev->board.name); 1519 1520 up(&dev->limit_sem); 1521 mutex_unlock(&glb_mutex); 1522} 1523 1524/* TODO: Add support for suspend, resume, pre_reset, 1525 * post_reset and flush */ 1526static struct usb_driver vmk80xx_driver = { 1527 .name = "vmk80xx", 1528 .probe = vmk80xx_probe, 1529 .disconnect = vmk80xx_disconnect, 1530 .id_table = vmk80xx_id_table 1531}; 1532 1533static struct comedi_driver driver_vmk80xx = { 1534 .module = THIS_MODULE, 1535 .driver_name = "vmk80xx", 1536 .attach = vmk80xx_attach, 1537 .detach = vmk80xx_detach 1538}; 1539 1540static int __init vmk80xx_init(void) 1541{ 1542 int retval; 1543 1544 printk(KERN_INFO "vmk80xx: version 0.8.01 " 1545 "Manuel Gebele <forensixs@gmx.de>\n"); 1546 1547 retval = comedi_driver_register(&driver_vmk80xx); 1548 if (retval < 0) 1549 return retval; 1550 1551 return usb_register(&vmk80xx_driver); 1552} 1553 1554static void __exit vmk80xx_exit(void) 1555{ 1556 comedi_driver_unregister(&driver_vmk80xx); 1557 usb_deregister(&vmk80xx_driver); 1558} 1559 1560module_init(vmk80xx_init); 1561module_exit(vmk80xx_exit); 1562