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