Version:  2.0.40 2.2.26 2.4.37 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6

Linux/drivers/staging/comedi/drivers/vmk80xx.c

  1 /*
  2  * 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 
 21 /*
 22  * Driver: vmk80xx
 23  * Description: Velleman USB Board Low-Level Driver
 24  * Devices: [Velleman] K8055 (K8055/VM110), K8061 (K8061/VM140),
 25  *   VM110 (K8055/VM110), VM140 (K8061/VM140)
 26  * Author: Manuel Gebele <forensixs@gmx.de>
 27  * Updated: Sun, 10 May 2009 11:14:59 +0200
 28  * Status: works
 29  *
 30  * Supports:
 31  *  - analog input
 32  *  - analog output
 33  *  - digital input
 34  *  - digital output
 35  *  - counter
 36  *  - pwm
 37  */
 38 
 39 #include <linux/kernel.h>
 40 #include <linux/module.h>
 41 #include <linux/mutex.h>
 42 #include <linux/errno.h>
 43 #include <linux/input.h>
 44 #include <linux/slab.h>
 45 #include <linux/poll.h>
 46 #include <linux/uaccess.h>
 47 
 48 #include "../comedi_usb.h"
 49 
 50 enum {
 51         DEVICE_VMK8055,
 52         DEVICE_VMK8061
 53 };
 54 
 55 #define VMK8055_DI_REG          0x00
 56 #define VMK8055_DO_REG          0x01
 57 #define VMK8055_AO1_REG         0x02
 58 #define VMK8055_AO2_REG         0x03
 59 #define VMK8055_AI1_REG         0x02
 60 #define VMK8055_AI2_REG         0x03
 61 #define VMK8055_CNT1_REG        0x04
 62 #define VMK8055_CNT2_REG        0x06
 63 
 64 #define VMK8061_CH_REG          0x01
 65 #define VMK8061_DI_REG          0x01
 66 #define VMK8061_DO_REG          0x01
 67 #define VMK8061_PWM_REG1        0x01
 68 #define VMK8061_PWM_REG2        0x02
 69 #define VMK8061_CNT_REG         0x02
 70 #define VMK8061_AO_REG          0x02
 71 #define VMK8061_AI_REG1         0x02
 72 #define VMK8061_AI_REG2         0x03
 73 
 74 #define VMK8055_CMD_RST         0x00
 75 #define VMK8055_CMD_DEB1_TIME   0x01
 76 #define VMK8055_CMD_DEB2_TIME   0x02
 77 #define VMK8055_CMD_RST_CNT1    0x03
 78 #define VMK8055_CMD_RST_CNT2    0x04
 79 #define VMK8055_CMD_WRT_AD      0x05
 80 
 81 #define VMK8061_CMD_RD_AI       0x00
 82 #define VMK8061_CMR_RD_ALL_AI   0x01    /* !non-active! */
 83 #define VMK8061_CMD_SET_AO      0x02
 84 #define VMK8061_CMD_SET_ALL_AO  0x03    /* !non-active! */
 85 #define VMK8061_CMD_OUT_PWM     0x04
 86 #define VMK8061_CMD_RD_DI       0x05
 87 #define VMK8061_CMD_DO          0x06    /* !non-active! */
 88 #define VMK8061_CMD_CLR_DO      0x07
 89 #define VMK8061_CMD_SET_DO      0x08
 90 #define VMK8061_CMD_RD_CNT      0x09    /* TODO: completely pointless? */
 91 #define VMK8061_CMD_RST_CNT     0x0a    /* TODO: completely pointless? */
 92 #define VMK8061_CMD_RD_VERSION  0x0b    /* internal usage */
 93 #define VMK8061_CMD_RD_JMP_STAT 0x0c    /* TODO: not implemented yet */
 94 #define VMK8061_CMD_RD_PWR_STAT 0x0d    /* internal usage */
 95 #define VMK8061_CMD_RD_DO       0x0e
 96 #define VMK8061_CMD_RD_AO       0x0f
 97 #define VMK8061_CMD_RD_PWM      0x10
 98 
 99 #define IC3_VERSION             BIT(0)
100 #define IC6_VERSION             BIT(1)
101 
102 enum vmk80xx_model {
103         VMK8055_MODEL,
104         VMK8061_MODEL
105 };
106 
107 static const struct comedi_lrange vmk8061_range = {
108         2, {
109                 UNI_RANGE(5),
110                 UNI_RANGE(10)
111         }
112 };
113 
114 struct vmk80xx_board {
115         const char *name;
116         enum vmk80xx_model model;
117         const struct comedi_lrange *range;
118         int ai_nchans;
119         unsigned int ai_maxdata;
120         int ao_nchans;
121         int di_nchans;
122         unsigned int cnt_maxdata;
123         int pwm_nchans;
124         unsigned int pwm_maxdata;
125 };
126 
127 static const struct vmk80xx_board vmk80xx_boardinfo[] = {
128         [DEVICE_VMK8055] = {
129                 .name           = "K8055 (VM110)",
130                 .model          = VMK8055_MODEL,
131                 .range          = &range_unipolar5,
132                 .ai_nchans      = 2,
133                 .ai_maxdata     = 0x00ff,
134                 .ao_nchans      = 2,
135                 .di_nchans      = 6,
136                 .cnt_maxdata    = 0xffff,
137         },
138         [DEVICE_VMK8061] = {
139                 .name           = "K8061 (VM140)",
140                 .model          = VMK8061_MODEL,
141                 .range          = &vmk8061_range,
142                 .ai_nchans      = 8,
143                 .ai_maxdata     = 0x03ff,
144                 .ao_nchans      = 8,
145                 .di_nchans      = 8,
146                 .cnt_maxdata    = 0,    /* unknown, device is not writeable */
147                 .pwm_nchans     = 1,
148                 .pwm_maxdata    = 0x03ff,
149         },
150 };
151 
152 struct vmk80xx_private {
153         struct usb_endpoint_descriptor *ep_rx;
154         struct usb_endpoint_descriptor *ep_tx;
155         struct semaphore limit_sem;
156         unsigned char *usb_rx_buf;
157         unsigned char *usb_tx_buf;
158         enum vmk80xx_model model;
159 };
160 
161 static void vmk80xx_do_bulk_msg(struct comedi_device *dev)
162 {
163         struct vmk80xx_private *devpriv = dev->private;
164         struct usb_device *usb = comedi_to_usb_dev(dev);
165         __u8 tx_addr;
166         __u8 rx_addr;
167         unsigned int tx_pipe;
168         unsigned int rx_pipe;
169         size_t size;
170 
171         tx_addr = devpriv->ep_tx->bEndpointAddress;
172         rx_addr = devpriv->ep_rx->bEndpointAddress;
173         tx_pipe = usb_sndbulkpipe(usb, tx_addr);
174         rx_pipe = usb_rcvbulkpipe(usb, rx_addr);
175 
176         /*
177          * The max packet size attributes of the K8061
178          * input/output endpoints are identical
179          */
180         size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
181 
182         usb_bulk_msg(usb, tx_pipe, devpriv->usb_tx_buf,
183                      size, NULL, devpriv->ep_tx->bInterval);
184         usb_bulk_msg(usb, rx_pipe, devpriv->usb_rx_buf, size, NULL, HZ * 10);
185 }
186 
187 static int vmk80xx_read_packet(struct comedi_device *dev)
188 {
189         struct vmk80xx_private *devpriv = dev->private;
190         struct usb_device *usb = comedi_to_usb_dev(dev);
191         struct usb_endpoint_descriptor *ep;
192         unsigned int pipe;
193 
194         if (devpriv->model == VMK8061_MODEL) {
195                 vmk80xx_do_bulk_msg(dev);
196                 return 0;
197         }
198 
199         ep = devpriv->ep_rx;
200         pipe = usb_rcvintpipe(usb, ep->bEndpointAddress);
201         return usb_interrupt_msg(usb, pipe, devpriv->usb_rx_buf,
202                                  le16_to_cpu(ep->wMaxPacketSize), NULL,
203                                  HZ * 10);
204 }
205 
206 static int vmk80xx_write_packet(struct comedi_device *dev, int cmd)
207 {
208         struct vmk80xx_private *devpriv = dev->private;
209         struct usb_device *usb = comedi_to_usb_dev(dev);
210         struct usb_endpoint_descriptor *ep;
211         unsigned int pipe;
212 
213         devpriv->usb_tx_buf[0] = cmd;
214 
215         if (devpriv->model == VMK8061_MODEL) {
216                 vmk80xx_do_bulk_msg(dev);
217                 return 0;
218         }
219 
220         ep = devpriv->ep_tx;
221         pipe = usb_sndintpipe(usb, ep->bEndpointAddress);
222         return usb_interrupt_msg(usb, pipe, devpriv->usb_tx_buf,
223                                  le16_to_cpu(ep->wMaxPacketSize), NULL,
224                                  HZ * 10);
225 }
226 
227 static int vmk80xx_reset_device(struct comedi_device *dev)
228 {
229         struct vmk80xx_private *devpriv = dev->private;
230         size_t size;
231         int retval;
232 
233         size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
234         memset(devpriv->usb_tx_buf, 0, size);
235         retval = vmk80xx_write_packet(dev, VMK8055_CMD_RST);
236         if (retval)
237                 return retval;
238         /* set outputs to known state as we cannot read them */
239         return vmk80xx_write_packet(dev, VMK8055_CMD_WRT_AD);
240 }
241 
242 static int vmk80xx_ai_insn_read(struct comedi_device *dev,
243                                 struct comedi_subdevice *s,
244                                 struct comedi_insn *insn,
245                                 unsigned int *data)
246 {
247         struct vmk80xx_private *devpriv = dev->private;
248         int chan;
249         int reg[2];
250         int n;
251 
252         down(&devpriv->limit_sem);
253         chan = CR_CHAN(insn->chanspec);
254 
255         switch (devpriv->model) {
256         case VMK8055_MODEL:
257                 if (!chan)
258                         reg[0] = VMK8055_AI1_REG;
259                 else
260                         reg[0] = VMK8055_AI2_REG;
261                 break;
262         case VMK8061_MODEL:
263         default:
264                 reg[0] = VMK8061_AI_REG1;
265                 reg[1] = VMK8061_AI_REG2;
266                 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
267                 devpriv->usb_tx_buf[VMK8061_CH_REG] = chan;
268                 break;
269         }
270 
271         for (n = 0; n < insn->n; n++) {
272                 if (vmk80xx_read_packet(dev))
273                         break;
274 
275                 if (devpriv->model == VMK8055_MODEL) {
276                         data[n] = devpriv->usb_rx_buf[reg[0]];
277                         continue;
278                 }
279 
280                 /* VMK8061_MODEL */
281                 data[n] = devpriv->usb_rx_buf[reg[0]] + 256 *
282                     devpriv->usb_rx_buf[reg[1]];
283         }
284 
285         up(&devpriv->limit_sem);
286 
287         return n;
288 }
289 
290 static int vmk80xx_ao_insn_write(struct comedi_device *dev,
291                                  struct comedi_subdevice *s,
292                                  struct comedi_insn *insn,
293                                  unsigned int *data)
294 {
295         struct vmk80xx_private *devpriv = dev->private;
296         int chan;
297         int cmd;
298         int reg;
299         int n;
300 
301         down(&devpriv->limit_sem);
302         chan = CR_CHAN(insn->chanspec);
303 
304         switch (devpriv->model) {
305         case VMK8055_MODEL:
306                 cmd = VMK8055_CMD_WRT_AD;
307                 if (!chan)
308                         reg = VMK8055_AO1_REG;
309                 else
310                         reg = VMK8055_AO2_REG;
311                 break;
312         default:                /* NOTE: avoid compiler warnings */
313                 cmd = VMK8061_CMD_SET_AO;
314                 reg = VMK8061_AO_REG;
315                 devpriv->usb_tx_buf[VMK8061_CH_REG] = chan;
316                 break;
317         }
318 
319         for (n = 0; n < insn->n; n++) {
320                 devpriv->usb_tx_buf[reg] = data[n];
321 
322                 if (vmk80xx_write_packet(dev, cmd))
323                         break;
324         }
325 
326         up(&devpriv->limit_sem);
327 
328         return n;
329 }
330 
331 static int vmk80xx_ao_insn_read(struct comedi_device *dev,
332                                 struct comedi_subdevice *s,
333                                 struct comedi_insn *insn,
334                                 unsigned int *data)
335 {
336         struct vmk80xx_private *devpriv = dev->private;
337         int chan;
338         int reg;
339         int n;
340 
341         down(&devpriv->limit_sem);
342         chan = CR_CHAN(insn->chanspec);
343 
344         reg = VMK8061_AO_REG - 1;
345 
346         devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AO;
347 
348         for (n = 0; n < insn->n; n++) {
349                 if (vmk80xx_read_packet(dev))
350                         break;
351 
352                 data[n] = devpriv->usb_rx_buf[reg + chan];
353         }
354 
355         up(&devpriv->limit_sem);
356 
357         return n;
358 }
359 
360 static int vmk80xx_di_insn_bits(struct comedi_device *dev,
361                                 struct comedi_subdevice *s,
362                                 struct comedi_insn *insn,
363                                 unsigned int *data)
364 {
365         struct vmk80xx_private *devpriv = dev->private;
366         unsigned char *rx_buf;
367         int reg;
368         int retval;
369 
370         down(&devpriv->limit_sem);
371 
372         rx_buf = devpriv->usb_rx_buf;
373 
374         if (devpriv->model == VMK8061_MODEL) {
375                 reg = VMK8061_DI_REG;
376                 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DI;
377         } else {
378                 reg = VMK8055_DI_REG;
379         }
380 
381         retval = vmk80xx_read_packet(dev);
382 
383         if (!retval) {
384                 if (devpriv->model == VMK8055_MODEL)
385                         data[1] = (((rx_buf[reg] >> 4) & 0x03) |
386                                   ((rx_buf[reg] << 2) & 0x04) |
387                                   ((rx_buf[reg] >> 3) & 0x18));
388                 else
389                         data[1] = rx_buf[reg];
390 
391                 retval = 2;
392         }
393 
394         up(&devpriv->limit_sem);
395 
396         return retval;
397 }
398 
399 static int vmk80xx_do_insn_bits(struct comedi_device *dev,
400                                 struct comedi_subdevice *s,
401                                 struct comedi_insn *insn,
402                                 unsigned int *data)
403 {
404         struct vmk80xx_private *devpriv = dev->private;
405         unsigned char *rx_buf = devpriv->usb_rx_buf;
406         unsigned char *tx_buf = devpriv->usb_tx_buf;
407         int reg, cmd;
408         int ret = 0;
409 
410         if (devpriv->model == VMK8061_MODEL) {
411                 reg = VMK8061_DO_REG;
412                 cmd = VMK8061_CMD_DO;
413         } else { /* VMK8055_MODEL */
414                 reg = VMK8055_DO_REG;
415                 cmd = VMK8055_CMD_WRT_AD;
416         }
417 
418         down(&devpriv->limit_sem);
419 
420         if (comedi_dio_update_state(s, data)) {
421                 tx_buf[reg] = s->state;
422                 ret = vmk80xx_write_packet(dev, cmd);
423                 if (ret)
424                         goto out;
425         }
426 
427         if (devpriv->model == VMK8061_MODEL) {
428                 tx_buf[0] = VMK8061_CMD_RD_DO;
429                 ret = vmk80xx_read_packet(dev);
430                 if (ret)
431                         goto out;
432                 data[1] = rx_buf[reg];
433         } else {
434                 data[1] = s->state;
435         }
436 
437 out:
438         up(&devpriv->limit_sem);
439 
440         return ret ? ret : insn->n;
441 }
442 
443 static int vmk80xx_cnt_insn_read(struct comedi_device *dev,
444                                  struct comedi_subdevice *s,
445                                  struct comedi_insn *insn,
446                                  unsigned int *data)
447 {
448         struct vmk80xx_private *devpriv = dev->private;
449         int chan;
450         int reg[2];
451         int n;
452 
453         down(&devpriv->limit_sem);
454         chan = CR_CHAN(insn->chanspec);
455 
456         switch (devpriv->model) {
457         case VMK8055_MODEL:
458                 if (!chan)
459                         reg[0] = VMK8055_CNT1_REG;
460                 else
461                         reg[0] = VMK8055_CNT2_REG;
462                 break;
463         case VMK8061_MODEL:
464         default:
465                 reg[0] = VMK8061_CNT_REG;
466                 reg[1] = VMK8061_CNT_REG;
467                 devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
468                 break;
469         }
470 
471         for (n = 0; n < insn->n; n++) {
472                 if (vmk80xx_read_packet(dev))
473                         break;
474 
475                 if (devpriv->model == VMK8055_MODEL)
476                         data[n] = devpriv->usb_rx_buf[reg[0]];
477                 else /* VMK8061_MODEL */
478                         data[n] = devpriv->usb_rx_buf[reg[0] * (chan + 1) + 1]
479                             + 256 * devpriv->usb_rx_buf[reg[1] * 2 + 2];
480         }
481 
482         up(&devpriv->limit_sem);
483 
484         return n;
485 }
486 
487 static int vmk80xx_cnt_insn_config(struct comedi_device *dev,
488                                    struct comedi_subdevice *s,
489                                    struct comedi_insn *insn,
490                                    unsigned int *data)
491 {
492         struct vmk80xx_private *devpriv = dev->private;
493         unsigned int chan = CR_CHAN(insn->chanspec);
494         int cmd;
495         int reg;
496         int ret;
497 
498         down(&devpriv->limit_sem);
499         switch (data[0]) {
500         case INSN_CONFIG_RESET:
501                 if (devpriv->model == VMK8055_MODEL) {
502                         if (!chan) {
503                                 cmd = VMK8055_CMD_RST_CNT1;
504                                 reg = VMK8055_CNT1_REG;
505                         } else {
506                                 cmd = VMK8055_CMD_RST_CNT2;
507                                 reg = VMK8055_CNT2_REG;
508                         }
509                         devpriv->usb_tx_buf[reg] = 0x00;
510                 } else {
511                         cmd = VMK8061_CMD_RST_CNT;
512                 }
513                 ret = vmk80xx_write_packet(dev, cmd);
514                 break;
515         default:
516                 ret = -EINVAL;
517                 break;
518         }
519         up(&devpriv->limit_sem);
520 
521         return ret ? ret : insn->n;
522 }
523 
524 static int vmk80xx_cnt_insn_write(struct comedi_device *dev,
525                                   struct comedi_subdevice *s,
526                                   struct comedi_insn *insn,
527                                   unsigned int *data)
528 {
529         struct vmk80xx_private *devpriv = dev->private;
530         unsigned long debtime;
531         unsigned long val;
532         int chan;
533         int cmd;
534         int n;
535 
536         down(&devpriv->limit_sem);
537         chan = CR_CHAN(insn->chanspec);
538 
539         if (!chan)
540                 cmd = VMK8055_CMD_DEB1_TIME;
541         else
542                 cmd = VMK8055_CMD_DEB2_TIME;
543 
544         for (n = 0; n < insn->n; n++) {
545                 debtime = data[n];
546                 if (debtime == 0)
547                         debtime = 1;
548 
549                 /* TODO: Prevent overflows */
550                 if (debtime > 7450)
551                         debtime = 7450;
552 
553                 val = int_sqrt(debtime * 1000 / 115);
554                 if (((val + 1) * val) < debtime * 1000 / 115)
555                         val += 1;
556 
557                 devpriv->usb_tx_buf[6 + chan] = val;
558 
559                 if (vmk80xx_write_packet(dev, cmd))
560                         break;
561         }
562 
563         up(&devpriv->limit_sem);
564 
565         return n;
566 }
567 
568 static int vmk80xx_pwm_insn_read(struct comedi_device *dev,
569                                  struct comedi_subdevice *s,
570                                  struct comedi_insn *insn,
571                                  unsigned int *data)
572 {
573         struct vmk80xx_private *devpriv = dev->private;
574         unsigned char *tx_buf;
575         unsigned char *rx_buf;
576         int reg[2];
577         int n;
578 
579         down(&devpriv->limit_sem);
580 
581         tx_buf = devpriv->usb_tx_buf;
582         rx_buf = devpriv->usb_rx_buf;
583 
584         reg[0] = VMK8061_PWM_REG1;
585         reg[1] = VMK8061_PWM_REG2;
586 
587         tx_buf[0] = VMK8061_CMD_RD_PWM;
588 
589         for (n = 0; n < insn->n; n++) {
590                 if (vmk80xx_read_packet(dev))
591                         break;
592 
593                 data[n] = rx_buf[reg[0]] + 4 * rx_buf[reg[1]];
594         }
595 
596         up(&devpriv->limit_sem);
597 
598         return n;
599 }
600 
601 static int vmk80xx_pwm_insn_write(struct comedi_device *dev,
602                                   struct comedi_subdevice *s,
603                                   struct comedi_insn *insn,
604                                   unsigned int *data)
605 {
606         struct vmk80xx_private *devpriv = dev->private;
607         unsigned char *tx_buf;
608         int reg[2];
609         int cmd;
610         int n;
611 
612         down(&devpriv->limit_sem);
613 
614         tx_buf = devpriv->usb_tx_buf;
615 
616         reg[0] = VMK8061_PWM_REG1;
617         reg[1] = VMK8061_PWM_REG2;
618 
619         cmd = VMK8061_CMD_OUT_PWM;
620 
621         /*
622          * The followin piece of code was translated from the inline
623          * assembler code in the DLL source code.
624          *
625          * asm
626          *   mov eax, k  ; k is the value (data[n])
627          *   and al, 03h ; al are the lower 8 bits of eax
628          *   mov lo, al  ; lo is the low part (tx_buf[reg[0]])
629          *   mov eax, k
630          *   shr eax, 2  ; right shift eax register by 2
631          *   mov hi, al  ; hi is the high part (tx_buf[reg[1]])
632          * end;
633          */
634         for (n = 0; n < insn->n; n++) {
635                 tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03);
636                 tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff;
637 
638                 if (vmk80xx_write_packet(dev, cmd))
639                         break;
640         }
641 
642         up(&devpriv->limit_sem);
643 
644         return n;
645 }
646 
647 static int vmk80xx_find_usb_endpoints(struct comedi_device *dev)
648 {
649         struct vmk80xx_private *devpriv = dev->private;
650         struct usb_interface *intf = comedi_to_usb_interface(dev);
651         struct usb_host_interface *iface_desc = intf->cur_altsetting;
652         struct usb_endpoint_descriptor *ep_desc;
653         int i;
654 
655         if (iface_desc->desc.bNumEndpoints != 2)
656                 return -ENODEV;
657 
658         for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
659                 ep_desc = &iface_desc->endpoint[i].desc;
660 
661                 if (usb_endpoint_is_int_in(ep_desc) ||
662                     usb_endpoint_is_bulk_in(ep_desc)) {
663                         if (!devpriv->ep_rx)
664                                 devpriv->ep_rx = ep_desc;
665                         continue;
666                 }
667 
668                 if (usb_endpoint_is_int_out(ep_desc) ||
669                     usb_endpoint_is_bulk_out(ep_desc)) {
670                         if (!devpriv->ep_tx)
671                                 devpriv->ep_tx = ep_desc;
672                         continue;
673                 }
674         }
675 
676         if (!devpriv->ep_rx || !devpriv->ep_tx)
677                 return -ENODEV;
678 
679         return 0;
680 }
681 
682 static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev)
683 {
684         struct vmk80xx_private *devpriv = dev->private;
685         size_t size;
686 
687         size = le16_to_cpu(devpriv->ep_rx->wMaxPacketSize);
688         devpriv->usb_rx_buf = kzalloc(size, GFP_KERNEL);
689         if (!devpriv->usb_rx_buf)
690                 return -ENOMEM;
691 
692         size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
693         devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL);
694         if (!devpriv->usb_tx_buf) {
695                 kfree(devpriv->usb_rx_buf);
696                 return -ENOMEM;
697         }
698 
699         return 0;
700 }
701 
702 static int vmk80xx_init_subdevices(struct comedi_device *dev)
703 {
704         const struct vmk80xx_board *board = dev->board_ptr;
705         struct vmk80xx_private *devpriv = dev->private;
706         struct comedi_subdevice *s;
707         int n_subd;
708         int ret;
709 
710         down(&devpriv->limit_sem);
711 
712         if (devpriv->model == VMK8055_MODEL)
713                 n_subd = 5;
714         else
715                 n_subd = 6;
716         ret = comedi_alloc_subdevices(dev, n_subd);
717         if (ret) {
718                 up(&devpriv->limit_sem);
719                 return ret;
720         }
721 
722         /* Analog input subdevice */
723         s = &dev->subdevices[0];
724         s->type         = COMEDI_SUBD_AI;
725         s->subdev_flags = SDF_READABLE | SDF_GROUND;
726         s->n_chan       = board->ai_nchans;
727         s->maxdata      = board->ai_maxdata;
728         s->range_table  = board->range;
729         s->insn_read    = vmk80xx_ai_insn_read;
730 
731         /* Analog output subdevice */
732         s = &dev->subdevices[1];
733         s->type         = COMEDI_SUBD_AO;
734         s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
735         s->n_chan       = board->ao_nchans;
736         s->maxdata      = 0x00ff;
737         s->range_table  = board->range;
738         s->insn_write   = vmk80xx_ao_insn_write;
739         if (devpriv->model == VMK8061_MODEL) {
740                 s->subdev_flags |= SDF_READABLE;
741                 s->insn_read    = vmk80xx_ao_insn_read;
742         }
743 
744         /* Digital input subdevice */
745         s = &dev->subdevices[2];
746         s->type         = COMEDI_SUBD_DI;
747         s->subdev_flags = SDF_READABLE;
748         s->n_chan       = board->di_nchans;
749         s->maxdata      = 1;
750         s->range_table  = &range_digital;
751         s->insn_bits    = vmk80xx_di_insn_bits;
752 
753         /* Digital output subdevice */
754         s = &dev->subdevices[3];
755         s->type         = COMEDI_SUBD_DO;
756         s->subdev_flags = SDF_WRITABLE;
757         s->n_chan       = 8;
758         s->maxdata      = 1;
759         s->range_table  = &range_digital;
760         s->insn_bits    = vmk80xx_do_insn_bits;
761 
762         /* Counter subdevice */
763         s = &dev->subdevices[4];
764         s->type         = COMEDI_SUBD_COUNTER;
765         s->subdev_flags = SDF_READABLE;
766         s->n_chan       = 2;
767         s->maxdata      = board->cnt_maxdata;
768         s->insn_read    = vmk80xx_cnt_insn_read;
769         s->insn_config  = vmk80xx_cnt_insn_config;
770         if (devpriv->model == VMK8055_MODEL) {
771                 s->subdev_flags |= SDF_WRITABLE;
772                 s->insn_write   = vmk80xx_cnt_insn_write;
773         }
774 
775         /* PWM subdevice */
776         if (devpriv->model == VMK8061_MODEL) {
777                 s = &dev->subdevices[5];
778                 s->type         = COMEDI_SUBD_PWM;
779                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
780                 s->n_chan       = board->pwm_nchans;
781                 s->maxdata      = board->pwm_maxdata;
782                 s->insn_read    = vmk80xx_pwm_insn_read;
783                 s->insn_write   = vmk80xx_pwm_insn_write;
784         }
785 
786         up(&devpriv->limit_sem);
787 
788         return 0;
789 }
790 
791 static int vmk80xx_auto_attach(struct comedi_device *dev,
792                                unsigned long context)
793 {
794         struct usb_interface *intf = comedi_to_usb_interface(dev);
795         const struct vmk80xx_board *board = NULL;
796         struct vmk80xx_private *devpriv;
797         int ret;
798 
799         if (context < ARRAY_SIZE(vmk80xx_boardinfo))
800                 board = &vmk80xx_boardinfo[context];
801         if (!board)
802                 return -ENODEV;
803         dev->board_ptr = board;
804         dev->board_name = board->name;
805 
806         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
807         if (!devpriv)
808                 return -ENOMEM;
809 
810         devpriv->model = board->model;
811 
812         ret = vmk80xx_find_usb_endpoints(dev);
813         if (ret)
814                 return ret;
815 
816         ret = vmk80xx_alloc_usb_buffers(dev);
817         if (ret)
818                 return ret;
819 
820         sema_init(&devpriv->limit_sem, 8);
821 
822         usb_set_intfdata(intf, devpriv);
823 
824         if (devpriv->model == VMK8055_MODEL)
825                 vmk80xx_reset_device(dev);
826 
827         return vmk80xx_init_subdevices(dev);
828 }
829 
830 static void vmk80xx_detach(struct comedi_device *dev)
831 {
832         struct usb_interface *intf = comedi_to_usb_interface(dev);
833         struct vmk80xx_private *devpriv = dev->private;
834 
835         if (!devpriv)
836                 return;
837 
838         down(&devpriv->limit_sem);
839 
840         usb_set_intfdata(intf, NULL);
841 
842         kfree(devpriv->usb_rx_buf);
843         kfree(devpriv->usb_tx_buf);
844 
845         up(&devpriv->limit_sem);
846 }
847 
848 static struct comedi_driver vmk80xx_driver = {
849         .module         = THIS_MODULE,
850         .driver_name    = "vmk80xx",
851         .auto_attach    = vmk80xx_auto_attach,
852         .detach         = vmk80xx_detach,
853 };
854 
855 static int vmk80xx_usb_probe(struct usb_interface *intf,
856                              const struct usb_device_id *id)
857 {
858         return comedi_usb_auto_config(intf, &vmk80xx_driver, id->driver_info);
859 }
860 
861 static const struct usb_device_id vmk80xx_usb_id_table[] = {
862         { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 },
863         { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 },
864         { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 },
865         { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 },
866         { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 },
867         { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 },
868         { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 },
869         { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 },
870         { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 },
871         { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 },
872         { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 },
873         { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 },
874         { }
875 };
876 MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table);
877 
878 static struct usb_driver vmk80xx_usb_driver = {
879         .name           = "vmk80xx",
880         .id_table       = vmk80xx_usb_id_table,
881         .probe          = vmk80xx_usb_probe,
882         .disconnect     = comedi_usb_auto_unconfig,
883 };
884 module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
885 
886 MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
887 MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
888 MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
889 MODULE_LICENSE("GPL");
890 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us