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