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