]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/serial2002.c
Merge branch 'for-4.8/core' of git://git.kernel.dk/linux-block
[karo-tx-linux.git] / drivers / staging / comedi / drivers / serial2002.c
1 /*
2  * serial2002.c
3  * Comedi driver for serial connected hardware
4  *
5  * COMEDI - Linux Control and Measurement Device Interface
6  * Copyright (C) 2002 Anders Blomdell <anders.blomdell@control.lth.se>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  */
18
19 /*
20  * Driver: serial2002
21  * Description: Driver for serial connected hardware
22  * Devices:
23  * Author: Anders Blomdell
24  * Updated: Fri,  7 Jun 2002 12:56:45 -0700
25  * Status: in development
26  */
27
28 #include <linux/module.h>
29 #include "../comedidev.h"
30
31 #include <linux/delay.h>
32 #include <linux/sched.h>
33 #include <linux/slab.h>
34 #include <linux/ktime.h>
35
36 #include <linux/termios.h>
37 #include <asm/ioctls.h>
38 #include <linux/serial.h>
39 #include <linux/poll.h>
40
41 struct serial2002_range_table_t {
42         /*  HACK... */
43         int length;
44         struct comedi_krange range;
45 };
46
47 struct serial2002_private {
48         int port;               /*  /dev/ttyS<port> */
49         int speed;              /*  baudrate */
50         struct file *tty;
51         unsigned int ao_readback[32];
52         unsigned char digital_in_mapping[32];
53         unsigned char digital_out_mapping[32];
54         unsigned char analog_in_mapping[32];
55         unsigned char analog_out_mapping[32];
56         unsigned char encoder_in_mapping[32];
57         struct serial2002_range_table_t in_range[32], out_range[32];
58 };
59
60 struct serial_data {
61         enum { is_invalid, is_digital, is_channel } kind;
62         int index;
63         unsigned long value;
64 };
65
66 /*
67  * The configuration serial_data.value read from the device is
68  * a bitmask that defines specific options of a channel:
69  *
70  * 4:0 - the channel to configure
71  * 7:5 - the kind of channel
72  * 9:8 - the command used to configure the channel
73  *
74  * The remaining bits vary in use depending on the command:
75  *
76  * BITS     15:10 - the channel bits (maxdata)
77  * MIN/MAX  12:10 - the units multiplier for the scale
78  *          13    - the sign of the scale
79  *          33:14 - the base value for the range
80  */
81 #define S2002_CFG_CHAN(x)               ((x) & 0x1f)
82 #define S2002_CFG_KIND(x)               (((x) >> 5) & 0x7)
83 #define S2002_CFG_KIND_INVALID          0
84 #define S2002_CFG_KIND_DIGITAL_IN       1
85 #define S2002_CFG_KIND_DIGITAL_OUT      2
86 #define S2002_CFG_KIND_ANALOG_IN        3
87 #define S2002_CFG_KIND_ANALOG_OUT       4
88 #define S2002_CFG_KIND_ENCODER_IN       5
89 #define S2002_CFG_CMD(x)                (((x) >> 8) & 0x3)
90 #define S2002_CFG_CMD_BITS              0
91 #define S2002_CFG_CMD_MIN               1
92 #define S2002_CFG_CMD_MAX               2
93 #define S2002_CFG_BITS(x)               (((x) >> 10) & 0x3f)
94 #define S2002_CFG_UNITS(x)              (((x) >> 10) & 0x7)
95 #define S2002_CFG_SIGN(x)               (((x) >> 13) & 0x1)
96 #define S2002_CFG_BASE(x)               (((x) >> 14) & 0xfffff)
97
98 static long serial2002_tty_ioctl(struct file *f, unsigned int op,
99                                  unsigned long param)
100 {
101         if (f->f_op->unlocked_ioctl)
102                 return f->f_op->unlocked_ioctl(f, op, param);
103
104         return -ENOTTY;
105 }
106
107 static int serial2002_tty_write(struct file *f, unsigned char *buf, int count)
108 {
109         const char __user *p = (__force const char __user *)buf;
110         int result;
111         loff_t offset = 0;
112         mm_segment_t oldfs;
113
114         oldfs = get_fs();
115         set_fs(KERNEL_DS);
116         result = __vfs_write(f, p, count, &offset);
117         set_fs(oldfs);
118         return result;
119 }
120
121 static void serial2002_tty_read_poll_wait(struct file *f, int timeout)
122 {
123         struct poll_wqueues table;
124         ktime_t start, now;
125
126         start = ktime_get();
127         poll_initwait(&table);
128         while (1) {
129                 long elapsed;
130                 int mask;
131
132                 mask = f->f_op->poll(f, &table.pt);
133                 if (mask & (POLLRDNORM | POLLRDBAND | POLLIN |
134                             POLLHUP | POLLERR)) {
135                         break;
136                 }
137                 now = ktime_get();
138                 elapsed = ktime_us_delta(now, start);
139                 if (elapsed > timeout)
140                         break;
141                 set_current_state(TASK_INTERRUPTIBLE);
142                 schedule_timeout(((timeout - elapsed) * HZ) / 10000);
143         }
144         poll_freewait(&table);
145 }
146
147 static int serial2002_tty_read(struct file *f, int timeout)
148 {
149         unsigned char ch;
150         int result;
151
152         result = -1;
153         if (!IS_ERR(f)) {
154                 mm_segment_t oldfs;
155                 char __user *p = (__force char __user *)&ch;
156                 loff_t offset = 0;
157
158                 oldfs = get_fs();
159                 set_fs(KERNEL_DS);
160                 if (f->f_op->poll) {
161                         serial2002_tty_read_poll_wait(f, timeout);
162
163                         if (__vfs_read(f, p, 1, &offset) == 1)
164                                 result = ch;
165                 } else {
166                         /* Device does not support poll, busy wait */
167                         int retries = 0;
168
169                         while (1) {
170                                 retries++;
171                                 if (retries >= timeout)
172                                         break;
173
174                                 if (__vfs_read(f, p, 1, &offset) == 1) {
175                                         result = ch;
176                                         break;
177                                 }
178                                 usleep_range(100, 1000);
179                         }
180                 }
181                 set_fs(oldfs);
182         }
183         return result;
184 }
185
186 static void serial2002_tty_setspeed(struct file *f, int speed)
187 {
188         struct termios termios;
189         struct serial_struct serial;
190         mm_segment_t oldfs;
191
192         oldfs = get_fs();
193         set_fs(KERNEL_DS);
194
195         /* Set speed */
196         serial2002_tty_ioctl(f, TCGETS, (unsigned long)&termios);
197         termios.c_iflag = 0;
198         termios.c_oflag = 0;
199         termios.c_lflag = 0;
200         termios.c_cflag = CLOCAL | CS8 | CREAD;
201         termios.c_cc[VMIN] = 0;
202         termios.c_cc[VTIME] = 0;
203         switch (speed) {
204         case 2400:
205                 termios.c_cflag |= B2400;
206                 break;
207         case 4800:
208                 termios.c_cflag |= B4800;
209                 break;
210         case 9600:
211                 termios.c_cflag |= B9600;
212                 break;
213         case 19200:
214                 termios.c_cflag |= B19200;
215                 break;
216         case 38400:
217                 termios.c_cflag |= B38400;
218                 break;
219         case 57600:
220                 termios.c_cflag |= B57600;
221                 break;
222         case 115200:
223                 termios.c_cflag |= B115200;
224                 break;
225         default:
226                 termios.c_cflag |= B9600;
227                 break;
228         }
229         serial2002_tty_ioctl(f, TCSETS, (unsigned long)&termios);
230
231         /* Set low latency */
232         serial2002_tty_ioctl(f, TIOCGSERIAL, (unsigned long)&serial);
233         serial.flags |= ASYNC_LOW_LATENCY;
234         serial2002_tty_ioctl(f, TIOCSSERIAL, (unsigned long)&serial);
235
236         set_fs(oldfs);
237 }
238
239 static void serial2002_poll_digital(struct file *f, int channel)
240 {
241         char cmd;
242
243         cmd = 0x40 | (channel & 0x1f);
244         serial2002_tty_write(f, &cmd, 1);
245 }
246
247 static void serial2002_poll_channel(struct file *f, int channel)
248 {
249         char cmd;
250
251         cmd = 0x60 | (channel & 0x1f);
252         serial2002_tty_write(f, &cmd, 1);
253 }
254
255 static struct serial_data serial2002_read(struct file *f, int timeout)
256 {
257         struct serial_data result;
258         int length;
259
260         result.kind = is_invalid;
261         result.index = 0;
262         result.value = 0;
263         length = 0;
264         while (1) {
265                 int data = serial2002_tty_read(f, timeout);
266
267                 length++;
268                 if (data < 0) {
269                         break;
270                 } else if (data & 0x80) {
271                         result.value = (result.value << 7) | (data & 0x7f);
272                 } else {
273                         if (length == 1) {
274                                 switch ((data >> 5) & 0x03) {
275                                 case 0:
276                                         result.value = 0;
277                                         result.kind = is_digital;
278                                         break;
279                                 case 1:
280                                         result.value = 1;
281                                         result.kind = is_digital;
282                                         break;
283                                 }
284                         } else {
285                                 result.value =
286                                     (result.value << 2) | ((data & 0x60) >> 5);
287                                 result.kind = is_channel;
288                         }
289                         result.index = data & 0x1f;
290                         break;
291                 }
292         }
293         return result;
294 }
295
296 static void serial2002_write(struct file *f, struct serial_data data)
297 {
298         if (data.kind == is_digital) {
299                 unsigned char ch =
300                     ((data.value << 5) & 0x20) | (data.index & 0x1f);
301                 serial2002_tty_write(f, &ch, 1);
302         } else {
303                 unsigned char ch[6];
304                 int i = 0;
305
306                 if (data.value >= (1L << 30)) {
307                         ch[i] = 0x80 | ((data.value >> 30) & 0x03);
308                         i++;
309                 }
310                 if (data.value >= (1L << 23)) {
311                         ch[i] = 0x80 | ((data.value >> 23) & 0x7f);
312                         i++;
313                 }
314                 if (data.value >= (1L << 16)) {
315                         ch[i] = 0x80 | ((data.value >> 16) & 0x7f);
316                         i++;
317                 }
318                 if (data.value >= (1L << 9)) {
319                         ch[i] = 0x80 | ((data.value >> 9) & 0x7f);
320                         i++;
321                 }
322                 ch[i] = 0x80 | ((data.value >> 2) & 0x7f);
323                 i++;
324                 ch[i] = ((data.value << 5) & 0x60) | (data.index & 0x1f);
325                 i++;
326                 serial2002_tty_write(f, ch, i);
327         }
328 }
329
330 struct config_t {
331         short int kind;
332         short int bits;
333         int min;
334         int max;
335 };
336
337 static int serial2002_setup_subdevice(struct comedi_subdevice *s,
338                                       struct config_t *cfg,
339                                       struct serial2002_range_table_t *range,
340                                       unsigned char *mapping,
341                                       int kind)
342 {
343         const struct comedi_lrange **range_table_list = NULL;
344         unsigned int *maxdata_list;
345         int j, chan;
346
347         for (chan = 0, j = 0; j < 32; j++) {
348                 if (cfg[j].kind == kind)
349                         chan++;
350         }
351         s->n_chan = chan;
352         s->maxdata = 0;
353         kfree(s->maxdata_list);
354         maxdata_list = kmalloc_array(s->n_chan, sizeof(unsigned int),
355                                      GFP_KERNEL);
356         if (!maxdata_list)
357                 return -ENOMEM;
358         s->maxdata_list = maxdata_list;
359         kfree(s->range_table_list);
360         s->range_table = NULL;
361         s->range_table_list = NULL;
362         if (kind == 1 || kind == 2) {
363                 s->range_table = &range_digital;
364         } else if (range) {
365                 range_table_list = kmalloc_array(s->n_chan, sizeof(*range),
366                                                  GFP_KERNEL);
367                 if (!range_table_list)
368                         return -ENOMEM;
369                 s->range_table_list = range_table_list;
370         }
371         for (chan = 0, j = 0; j < 32; j++) {
372                 if (cfg[j].kind == kind) {
373                         if (mapping)
374                                 mapping[chan] = j;
375                         if (range && range_table_list) {
376                                 range[j].length = 1;
377                                 range[j].range.min = cfg[j].min;
378                                 range[j].range.max = cfg[j].max;
379                                 range_table_list[chan] =
380                                     (const struct comedi_lrange *)&range[j];
381                         }
382                         if (cfg[j].bits < 32)
383                                 maxdata_list[chan] = (1u << cfg[j].bits) - 1;
384                         else
385                                 maxdata_list[chan] = 0xffffffff;
386                         chan++;
387                 }
388         }
389         return 0;
390 }
391
392 static int serial2002_setup_subdevs(struct comedi_device *dev)
393 {
394         struct serial2002_private *devpriv = dev->private;
395         struct config_t *di_cfg;
396         struct config_t *do_cfg;
397         struct config_t *ai_cfg;
398         struct config_t *ao_cfg;
399         struct config_t *cfg;
400         struct comedi_subdevice *s;
401         int result = 0;
402         int i;
403
404         /* Allocate the temporary structs to hold the configuration data */
405         di_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL);
406         do_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL);
407         ai_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL);
408         ao_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL);
409         if (!di_cfg || !do_cfg || !ai_cfg || !ao_cfg) {
410                 result = -ENOMEM;
411                 goto err_alloc_configs;
412         }
413
414         /* Read the configuration from the connected device */
415         serial2002_tty_setspeed(devpriv->tty, devpriv->speed);
416         serial2002_poll_channel(devpriv->tty, 31);
417         while (1) {
418                 struct serial_data data = serial2002_read(devpriv->tty, 1000);
419                 int kind = S2002_CFG_KIND(data.value);
420                 int channel = S2002_CFG_CHAN(data.value);
421                 int range = S2002_CFG_BASE(data.value);
422                 int cmd = S2002_CFG_CMD(data.value);
423
424                 if (data.kind != is_channel || data.index != 31 ||
425                     kind == S2002_CFG_KIND_INVALID)
426                         break;
427
428                 switch (kind) {
429                 case S2002_CFG_KIND_DIGITAL_IN:
430                         cfg = di_cfg;
431                         break;
432                 case S2002_CFG_KIND_DIGITAL_OUT:
433                         cfg = do_cfg;
434                         break;
435                 case S2002_CFG_KIND_ANALOG_IN:
436                         cfg = ai_cfg;
437                         break;
438                 case S2002_CFG_KIND_ANALOG_OUT:
439                         cfg = ao_cfg;
440                         break;
441                 case S2002_CFG_KIND_ENCODER_IN:
442                         cfg = ai_cfg;
443                         break;
444                 default:
445                         cfg = NULL;
446                         break;
447                 }
448                 if (!cfg)
449                         continue;       /* unknown kind, skip it */
450
451                 cfg[channel].kind = kind;
452
453                 switch (cmd) {
454                 case S2002_CFG_CMD_BITS:
455                         cfg[channel].bits = S2002_CFG_BITS(data.value);
456                         break;
457                 case S2002_CFG_CMD_MIN:
458                 case S2002_CFG_CMD_MAX:
459                         switch (S2002_CFG_UNITS(data.value)) {
460                         case 0:
461                                 range *= 1000000;
462                                 break;
463                         case 1:
464                                 range *= 1000;
465                                 break;
466                         case 2:
467                                 range *= 1;
468                                 break;
469                         }
470                         if (S2002_CFG_SIGN(data.value))
471                                 range = -range;
472                         if (cmd == S2002_CFG_CMD_MIN)
473                                 cfg[channel].min = range;
474                         else
475                                 cfg[channel].max = range;
476                         break;
477                 }
478         }
479
480         /* Fill in subdevice data */
481         for (i = 0; i <= 4; i++) {
482                 unsigned char *mapping = NULL;
483                 struct serial2002_range_table_t *range = NULL;
484                 int kind = 0;
485
486                 s = &dev->subdevices[i];
487
488                 switch (i) {
489                 case 0:
490                         cfg = di_cfg;
491                         mapping = devpriv->digital_in_mapping;
492                         kind = S2002_CFG_KIND_DIGITAL_IN;
493                         break;
494                 case 1:
495                         cfg = do_cfg;
496                         mapping = devpriv->digital_out_mapping;
497                         kind = S2002_CFG_KIND_DIGITAL_OUT;
498                         break;
499                 case 2:
500                         cfg = ai_cfg;
501                         mapping = devpriv->analog_in_mapping;
502                         range = devpriv->in_range;
503                         kind = S2002_CFG_KIND_ANALOG_IN;
504                         break;
505                 case 3:
506                         cfg = ao_cfg;
507                         mapping = devpriv->analog_out_mapping;
508                         range = devpriv->out_range;
509                         kind = S2002_CFG_KIND_ANALOG_OUT;
510                         break;
511                 case 4:
512                         cfg = ai_cfg;
513                         mapping = devpriv->encoder_in_mapping;
514                         range = devpriv->in_range;
515                         kind = S2002_CFG_KIND_ENCODER_IN;
516                         break;
517                 }
518
519                 if (serial2002_setup_subdevice(s, cfg, range, mapping, kind))
520                         break;  /* err handled below */
521         }
522         if (i <= 4) {
523                 /*
524                  * Failed to allocate maxdata_list or range_table_list
525                  * for a subdevice that needed it.
526                  */
527                 result = -ENOMEM;
528                 for (i = 0; i <= 4; i++) {
529                         s = &dev->subdevices[i];
530                         kfree(s->maxdata_list);
531                         s->maxdata_list = NULL;
532                         kfree(s->range_table_list);
533                         s->range_table_list = NULL;
534                 }
535         }
536
537 err_alloc_configs:
538         kfree(di_cfg);
539         kfree(do_cfg);
540         kfree(ai_cfg);
541         kfree(ao_cfg);
542
543         if (result) {
544                 if (devpriv->tty) {
545                         filp_close(devpriv->tty, NULL);
546                         devpriv->tty = NULL;
547                 }
548         }
549
550         return result;
551 }
552
553 static int serial2002_open(struct comedi_device *dev)
554 {
555         struct serial2002_private *devpriv = dev->private;
556         int result;
557         char port[20];
558
559         sprintf(port, "/dev/ttyS%d", devpriv->port);
560         devpriv->tty = filp_open(port, O_RDWR, 0);
561         if (IS_ERR(devpriv->tty)) {
562                 result = (int)PTR_ERR(devpriv->tty);
563                 dev_err(dev->class_dev, "file open error = %d\n", result);
564         } else {
565                 result = serial2002_setup_subdevs(dev);
566         }
567         return result;
568 }
569
570 static void serial2002_close(struct comedi_device *dev)
571 {
572         struct serial2002_private *devpriv = dev->private;
573
574         if (!IS_ERR(devpriv->tty) && devpriv->tty)
575                 filp_close(devpriv->tty, NULL);
576 }
577
578 static int serial2002_di_insn_read(struct comedi_device *dev,
579                                    struct comedi_subdevice *s,
580                                    struct comedi_insn *insn,
581                                    unsigned int *data)
582 {
583         struct serial2002_private *devpriv = dev->private;
584         int n;
585         int chan;
586
587         chan = devpriv->digital_in_mapping[CR_CHAN(insn->chanspec)];
588         for (n = 0; n < insn->n; n++) {
589                 struct serial_data read;
590
591                 serial2002_poll_digital(devpriv->tty, chan);
592                 while (1) {
593                         read = serial2002_read(devpriv->tty, 1000);
594                         if (read.kind != is_digital || read.index == chan)
595                                 break;
596                 }
597                 data[n] = read.value;
598         }
599         return n;
600 }
601
602 static int serial2002_do_insn_write(struct comedi_device *dev,
603                                     struct comedi_subdevice *s,
604                                     struct comedi_insn *insn,
605                                     unsigned int *data)
606 {
607         struct serial2002_private *devpriv = dev->private;
608         int n;
609         int chan;
610
611         chan = devpriv->digital_out_mapping[CR_CHAN(insn->chanspec)];
612         for (n = 0; n < insn->n; n++) {
613                 struct serial_data write;
614
615                 write.kind = is_digital;
616                 write.index = chan;
617                 write.value = data[n];
618                 serial2002_write(devpriv->tty, write);
619         }
620         return n;
621 }
622
623 static int serial2002_ai_insn_read(struct comedi_device *dev,
624                                    struct comedi_subdevice *s,
625                                    struct comedi_insn *insn,
626                                    unsigned int *data)
627 {
628         struct serial2002_private *devpriv = dev->private;
629         int n;
630         int chan;
631
632         chan = devpriv->analog_in_mapping[CR_CHAN(insn->chanspec)];
633         for (n = 0; n < insn->n; n++) {
634                 struct serial_data read;
635
636                 serial2002_poll_channel(devpriv->tty, chan);
637                 while (1) {
638                         read = serial2002_read(devpriv->tty, 1000);
639                         if (read.kind != is_channel || read.index == chan)
640                                 break;
641                 }
642                 data[n] = read.value;
643         }
644         return n;
645 }
646
647 static int serial2002_ao_insn_write(struct comedi_device *dev,
648                                     struct comedi_subdevice *s,
649                                     struct comedi_insn *insn,
650                                     unsigned int *data)
651 {
652         struct serial2002_private *devpriv = dev->private;
653         int n;
654         int chan;
655
656         chan = devpriv->analog_out_mapping[CR_CHAN(insn->chanspec)];
657         for (n = 0; n < insn->n; n++) {
658                 struct serial_data write;
659
660                 write.kind = is_channel;
661                 write.index = chan;
662                 write.value = data[n];
663                 serial2002_write(devpriv->tty, write);
664                 devpriv->ao_readback[chan] = data[n];
665         }
666         return n;
667 }
668
669 static int serial2002_ao_insn_read(struct comedi_device *dev,
670                                    struct comedi_subdevice *s,
671                                    struct comedi_insn *insn,
672                                    unsigned int *data)
673 {
674         struct serial2002_private *devpriv = dev->private;
675         int n;
676         int chan = CR_CHAN(insn->chanspec);
677
678         for (n = 0; n < insn->n; n++)
679                 data[n] = devpriv->ao_readback[chan];
680
681         return n;
682 }
683
684 static int serial2002_encoder_insn_read(struct comedi_device *dev,
685                                         struct comedi_subdevice *s,
686                                         struct comedi_insn *insn,
687                                         unsigned int *data)
688 {
689         struct serial2002_private *devpriv = dev->private;
690         int n;
691         int chan;
692
693         chan = devpriv->encoder_in_mapping[CR_CHAN(insn->chanspec)];
694         for (n = 0; n < insn->n; n++) {
695                 struct serial_data read;
696
697                 serial2002_poll_channel(devpriv->tty, chan);
698                 while (1) {
699                         read = serial2002_read(devpriv->tty, 1000);
700                         if (read.kind != is_channel || read.index == chan)
701                                 break;
702                 }
703                 data[n] = read.value;
704         }
705         return n;
706 }
707
708 static int serial2002_attach(struct comedi_device *dev,
709                              struct comedi_devconfig *it)
710 {
711         struct serial2002_private *devpriv;
712         struct comedi_subdevice *s;
713         int ret;
714
715         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
716         if (!devpriv)
717                 return -ENOMEM;
718
719         devpriv->port = it->options[0];
720         devpriv->speed = it->options[1];
721
722         ret = comedi_alloc_subdevices(dev, 5);
723         if (ret)
724                 return ret;
725
726         /* digital input subdevice */
727         s = &dev->subdevices[0];
728         s->type         = COMEDI_SUBD_DI;
729         s->subdev_flags = SDF_READABLE;
730         s->n_chan       = 0;
731         s->maxdata      = 1;
732         s->range_table  = &range_digital;
733         s->insn_read    = serial2002_di_insn_read;
734
735         /* digital output subdevice */
736         s = &dev->subdevices[1];
737         s->type         = COMEDI_SUBD_DO;
738         s->subdev_flags = SDF_WRITABLE;
739         s->n_chan       = 0;
740         s->maxdata      = 1;
741         s->range_table  = &range_digital;
742         s->insn_write   = serial2002_do_insn_write;
743
744         /* analog input subdevice */
745         s = &dev->subdevices[2];
746         s->type         = COMEDI_SUBD_AI;
747         s->subdev_flags = SDF_READABLE | SDF_GROUND;
748         s->n_chan       = 0;
749         s->maxdata      = 1;
750         s->range_table  = NULL;
751         s->insn_read    = serial2002_ai_insn_read;
752
753         /* analog output subdevice */
754         s = &dev->subdevices[3];
755         s->type         = COMEDI_SUBD_AO;
756         s->subdev_flags = SDF_WRITABLE;
757         s->n_chan       = 0;
758         s->maxdata      = 1;
759         s->range_table  = NULL;
760         s->insn_write   = serial2002_ao_insn_write;
761         s->insn_read    = serial2002_ao_insn_read;
762
763         /* encoder input subdevice */
764         s = &dev->subdevices[4];
765         s->type         = COMEDI_SUBD_COUNTER;
766         s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
767         s->n_chan       = 0;
768         s->maxdata      = 1;
769         s->range_table  = NULL;
770         s->insn_read    = serial2002_encoder_insn_read;
771
772         dev->open       = serial2002_open;
773         dev->close      = serial2002_close;
774
775         return 0;
776 }
777
778 static void serial2002_detach(struct comedi_device *dev)
779 {
780         struct comedi_subdevice *s;
781         int i;
782
783         for (i = 0; i < dev->n_subdevices; i++) {
784                 s = &dev->subdevices[i];
785                 kfree(s->maxdata_list);
786                 kfree(s->range_table_list);
787         }
788 }
789
790 static struct comedi_driver serial2002_driver = {
791         .driver_name    = "serial2002",
792         .module         = THIS_MODULE,
793         .attach         = serial2002_attach,
794         .detach         = serial2002_detach,
795 };
796 module_comedi_driver(serial2002_driver);
797
798 MODULE_AUTHOR("Comedi http://www.comedi.org");
799 MODULE_DESCRIPTION("Comedi low-level driver");
800 MODULE_LICENSE("GPL");