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