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