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