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