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