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