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