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