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