linux/drivers/char/n_r3964.c
<<
>>
Prefs
   1/* r3964 linediscipline for linux
   2 *
   3 * -----------------------------------------------------------
   4 * Copyright by 
   5 * Philips Automation Projects
   6 * Kassel (Germany)
   7 * http://www.pap-philips.de
   8 * -----------------------------------------------------------
   9 * This software may be used and distributed according to the terms of
  10 * the GNU General Public License, incorporated herein by reference.
  11 *
  12 * Author:
  13 * L. Haag
  14 *
  15 * $Log: n_r3964.c,v $
  16 * Revision 1.10  2001/03/18 13:02:24  dwmw2
  17 * Fix timer usage, use spinlocks properly.
  18 *
  19 * Revision 1.9  2001/03/18 12:52:14  dwmw2
  20 * Merge changes in 2.4.2
  21 *
  22 * Revision 1.8  2000/03/23 14:14:54  dwmw2
  23 * Fix race in sleeping in r3964_read()
  24 *
  25 * Revision 1.7  1999/28/08 11:41:50  dwmw2
  26 * Port to 2.3 kernel
  27 *
  28 * Revision 1.6  1998/09/30 00:40:40  dwmw2
  29 * Fixed compilation on 2.0.x kernels
  30 * Updated to newly registered tty-ldisc number 9
  31 *
  32 * Revision 1.5  1998/09/04 21:57:36  dwmw2
  33 * Signal handling bug fixes, port to 2.1.x.
  34 *
  35 * Revision 1.4  1998/04/02 20:26:59  lhaag
  36 * select, blocking, ...
  37 *
  38 * Revision 1.3  1998/02/12 18:58:43  root
  39 * fixed some memory leaks
  40 * calculation of checksum characters
  41 *
  42 * Revision 1.2  1998/02/07 13:03:34  root
  43 * ioctl read_telegram
  44 *
  45 * Revision 1.1  1998/02/06 19:21:03  root
  46 * Initial revision
  47 *
  48 *
  49 */
  50
  51#include <linux/module.h>
  52#include <linux/kernel.h>
  53#include <linux/sched.h>
  54#include <linux/types.h>
  55#include <linux/fcntl.h>
  56#include <linux/interrupt.h>
  57#include <linux/ptrace.h>
  58#include <linux/ioport.h>
  59#include <linux/in.h>
  60#include <linux/slab.h>
  61#include <linux/smp_lock.h>
  62#include <linux/tty.h>
  63#include <linux/errno.h>
  64#include <linux/string.h>       /* used in new tty drivers */
  65#include <linux/signal.h>       /* used in new tty drivers */
  66#include <linux/ioctl.h>
  67#include <linux/n_r3964.h>
  68#include <linux/poll.h>
  69#include <linux/init.h>
  70#include <asm/uaccess.h>
  71
  72/*#define DEBUG_QUEUE*/
  73
  74/* Log successful handshake and protocol operations  */
  75/*#define DEBUG_PROTO_S*/
  76
  77/* Log handshake and protocol errors: */
  78/*#define DEBUG_PROTO_E*/
  79
  80/* Log Linediscipline operations (open, close, read, write...): */
  81/*#define DEBUG_LDISC*/
  82
  83/* Log module and memory operations (init, cleanup; kmalloc, kfree): */
  84/*#define DEBUG_MODUL*/
  85
  86/* Macro helpers for debug output: */
  87#define TRACE(format, args...) printk("r3964: " format "\n" , ## args)
  88
  89#ifdef DEBUG_MODUL
  90#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)
  91#else
  92#define TRACE_M(fmt, arg...) do {} while (0)
  93#endif
  94#ifdef DEBUG_PROTO_S
  95#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)
  96#else
  97#define TRACE_PS(fmt, arg...) do {} while (0)
  98#endif
  99#ifdef DEBUG_PROTO_E
 100#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)
 101#else
 102#define TRACE_PE(fmt, arg...) do {} while (0)
 103#endif
 104#ifdef DEBUG_LDISC
 105#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)
 106#else
 107#define TRACE_L(fmt, arg...) do {} while (0)
 108#endif
 109#ifdef DEBUG_QUEUE
 110#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)
 111#else
 112#define TRACE_Q(fmt, arg...) do {} while (0)
 113#endif
 114static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
 115static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
 116static void put_char(struct r3964_info *pInfo, unsigned char ch);
 117static void trigger_transmit(struct r3964_info *pInfo);
 118static void retry_transmit(struct r3964_info *pInfo);
 119static void transmit_block(struct r3964_info *pInfo);
 120static void receive_char(struct r3964_info *pInfo, const unsigned char c);
 121static void receive_error(struct r3964_info *pInfo, const char flag);
 122static void on_timeout(unsigned long priv);
 123static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);
 124static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
 125                unsigned char __user * buf);
 126static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
 127                int error_code, struct r3964_block_header *pBlock);
 128static struct r3964_message *remove_msg(struct r3964_info *pInfo,
 129                struct r3964_client_info *pClient);
 130static void remove_client_block(struct r3964_info *pInfo,
 131                struct r3964_client_info *pClient);
 132
 133static int r3964_open(struct tty_struct *tty);
 134static void r3964_close(struct tty_struct *tty);
 135static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 136                unsigned char __user * buf, size_t nr);
 137static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
 138                const unsigned char *buf, size_t nr);
 139static int r3964_ioctl(struct tty_struct *tty, struct file *file,
 140                unsigned int cmd, unsigned long arg);
 141static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
 142static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
 143                struct poll_table_struct *wait);
 144static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 145                char *fp, int count);
 146
 147static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
 148        .owner = THIS_MODULE,
 149        .magic = TTY_LDISC_MAGIC,
 150        .name = "R3964",
 151        .open = r3964_open,
 152        .close = r3964_close,
 153        .read = r3964_read,
 154        .write = r3964_write,
 155        .ioctl = r3964_ioctl,
 156        .set_termios = r3964_set_termios,
 157        .poll = r3964_poll,
 158        .receive_buf = r3964_receive_buf,
 159};
 160
 161static void dump_block(const unsigned char *block, unsigned int length)
 162{
 163        unsigned int i, j;
 164        char linebuf[16 * 3 + 1];
 165
 166        for (i = 0; i < length; i += 16) {
 167                for (j = 0; (j < 16) && (j + i < length); j++) {
 168                        sprintf(linebuf + 3 * j, "%02x ", block[i + j]);
 169                }
 170                linebuf[3 * j] = '\0';
 171                TRACE_PS("%s", linebuf);
 172        }
 173}
 174
 175/*************************************************************
 176 * Driver initialisation
 177 *************************************************************/
 178
 179/*************************************************************
 180 * Module support routines
 181 *************************************************************/
 182
 183static void __exit r3964_exit(void)
 184{
 185        int status;
 186
 187        TRACE_M("cleanup_module()");
 188
 189        status = tty_unregister_ldisc(N_R3964);
 190
 191        if (status != 0) {
 192                printk(KERN_ERR "r3964: error unregistering linediscipline: "
 193                                "%d\n", status);
 194        } else {
 195                TRACE_L("linediscipline successfully unregistered");
 196        }
 197}
 198
 199static int __init r3964_init(void)
 200{
 201        int status;
 202
 203        printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n");
 204
 205        /*
 206         * Register the tty line discipline
 207         */
 208
 209        status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964);
 210        if (status == 0) {
 211                TRACE_L("line discipline %d registered", N_R3964);
 212                TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
 213                        tty_ldisc_N_R3964.num);
 214                TRACE_L("open=%p", tty_ldisc_N_R3964.open);
 215                TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
 216        } else {
 217                printk(KERN_ERR "r3964: error registering line discipline: "
 218                                "%d\n", status);
 219        }
 220        return status;
 221}
 222
 223module_init(r3964_init);
 224module_exit(r3964_exit);
 225
 226/*************************************************************
 227 * Protocol implementation routines
 228 *************************************************************/
 229
 230static void add_tx_queue(struct r3964_info *pInfo,
 231                         struct r3964_block_header *pHeader)
 232{
 233        unsigned long flags;
 234
 235        spin_lock_irqsave(&pInfo->lock, flags);
 236
 237        pHeader->next = NULL;
 238
 239        if (pInfo->tx_last == NULL) {
 240                pInfo->tx_first = pInfo->tx_last = pHeader;
 241        } else {
 242                pInfo->tx_last->next = pHeader;
 243                pInfo->tx_last = pHeader;
 244        }
 245
 246        spin_unlock_irqrestore(&pInfo->lock, flags);
 247
 248        TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",
 249                pHeader, pHeader->length, pInfo->tx_first);
 250}
 251
 252static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
 253{
 254        struct r3964_block_header *pHeader;
 255        unsigned long flags;
 256#ifdef DEBUG_QUEUE
 257        struct r3964_block_header *pDump;
 258#endif
 259
 260        pHeader = pInfo->tx_first;
 261
 262        if (pHeader == NULL)
 263                return;
 264
 265#ifdef DEBUG_QUEUE
 266        printk("r3964: remove_from_tx_queue: %p, length %u - ",
 267                pHeader, pHeader->length);
 268        for (pDump = pHeader; pDump; pDump = pDump->next)
 269                printk("%p ", pDump);
 270        printk("\n");
 271#endif
 272
 273        if (pHeader->owner) {
 274                if (error_code) {
 275                        add_msg(pHeader->owner, R3964_MSG_ACK, 0,
 276                                error_code, NULL);
 277                } else {
 278                        add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
 279                                error_code, NULL);
 280                }
 281                wake_up_interruptible(&pInfo->read_wait);
 282        }
 283
 284        spin_lock_irqsave(&pInfo->lock, flags);
 285
 286        pInfo->tx_first = pHeader->next;
 287        if (pInfo->tx_first == NULL) {
 288                pInfo->tx_last = NULL;
 289        }
 290
 291        spin_unlock_irqrestore(&pInfo->lock, flags);
 292
 293        kfree(pHeader);
 294        TRACE_M("remove_from_tx_queue - kfree %p", pHeader);
 295
 296        TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",
 297                pInfo->tx_first, pInfo->tx_last);
 298}
 299
 300static void add_rx_queue(struct r3964_info *pInfo,
 301                         struct r3964_block_header *pHeader)
 302{
 303        unsigned long flags;
 304
 305        spin_lock_irqsave(&pInfo->lock, flags);
 306
 307        pHeader->next = NULL;
 308
 309        if (pInfo->rx_last == NULL) {
 310                pInfo->rx_first = pInfo->rx_last = pHeader;
 311        } else {
 312                pInfo->rx_last->next = pHeader;
 313                pInfo->rx_last = pHeader;
 314        }
 315        pInfo->blocks_in_rx_queue++;
 316
 317        spin_unlock_irqrestore(&pInfo->lock, flags);
 318
 319        TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
 320                pHeader, pHeader->length,
 321                pInfo->rx_first, pInfo->blocks_in_rx_queue);
 322}
 323
 324static void remove_from_rx_queue(struct r3964_info *pInfo,
 325                                 struct r3964_block_header *pHeader)
 326{
 327        unsigned long flags;
 328        struct r3964_block_header *pFind;
 329
 330        if (pHeader == NULL)
 331                return;
 332
 333        TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
 334                pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
 335        TRACE_Q("remove_from_rx_queue: %p, length %u",
 336                pHeader, pHeader->length);
 337
 338        spin_lock_irqsave(&pInfo->lock, flags);
 339
 340        if (pInfo->rx_first == pHeader) {
 341                /* Remove the first block in the linked list: */
 342                pInfo->rx_first = pHeader->next;
 343
 344                if (pInfo->rx_first == NULL) {
 345                        pInfo->rx_last = NULL;
 346                }
 347                pInfo->blocks_in_rx_queue--;
 348        } else {
 349                /* Find block to remove: */
 350                for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) {
 351                        if (pFind->next == pHeader) {
 352                                /* Got it. */
 353                                pFind->next = pHeader->next;
 354                                pInfo->blocks_in_rx_queue--;
 355                                if (pFind->next == NULL) {
 356                                        /* Oh, removed the last one! */
 357                                        pInfo->rx_last = pFind;
 358                                }
 359                                break;
 360                        }
 361                }
 362        }
 363
 364        spin_unlock_irqrestore(&pInfo->lock, flags);
 365
 366        kfree(pHeader);
 367        TRACE_M("remove_from_rx_queue - kfree %p", pHeader);
 368
 369        TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
 370                pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
 371}
 372
 373static void put_char(struct r3964_info *pInfo, unsigned char ch)
 374{
 375        struct tty_struct *tty = pInfo->tty;
 376        /* FIXME: put_char should not be called from an IRQ */
 377        tty_put_char(tty, ch);
 378        pInfo->bcc ^= ch;
 379}
 380
 381static void flush(struct r3964_info *pInfo)
 382{
 383        struct tty_struct *tty = pInfo->tty;
 384
 385        if (tty == NULL || tty->ops->flush_chars == NULL)
 386                return;
 387        tty->ops->flush_chars(tty);
 388}
 389
 390static void trigger_transmit(struct r3964_info *pInfo)
 391{
 392        unsigned long flags;
 393
 394        spin_lock_irqsave(&pInfo->lock, flags);
 395
 396        if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) {
 397                pInfo->state = R3964_TX_REQUEST;
 398                pInfo->nRetry = 0;
 399                pInfo->flags &= ~R3964_ERROR;
 400                mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
 401
 402                spin_unlock_irqrestore(&pInfo->lock, flags);
 403
 404                TRACE_PS("trigger_transmit - sent STX");
 405
 406                put_char(pInfo, STX);
 407                flush(pInfo);
 408
 409                pInfo->bcc = 0;
 410        } else {
 411                spin_unlock_irqrestore(&pInfo->lock, flags);
 412        }
 413}
 414
 415static void retry_transmit(struct r3964_info *pInfo)
 416{
 417        if (pInfo->nRetry < R3964_MAX_RETRIES) {
 418                TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry);
 419                pInfo->bcc = 0;
 420                put_char(pInfo, STX);
 421                flush(pInfo);
 422                pInfo->state = R3964_TX_REQUEST;
 423                pInfo->nRetry++;
 424                mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
 425        } else {
 426                TRACE_PE("transmission failed after %d retries",
 427                         R3964_MAX_RETRIES);
 428
 429                remove_from_tx_queue(pInfo, R3964_TX_FAIL);
 430
 431                put_char(pInfo, NAK);
 432                flush(pInfo);
 433                pInfo->state = R3964_IDLE;
 434
 435                trigger_transmit(pInfo);
 436        }
 437}
 438
 439static void transmit_block(struct r3964_info *pInfo)
 440{
 441        struct tty_struct *tty = pInfo->tty;
 442        struct r3964_block_header *pBlock = pInfo->tx_first;
 443        int room = 0;
 444
 445        if (tty == NULL || pBlock == NULL) {
 446                return;
 447        }
 448
 449        room = tty_write_room(tty);
 450
 451        TRACE_PS("transmit_block %p, room %d, length %d",
 452                 pBlock, room, pBlock->length);
 453
 454        while (pInfo->tx_position < pBlock->length) {
 455                if (room < 2)
 456                        break;
 457
 458                if (pBlock->data[pInfo->tx_position] == DLE) {
 459                        /* send additional DLE char: */
 460                        put_char(pInfo, DLE);
 461                }
 462                put_char(pInfo, pBlock->data[pInfo->tx_position++]);
 463
 464                room--;
 465        }
 466
 467        if ((pInfo->tx_position == pBlock->length) && (room >= 3)) {
 468                put_char(pInfo, DLE);
 469                put_char(pInfo, ETX);
 470                if (pInfo->flags & R3964_BCC) {
 471                        put_char(pInfo, pInfo->bcc);
 472                }
 473                pInfo->state = R3964_WAIT_FOR_TX_ACK;
 474                mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
 475        }
 476        flush(pInfo);
 477}
 478
 479static void on_receive_block(struct r3964_info *pInfo)
 480{
 481        unsigned int length;
 482        struct r3964_client_info *pClient;
 483        struct r3964_block_header *pBlock;
 484
 485        length = pInfo->rx_position;
 486
 487        /* compare byte checksum characters: */
 488        if (pInfo->flags & R3964_BCC) {
 489                if (pInfo->bcc != pInfo->last_rx) {
 490                        TRACE_PE("checksum error - got %x but expected %x",
 491                                 pInfo->last_rx, pInfo->bcc);
 492                        pInfo->flags |= R3964_CHECKSUM;
 493                }
 494        }
 495
 496        /* check for errors (parity, overrun,...): */
 497        if (pInfo->flags & R3964_ERROR) {
 498                TRACE_PE("on_receive_block - transmission failed error %x",
 499                         pInfo->flags & R3964_ERROR);
 500
 501                put_char(pInfo, NAK);
 502                flush(pInfo);
 503                if (pInfo->nRetry < R3964_MAX_RETRIES) {
 504                        pInfo->state = R3964_WAIT_FOR_RX_REPEAT;
 505                        pInfo->nRetry++;
 506                        mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);
 507                } else {
 508                        TRACE_PE("on_receive_block - failed after max retries");
 509                        pInfo->state = R3964_IDLE;
 510                }
 511                return;
 512        }
 513
 514        /* received block; submit DLE: */
 515        put_char(pInfo, DLE);
 516        flush(pInfo);
 517        del_timer_sync(&pInfo->tmr);
 518        TRACE_PS(" rx success: got %d chars", length);
 519
 520        /* prepare struct r3964_block_header: */
 521        pBlock = kmalloc(length + sizeof(struct r3964_block_header),
 522                        GFP_KERNEL);
 523        TRACE_M("on_receive_block - kmalloc %p", pBlock);
 524
 525        if (pBlock == NULL)
 526                return;
 527
 528        pBlock->length = length;
 529        pBlock->data = ((unsigned char *)pBlock) +
 530                        sizeof(struct r3964_block_header);
 531        pBlock->locks = 0;
 532        pBlock->next = NULL;
 533        pBlock->owner = NULL;
 534
 535        memcpy(pBlock->data, pInfo->rx_buf, length);
 536
 537        /* queue block into rx_queue: */
 538        add_rx_queue(pInfo, pBlock);
 539
 540        /* notify attached client processes: */
 541        for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
 542                if (pClient->sig_flags & R3964_SIG_DATA) {
 543                        add_msg(pClient, R3964_MSG_DATA, length, R3964_OK,
 544                                pBlock);
 545                }
 546        }
 547        wake_up_interruptible(&pInfo->read_wait);
 548
 549        pInfo->state = R3964_IDLE;
 550
 551        trigger_transmit(pInfo);
 552}
 553
 554static void receive_char(struct r3964_info *pInfo, const unsigned char c)
 555{
 556        switch (pInfo->state) {
 557        case R3964_TX_REQUEST:
 558                if (c == DLE) {
 559                        TRACE_PS("TX_REQUEST - got DLE");
 560
 561                        pInfo->state = R3964_TRANSMITTING;
 562                        pInfo->tx_position = 0;
 563
 564                        transmit_block(pInfo);
 565                } else if (c == STX) {
 566                        if (pInfo->nRetry == 0) {
 567                                TRACE_PE("TX_REQUEST - init conflict");
 568                                if (pInfo->priority == R3964_SLAVE) {
 569                                        goto start_receiving;
 570                                }
 571                        } else {
 572                                TRACE_PE("TX_REQUEST - secondary init "
 573                                        "conflict!? Switching to SLAVE mode "
 574                                        "for next rx.");
 575                                goto start_receiving;
 576                        }
 577                } else {
 578                        TRACE_PE("TX_REQUEST - char != DLE: %x", c);
 579                        retry_transmit(pInfo);
 580                }
 581                break;
 582        case R3964_TRANSMITTING:
 583                if (c == NAK) {
 584                        TRACE_PE("TRANSMITTING - got NAK");
 585                        retry_transmit(pInfo);
 586                } else {
 587                        TRACE_PE("TRANSMITTING - got invalid char");
 588
 589                        pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
 590                        mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
 591                }
 592                break;
 593        case R3964_WAIT_FOR_TX_ACK:
 594                if (c == DLE) {
 595                        TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
 596                        remove_from_tx_queue(pInfo, R3964_OK);
 597
 598                        pInfo->state = R3964_IDLE;
 599                        trigger_transmit(pInfo);
 600                } else {
 601                        retry_transmit(pInfo);
 602                }
 603                break;
 604        case R3964_WAIT_FOR_RX_REPEAT:
 605                /* FALLTROUGH */
 606        case R3964_IDLE:
 607                if (c == STX) {
 608                        /* Prevent rx_queue from overflow: */
 609                        if (pInfo->blocks_in_rx_queue >=
 610                            R3964_MAX_BLOCKS_IN_RX_QUEUE) {
 611                                TRACE_PE("IDLE - got STX but no space in "
 612                                                "rx_queue!");
 613                                pInfo->state = R3964_WAIT_FOR_RX_BUF;
 614                                mod_timer(&pInfo->tmr,
 615                                          jiffies + R3964_TO_NO_BUF);
 616                                break;
 617                        }
 618start_receiving:
 619                        /* Ok, start receiving: */
 620                        TRACE_PS("IDLE - got STX");
 621                        pInfo->rx_position = 0;
 622                        pInfo->last_rx = 0;
 623                        pInfo->flags &= ~R3964_ERROR;
 624                        pInfo->state = R3964_RECEIVING;
 625                        mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
 626                        pInfo->nRetry = 0;
 627                        put_char(pInfo, DLE);
 628                        flush(pInfo);
 629                        pInfo->bcc = 0;
 630                }
 631                break;
 632        case R3964_RECEIVING:
 633                if (pInfo->rx_position < RX_BUF_SIZE) {
 634                        pInfo->bcc ^= c;
 635
 636                        if (c == DLE) {
 637                                if (pInfo->last_rx == DLE) {
 638                                        pInfo->last_rx = 0;
 639                                        goto char_to_buf;
 640                                }
 641                                pInfo->last_rx = DLE;
 642                                break;
 643                        } else if ((c == ETX) && (pInfo->last_rx == DLE)) {
 644                                if (pInfo->flags & R3964_BCC) {
 645                                        pInfo->state = R3964_WAIT_FOR_BCC;
 646                                        mod_timer(&pInfo->tmr,
 647                                                  jiffies + R3964_TO_ZVZ);
 648                                } else {
 649                                        on_receive_block(pInfo);
 650                                }
 651                        } else {
 652                                pInfo->last_rx = c;
 653char_to_buf:
 654                                pInfo->rx_buf[pInfo->rx_position++] = c;
 655                                mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
 656                        }
 657                }
 658                /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
 659                break;
 660        case R3964_WAIT_FOR_BCC:
 661                pInfo->last_rx = c;
 662                on_receive_block(pInfo);
 663                break;
 664        }
 665}
 666
 667static void receive_error(struct r3964_info *pInfo, const char flag)
 668{
 669        switch (flag) {
 670        case TTY_NORMAL:
 671                break;
 672        case TTY_BREAK:
 673                TRACE_PE("received break");
 674                pInfo->flags |= R3964_BREAK;
 675                break;
 676        case TTY_PARITY:
 677                TRACE_PE("parity error");
 678                pInfo->flags |= R3964_PARITY;
 679                break;
 680        case TTY_FRAME:
 681                TRACE_PE("frame error");
 682                pInfo->flags |= R3964_FRAME;
 683                break;
 684        case TTY_OVERRUN:
 685                TRACE_PE("frame overrun");
 686                pInfo->flags |= R3964_OVERRUN;
 687                break;
 688        default:
 689                TRACE_PE("receive_error - unknown flag %d", flag);
 690                pInfo->flags |= R3964_UNKNOWN;
 691                break;
 692        }
 693}
 694
 695static void on_timeout(unsigned long priv)
 696{
 697        struct r3964_info *pInfo = (void *)priv;
 698
 699        switch (pInfo->state) {
 700        case R3964_TX_REQUEST:
 701                TRACE_PE("TX_REQUEST - timeout");
 702                retry_transmit(pInfo);
 703                break;
 704        case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
 705                put_char(pInfo, NAK);
 706                flush(pInfo);
 707                retry_transmit(pInfo);
 708                break;
 709        case R3964_WAIT_FOR_TX_ACK:
 710                TRACE_PE("WAIT_FOR_TX_ACK - timeout");
 711                retry_transmit(pInfo);
 712                break;
 713        case R3964_WAIT_FOR_RX_BUF:
 714                TRACE_PE("WAIT_FOR_RX_BUF - timeout");
 715                put_char(pInfo, NAK);
 716                flush(pInfo);
 717                pInfo->state = R3964_IDLE;
 718                break;
 719        case R3964_RECEIVING:
 720                TRACE_PE("RECEIVING - timeout after %d chars",
 721                         pInfo->rx_position);
 722                put_char(pInfo, NAK);
 723                flush(pInfo);
 724                pInfo->state = R3964_IDLE;
 725                break;
 726        case R3964_WAIT_FOR_RX_REPEAT:
 727                TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
 728                pInfo->state = R3964_IDLE;
 729                break;
 730        case R3964_WAIT_FOR_BCC:
 731                TRACE_PE("WAIT_FOR_BCC - timeout");
 732                put_char(pInfo, NAK);
 733                flush(pInfo);
 734                pInfo->state = R3964_IDLE;
 735                break;
 736        }
 737}
 738
 739static struct r3964_client_info *findClient(struct r3964_info *pInfo,
 740                struct pid *pid)
 741{
 742        struct r3964_client_info *pClient;
 743
 744        for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
 745                if (pClient->pid == pid) {
 746                        return pClient;
 747                }
 748        }
 749        return NULL;
 750}
 751
 752static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg)
 753{
 754        struct r3964_client_info *pClient;
 755        struct r3964_client_info **ppClient;
 756        struct r3964_message *pMsg;
 757
 758        if ((arg & R3964_SIG_ALL) == 0) {
 759                /* Remove client from client list */
 760                for (ppClient = &pInfo->firstClient; *ppClient;
 761                     ppClient = &(*ppClient)->next) {
 762                        pClient = *ppClient;
 763
 764                        if (pClient->pid == pid) {
 765                                TRACE_PS("removing client %d from client list",
 766                                         pid_nr(pid));
 767                                *ppClient = pClient->next;
 768                                while (pClient->msg_count) {
 769                                        pMsg = remove_msg(pInfo, pClient);
 770                                        if (pMsg) {
 771                                                kfree(pMsg);
 772                                                TRACE_M("enable_signals - msg "
 773                                                        "kfree %p", pMsg);
 774                                        }
 775                                }
 776                                put_pid(pClient->pid);
 777                                kfree(pClient);
 778                                TRACE_M("enable_signals - kfree %p", pClient);
 779                                return 0;
 780                        }
 781                }
 782                return -EINVAL;
 783        } else {
 784                pClient = findClient(pInfo, pid);
 785                if (pClient) {
 786                        /* update signal options */
 787                        pClient->sig_flags = arg;
 788                } else {
 789                        /* add client to client list */
 790                        pClient = kmalloc(sizeof(struct r3964_client_info),
 791                                        GFP_KERNEL);
 792                        TRACE_M("enable_signals - kmalloc %p", pClient);
 793                        if (pClient == NULL)
 794                                return -ENOMEM;
 795
 796                        TRACE_PS("add client %d to client list", pid_nr(pid));
 797                        spin_lock_init(&pClient->lock);
 798                        pClient->sig_flags = arg;
 799                        pClient->pid = get_pid(pid);
 800                        pClient->next = pInfo->firstClient;
 801                        pClient->first_msg = NULL;
 802                        pClient->last_msg = NULL;
 803                        pClient->next_block_to_read = NULL;
 804                        pClient->msg_count = 0;
 805                        pInfo->firstClient = pClient;
 806                }
 807        }
 808
 809        return 0;
 810}
 811
 812static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
 813                         unsigned char __user * buf)
 814{
 815        struct r3964_client_info *pClient;
 816        struct r3964_block_header *block;
 817
 818        if (!buf) {
 819                return -EINVAL;
 820        }
 821
 822        pClient = findClient(pInfo, pid);
 823        if (pClient == NULL) {
 824                return -EINVAL;
 825        }
 826
 827        block = pClient->next_block_to_read;
 828        if (!block) {
 829                return 0;
 830        } else {
 831                if (copy_to_user(buf, block->data, block->length))
 832                        return -EFAULT;
 833
 834                remove_client_block(pInfo, pClient);
 835                return block->length;
 836        }
 837
 838        return -EINVAL;
 839}
 840
 841static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
 842                int error_code, struct r3964_block_header *pBlock)
 843{
 844        struct r3964_message *pMsg;
 845        unsigned long flags;
 846
 847        if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) {
 848queue_the_message:
 849
 850                pMsg = kmalloc(sizeof(struct r3964_message),
 851                                error_code ? GFP_ATOMIC : GFP_KERNEL);
 852                TRACE_M("add_msg - kmalloc %p", pMsg);
 853                if (pMsg == NULL) {
 854                        return;
 855                }
 856
 857                spin_lock_irqsave(&pClient->lock, flags);
 858
 859                pMsg->msg_id = msg_id;
 860                pMsg->arg = arg;
 861                pMsg->error_code = error_code;
 862                pMsg->block = pBlock;
 863                pMsg->next = NULL;
 864
 865                if (pClient->last_msg == NULL) {
 866                        pClient->first_msg = pClient->last_msg = pMsg;
 867                } else {
 868                        pClient->last_msg->next = pMsg;
 869                        pClient->last_msg = pMsg;
 870                }
 871
 872                pClient->msg_count++;
 873
 874                if (pBlock != NULL) {
 875                        pBlock->locks++;
 876                }
 877                spin_unlock_irqrestore(&pClient->lock, flags);
 878        } else {
 879                if ((pClient->last_msg->msg_id == R3964_MSG_ACK)
 880                    && (pClient->last_msg->error_code == R3964_OVERFLOW)) {
 881                        pClient->last_msg->arg++;
 882                        TRACE_PE("add_msg - inc prev OVERFLOW-msg");
 883                } else {
 884                        msg_id = R3964_MSG_ACK;
 885                        arg = 0;
 886                        error_code = R3964_OVERFLOW;
 887                        pBlock = NULL;
 888                        TRACE_PE("add_msg - queue OVERFLOW-msg");
 889                        goto queue_the_message;
 890                }
 891        }
 892        /* Send SIGIO signal to client process: */
 893        if (pClient->sig_flags & R3964_USE_SIGIO) {
 894                kill_pid(pClient->pid, SIGIO, 1);
 895        }
 896}
 897
 898static struct r3964_message *remove_msg(struct r3964_info *pInfo,
 899                                        struct r3964_client_info *pClient)
 900{
 901        struct r3964_message *pMsg = NULL;
 902        unsigned long flags;
 903
 904        if (pClient->first_msg) {
 905                spin_lock_irqsave(&pClient->lock, flags);
 906
 907                pMsg = pClient->first_msg;
 908                pClient->first_msg = pMsg->next;
 909                if (pClient->first_msg == NULL) {
 910                        pClient->last_msg = NULL;
 911                }
 912
 913                pClient->msg_count--;
 914                if (pMsg->block) {
 915                        remove_client_block(pInfo, pClient);
 916                        pClient->next_block_to_read = pMsg->block;
 917                }
 918                spin_unlock_irqrestore(&pClient->lock, flags);
 919        }
 920        return pMsg;
 921}
 922
 923static void remove_client_block(struct r3964_info *pInfo,
 924                                struct r3964_client_info *pClient)
 925{
 926        struct r3964_block_header *block;
 927
 928        TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
 929
 930        block = pClient->next_block_to_read;
 931        if (block) {
 932                block->locks--;
 933                if (block->locks == 0) {
 934                        remove_from_rx_queue(pInfo, block);
 935                }
 936        }
 937        pClient->next_block_to_read = NULL;
 938}
 939
 940/*************************************************************
 941 * Line discipline routines
 942 *************************************************************/
 943
 944static int r3964_open(struct tty_struct *tty)
 945{
 946        struct r3964_info *pInfo;
 947
 948        TRACE_L("open");
 949        TRACE_L("tty=%p, PID=%d, disc_data=%p",
 950                tty, current->pid, tty->disc_data);
 951
 952        pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
 953        TRACE_M("r3964_open - info kmalloc %p", pInfo);
 954
 955        if (!pInfo) {
 956                printk(KERN_ERR "r3964: failed to alloc info structure\n");
 957                return -ENOMEM;
 958        }
 959
 960        pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
 961        TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf);
 962
 963        if (!pInfo->rx_buf) {
 964                printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
 965                kfree(pInfo);
 966                TRACE_M("r3964_open - info kfree %p", pInfo);
 967                return -ENOMEM;
 968        }
 969
 970        pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
 971        TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf);
 972
 973        if (!pInfo->tx_buf) {
 974                printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
 975                kfree(pInfo->rx_buf);
 976                TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf);
 977                kfree(pInfo);
 978                TRACE_M("r3964_open - info kfree %p", pInfo);
 979                return -ENOMEM;
 980        }
 981
 982        spin_lock_init(&pInfo->lock);
 983        pInfo->tty = tty;
 984        init_waitqueue_head(&pInfo->read_wait);
 985        pInfo->priority = R3964_MASTER;
 986        pInfo->rx_first = pInfo->rx_last = NULL;
 987        pInfo->tx_first = pInfo->tx_last = NULL;
 988        pInfo->rx_position = 0;
 989        pInfo->tx_position = 0;
 990        pInfo->last_rx = 0;
 991        pInfo->blocks_in_rx_queue = 0;
 992        pInfo->firstClient = NULL;
 993        pInfo->state = R3964_IDLE;
 994        pInfo->flags = R3964_DEBUG;
 995        pInfo->nRetry = 0;
 996
 997        tty->disc_data = pInfo;
 998        tty->receive_room = 65536;
 999
1000        setup_timer(&pInfo->tmr, on_timeout, (unsigned long)pInfo);
1001
1002        return 0;
1003}
1004
1005static void r3964_close(struct tty_struct *tty)
1006{
1007        struct r3964_info *pInfo = tty->disc_data;
1008        struct r3964_client_info *pClient, *pNext;
1009        struct r3964_message *pMsg;
1010        struct r3964_block_header *pHeader, *pNextHeader;
1011        unsigned long flags;
1012
1013        TRACE_L("close");
1014
1015        /*
1016         * Make sure that our task queue isn't activated.  If it
1017         * is, take it out of the linked list.
1018         */
1019        del_timer_sync(&pInfo->tmr);
1020
1021        /* Remove client-structs and message queues: */
1022        pClient = pInfo->firstClient;
1023        while (pClient) {
1024                pNext = pClient->next;
1025                while (pClient->msg_count) {
1026                        pMsg = remove_msg(pInfo, pClient);
1027                        if (pMsg) {
1028                                kfree(pMsg);
1029                                TRACE_M("r3964_close - msg kfree %p", pMsg);
1030                        }
1031                }
1032                put_pid(pClient->pid);
1033                kfree(pClient);
1034                TRACE_M("r3964_close - client kfree %p", pClient);
1035                pClient = pNext;
1036        }
1037        /* Remove jobs from tx_queue: */
1038        spin_lock_irqsave(&pInfo->lock, flags);
1039        pHeader = pInfo->tx_first;
1040        pInfo->tx_first = pInfo->tx_last = NULL;
1041        spin_unlock_irqrestore(&pInfo->lock, flags);
1042
1043        while (pHeader) {
1044                pNextHeader = pHeader->next;
1045                kfree(pHeader);
1046                pHeader = pNextHeader;
1047        }
1048
1049        /* Free buffers: */
1050        wake_up_interruptible(&pInfo->read_wait);
1051        kfree(pInfo->rx_buf);
1052        TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
1053        kfree(pInfo->tx_buf);
1054        TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf);
1055        kfree(pInfo);
1056        TRACE_M("r3964_close - info kfree %p", pInfo);
1057}
1058
1059static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
1060                          unsigned char __user * buf, size_t nr)
1061{
1062        struct r3964_info *pInfo = tty->disc_data;
1063        struct r3964_client_info *pClient;
1064        struct r3964_message *pMsg;
1065        struct r3964_client_message theMsg;
1066        int ret;
1067
1068        TRACE_L("read()");
1069
1070        lock_kernel();
1071
1072        pClient = findClient(pInfo, task_pid(current));
1073        if (pClient) {
1074                pMsg = remove_msg(pInfo, pClient);
1075                if (pMsg == NULL) {
1076                        /* no messages available. */
1077                        if (file->f_flags & O_NONBLOCK) {
1078                                ret = -EAGAIN;
1079                                goto unlock;
1080                        }
1081                        /* block until there is a message: */
1082                        wait_event_interruptible(pInfo->read_wait,
1083                                        (pMsg = remove_msg(pInfo, pClient)));
1084                }
1085
1086                /* If we still haven't got a message, we must have been signalled */
1087
1088                if (!pMsg) {
1089                        ret = -EINTR;
1090                        goto unlock;
1091                }
1092
1093                /* deliver msg to client process: */
1094                theMsg.msg_id = pMsg->msg_id;
1095                theMsg.arg = pMsg->arg;
1096                theMsg.error_code = pMsg->error_code;
1097                ret = sizeof(struct r3964_client_message);
1098
1099                kfree(pMsg);
1100                TRACE_M("r3964_read - msg kfree %p", pMsg);
1101
1102                if (copy_to_user(buf, &theMsg, ret)) {
1103                        ret = -EFAULT;
1104                        goto unlock;
1105                }
1106
1107                TRACE_PS("read - return %d", ret);
1108                goto unlock;
1109        }
1110        ret = -EPERM;
1111unlock:
1112        unlock_kernel();
1113        return ret;
1114}
1115
1116static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
1117                           const unsigned char *data, size_t count)
1118{
1119        struct r3964_info *pInfo = tty->disc_data;
1120        struct r3964_block_header *pHeader;
1121        struct r3964_client_info *pClient;
1122        unsigned char *new_data;
1123
1124        TRACE_L("write request, %d characters", count);
1125/* 
1126 * Verify the pointers 
1127 */
1128
1129        if (!pInfo)
1130                return -EIO;
1131
1132/*
1133 * Ensure that the caller does not wish to send too much.
1134 */
1135        if (count > R3964_MTU) {
1136                if (pInfo->flags & R3964_DEBUG) {
1137                        TRACE_L(KERN_WARNING "r3964_write: truncating user "
1138                                "packet from %u to mtu %d", count, R3964_MTU);
1139                }
1140                count = R3964_MTU;
1141        }
1142/*
1143 * Allocate a buffer for the data and copy it from the buffer with header prepended
1144 */
1145        new_data = kmalloc(count + sizeof(struct r3964_block_header),
1146                        GFP_KERNEL);
1147        TRACE_M("r3964_write - kmalloc %p", new_data);
1148        if (new_data == NULL) {
1149                if (pInfo->flags & R3964_DEBUG) {
1150                        printk(KERN_ERR "r3964_write: no memory\n");
1151                }
1152                return -ENOSPC;
1153        }
1154
1155        pHeader = (struct r3964_block_header *)new_data;
1156        pHeader->data = new_data + sizeof(struct r3964_block_header);
1157        pHeader->length = count;
1158        pHeader->locks = 0;
1159        pHeader->owner = NULL;
1160
1161        lock_kernel();
1162
1163        pClient = findClient(pInfo, task_pid(current));
1164        if (pClient) {
1165                pHeader->owner = pClient;
1166        }
1167
1168        memcpy(pHeader->data, data, count);     /* We already verified this */
1169
1170        if (pInfo->flags & R3964_DEBUG) {
1171                dump_block(pHeader->data, count);
1172        }
1173
1174/*
1175 * Add buffer to transmit-queue:
1176 */
1177        add_tx_queue(pInfo, pHeader);
1178        trigger_transmit(pInfo);
1179
1180        unlock_kernel();
1181
1182        return 0;
1183}
1184
1185static int r3964_ioctl(struct tty_struct *tty, struct file *file,
1186                unsigned int cmd, unsigned long arg)
1187{
1188        struct r3964_info *pInfo = tty->disc_data;
1189        if (pInfo == NULL)
1190                return -EINVAL;
1191        switch (cmd) {
1192        case R3964_ENABLE_SIGNALS:
1193                return enable_signals(pInfo, task_pid(current), arg);
1194        case R3964_SETPRIORITY:
1195                if (arg < R3964_MASTER || arg > R3964_SLAVE)
1196                        return -EINVAL;
1197                pInfo->priority = arg & 0xff;
1198                return 0;
1199        case R3964_USE_BCC:
1200                if (arg)
1201                        pInfo->flags |= R3964_BCC;
1202                else
1203                        pInfo->flags &= ~R3964_BCC;
1204                return 0;
1205        case R3964_READ_TELEGRAM:
1206                return read_telegram(pInfo, task_pid(current),
1207                                (unsigned char __user *)arg);
1208        default:
1209                return -ENOIOCTLCMD;
1210        }
1211}
1212
1213static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
1214{
1215        TRACE_L("set_termios");
1216}
1217
1218/* Called without the kernel lock held - fine */
1219static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
1220                        struct poll_table_struct *wait)
1221{
1222        struct r3964_info *pInfo = tty->disc_data;
1223        struct r3964_client_info *pClient;
1224        struct r3964_message *pMsg = NULL;
1225        unsigned long flags;
1226        int result = POLLOUT;
1227
1228        TRACE_L("POLL");
1229
1230        pClient = findClient(pInfo, task_pid(current));
1231        if (pClient) {
1232                poll_wait(file, &pInfo->read_wait, wait);
1233                spin_lock_irqsave(&pInfo->lock, flags);
1234                pMsg = pClient->first_msg;
1235                spin_unlock_irqrestore(&pInfo->lock, flags);
1236                if (pMsg)
1237                        result |= POLLIN | POLLRDNORM;
1238        } else {
1239                result = -EINVAL;
1240        }
1241        return result;
1242}
1243
1244static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
1245                        char *fp, int count)
1246{
1247        struct r3964_info *pInfo = tty->disc_data;
1248        const unsigned char *p;
1249        char *f, flags = 0;
1250        int i;
1251
1252        for (i = count, p = cp, f = fp; i; i--, p++) {
1253                if (f)
1254                        flags = *f++;
1255                if (flags == TTY_NORMAL) {
1256                        receive_char(pInfo, *p);
1257                } else {
1258                        receive_error(pInfo, flags);
1259                }
1260
1261        }
1262}
1263
1264MODULE_LICENSE("GPL");
1265MODULE_ALIAS_LDISC(N_R3964);
1266