linux/drivers/isdn/gigaset/asyncdata.c
<<
>>
Prefs
   1/*
   2 * Common data handling layer for ser_gigaset and usb_gigaset
   3 *
   4 * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>,
   5 *                       Hansjoerg Lipp <hjlipp@web.de>,
   6 *                       Stefan Eilers.
   7 *
   8 * =====================================================================
   9 *      This program is free software; you can redistribute it and/or
  10 *      modify it under the terms of the GNU General Public License as
  11 *      published by the Free Software Foundation; either version 2 of
  12 *      the License, or (at your option) any later version.
  13 * =====================================================================
  14 */
  15
  16#include "gigaset.h"
  17#include <linux/crc-ccitt.h>
  18#include <linux/bitrev.h>
  19#include <linux/export.h>
  20
  21/* check if byte must be stuffed/escaped
  22 * I'm not sure which data should be encoded.
  23 * Therefore I will go the hard way and encode every value
  24 * less than 0x20, the flag sequence and the control escape char.
  25 */
  26static inline int muststuff(unsigned char c)
  27{
  28        if (c < PPP_TRANS) return 1;
  29        if (c == PPP_FLAG) return 1;
  30        if (c == PPP_ESCAPE) return 1;
  31        /* other possible candidates: */
  32        /* 0x91: XON with parity set */
  33        /* 0x93: XOFF with parity set */
  34        return 0;
  35}
  36
  37/* == data input =========================================================== */
  38
  39/* process a block of received bytes in command mode
  40 * (mstate != MS_LOCKED && (inputstate & INS_command))
  41 * Append received bytes to the command response buffer and forward them
  42 * line by line to the response handler. Exit whenever a mode/state change
  43 * might have occurred.
  44 * Note: Received lines may be terminated by CR, LF, or CR LF, which will be
  45 * removed before passing the line to the response handler.
  46 * Return value:
  47 *      number of processed bytes
  48 */
  49static unsigned cmd_loop(unsigned numbytes, struct inbuf_t *inbuf)
  50{
  51        unsigned char *src = inbuf->data + inbuf->head;
  52        struct cardstate *cs = inbuf->cs;
  53        unsigned cbytes = cs->cbytes;
  54        unsigned procbytes = 0;
  55        unsigned char c;
  56
  57        while (procbytes < numbytes) {
  58                c = *src++;
  59                procbytes++;
  60
  61                switch (c) {
  62                case '\n':
  63                        if (cbytes == 0 && cs->respdata[0] == '\r') {
  64                                /* collapse LF with preceding CR */
  65                                cs->respdata[0] = 0;
  66                                break;
  67                        }
  68                        /* --v-- fall through --v-- */
  69                case '\r':
  70                        /* end of message line, pass to response handler */
  71                        if (cbytes >= MAX_RESP_SIZE) {
  72                                dev_warn(cs->dev, "response too large (%d)\n",
  73                                         cbytes);
  74                                cbytes = MAX_RESP_SIZE;
  75                        }
  76                        cs->cbytes = cbytes;
  77                        gigaset_dbg_buffer(DEBUG_TRANSCMD, "received response",
  78                                           cbytes, cs->respdata);
  79                        gigaset_handle_modem_response(cs);
  80                        cbytes = 0;
  81
  82                        /* store EOL byte for CRLF collapsing */
  83                        cs->respdata[0] = c;
  84
  85                        /* cs->dle may have changed */
  86                        if (cs->dle && !(inbuf->inputstate & INS_DLE_command))
  87                                inbuf->inputstate &= ~INS_command;
  88
  89                        /* return for reevaluating state */
  90                        goto exit;
  91
  92                case DLE_FLAG:
  93                        if (inbuf->inputstate & INS_DLE_char) {
  94                                /* quoted DLE: clear quote flag */
  95                                inbuf->inputstate &= ~INS_DLE_char;
  96                        } else if (cs->dle ||
  97                                   (inbuf->inputstate & INS_DLE_command)) {
  98                                /* DLE escape, pass up for handling */
  99                                inbuf->inputstate |= INS_DLE_char;
 100                                goto exit;
 101                        }
 102                        /* quoted or not in DLE mode: treat as regular data */
 103                        /* --v-- fall through --v-- */
 104                default:
 105                        /* append to line buffer if possible */
 106                        if (cbytes < MAX_RESP_SIZE)
 107                                cs->respdata[cbytes] = c;
 108                        cbytes++;
 109                }
 110        }
 111exit:
 112        cs->cbytes = cbytes;
 113        return procbytes;
 114}
 115
 116/* process a block of received bytes in lock mode
 117 * All received bytes are passed unmodified to the tty i/f.
 118 * Return value:
 119 *      number of processed bytes
 120 */
 121static unsigned lock_loop(unsigned numbytes, struct inbuf_t *inbuf)
 122{
 123        unsigned char *src = inbuf->data + inbuf->head;
 124
 125        gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", numbytes, src);
 126        gigaset_if_receive(inbuf->cs, src, numbytes);
 127        return numbytes;
 128}
 129
 130/* process a block of received bytes in HDLC data mode
 131 * (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 == L2_HDLC)
 132 * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes.
 133 * When a frame is complete, check the FCS and pass valid frames to the LL.
 134 * If DLE is encountered, return immediately to let the caller handle it.
 135 * Return value:
 136 *      number of processed bytes
 137 */
 138static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf)
 139{
 140        struct cardstate *cs = inbuf->cs;
 141        struct bc_state *bcs = cs->bcs;
 142        int inputstate = bcs->inputstate;
 143        __u16 fcs = bcs->rx_fcs;
 144        struct sk_buff *skb = bcs->rx_skb;
 145        unsigned char *src = inbuf->data + inbuf->head;
 146        unsigned procbytes = 0;
 147        unsigned char c;
 148
 149        if (inputstate & INS_byte_stuff) {
 150                if (!numbytes)
 151                        return 0;
 152                inputstate &= ~INS_byte_stuff;
 153                goto byte_stuff;
 154        }
 155
 156        while (procbytes < numbytes) {
 157                c = *src++;
 158                procbytes++;
 159                if (c == DLE_FLAG) {
 160                        if (inputstate & INS_DLE_char) {
 161                                /* quoted DLE: clear quote flag */
 162                                inputstate &= ~INS_DLE_char;
 163                        } else if (cs->dle || (inputstate & INS_DLE_command)) {
 164                                /* DLE escape, pass up for handling */
 165                                inputstate |= INS_DLE_char;
 166                                break;
 167                        }
 168                }
 169
 170                if (c == PPP_ESCAPE) {
 171                        /* byte stuffing indicator: pull in next byte */
 172                        if (procbytes >= numbytes) {
 173                                /* end of buffer, save for later processing */
 174                                inputstate |= INS_byte_stuff;
 175                                break;
 176                        }
 177byte_stuff:
 178                        c = *src++;
 179                        procbytes++;
 180                        if (c == DLE_FLAG) {
 181                                if (inputstate & INS_DLE_char) {
 182                                        /* quoted DLE: clear quote flag */
 183                                        inputstate &= ~INS_DLE_char;
 184                                } else if (cs->dle ||
 185                                           (inputstate & INS_DLE_command)) {
 186                                        /* DLE escape, pass up for handling */
 187                                        inputstate |=
 188                                                INS_DLE_char | INS_byte_stuff;
 189                                        break;
 190                                }
 191                        }
 192                        c ^= PPP_TRANS;
 193#ifdef CONFIG_GIGASET_DEBUG
 194                        if (!muststuff(c))
 195                                gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c);
 196#endif
 197                } else if (c == PPP_FLAG) {
 198                        /* end of frame: process content if any */
 199                        if (inputstate & INS_have_data) {
 200                                gig_dbg(DEBUG_HDLC,
 201                                        "7e----------------------------");
 202
 203                                /* check and pass received frame */
 204                                if (!skb) {
 205                                        /* skipped frame */
 206                                        gigaset_isdn_rcv_err(bcs);
 207                                } else if (skb->len < 2) {
 208                                        /* frame too short for FCS */
 209                                        dev_warn(cs->dev,
 210                                                 "short frame (%d)\n",
 211                                                 skb->len);
 212                                        gigaset_isdn_rcv_err(bcs);
 213                                        dev_kfree_skb_any(skb);
 214                                } else if (fcs != PPP_GOODFCS) {
 215                                        /* frame check error */
 216                                        dev_err(cs->dev,
 217                                "Checksum failed, %u bytes corrupted!\n",
 218                                                skb->len);
 219                                        gigaset_isdn_rcv_err(bcs);
 220                                        dev_kfree_skb_any(skb);
 221                                } else {
 222                                        /* good frame */
 223                                        __skb_trim(skb, skb->len - 2);
 224                                        gigaset_skb_rcvd(bcs, skb);
 225                                }
 226
 227                                /* prepare reception of next frame */
 228                                inputstate &= ~INS_have_data;
 229                                skb = gigaset_new_rx_skb(bcs);
 230                        } else {
 231                                /* empty frame (7E 7E) */
 232#ifdef CONFIG_GIGASET_DEBUG
 233                                ++bcs->emptycount;
 234#endif
 235                                if (!skb) {
 236                                        /* skipped (?) */
 237                                        gigaset_isdn_rcv_err(bcs);
 238                                        skb = gigaset_new_rx_skb(bcs);
 239                                }
 240                        }
 241
 242                        fcs = PPP_INITFCS;
 243                        continue;
 244#ifdef CONFIG_GIGASET_DEBUG
 245                } else if (muststuff(c)) {
 246                        /* Should not happen. Possible after ZDLE=1<CR><LF>. */
 247                        gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
 248#endif
 249                }
 250
 251                /* regular data byte, append to skb */
 252#ifdef CONFIG_GIGASET_DEBUG
 253                if (!(inputstate & INS_have_data)) {
 254                        gig_dbg(DEBUG_HDLC, "7e (%d x) ================",
 255                                bcs->emptycount);
 256                        bcs->emptycount = 0;
 257                }
 258#endif
 259                inputstate |= INS_have_data;
 260                if (skb) {
 261                        if (skb->len >= bcs->rx_bufsize) {
 262                                dev_warn(cs->dev, "received packet too long\n");
 263                                dev_kfree_skb_any(skb);
 264                                /* skip remainder of packet */
 265                                bcs->rx_skb = skb = NULL;
 266                        } else {
 267                                *__skb_put(skb, 1) = c;
 268                                fcs = crc_ccitt_byte(fcs, c);
 269                        }
 270                }
 271        }
 272
 273        bcs->inputstate = inputstate;
 274        bcs->rx_fcs = fcs;
 275        return procbytes;
 276}
 277
 278/* process a block of received bytes in transparent data mode
 279 * (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 != L2_HDLC)
 280 * Invert bytes, undoing byte stuffing and watching for DLE escapes.
 281 * If DLE is encountered, return immediately to let the caller handle it.
 282 * Return value:
 283 *      number of processed bytes
 284 */
 285static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf)
 286{
 287        struct cardstate *cs = inbuf->cs;
 288        struct bc_state *bcs = cs->bcs;
 289        int inputstate = bcs->inputstate;
 290        struct sk_buff *skb = bcs->rx_skb;
 291        unsigned char *src = inbuf->data + inbuf->head;
 292        unsigned procbytes = 0;
 293        unsigned char c;
 294
 295        if (!skb) {
 296                /* skip this block */
 297                gigaset_new_rx_skb(bcs);
 298                return numbytes;
 299        }
 300
 301        while (procbytes < numbytes && skb->len < bcs->rx_bufsize) {
 302                c = *src++;
 303                procbytes++;
 304
 305                if (c == DLE_FLAG) {
 306                        if (inputstate & INS_DLE_char) {
 307                                /* quoted DLE: clear quote flag */
 308                                inputstate &= ~INS_DLE_char;
 309                        } else if (cs->dle || (inputstate & INS_DLE_command)) {
 310                                /* DLE escape, pass up for handling */
 311                                inputstate |= INS_DLE_char;
 312                                break;
 313                        }
 314                }
 315
 316                /* regular data byte: append to current skb */
 317                inputstate |= INS_have_data;
 318                *__skb_put(skb, 1) = bitrev8(c);
 319        }
 320
 321        /* pass data up */
 322        if (inputstate & INS_have_data) {
 323                gigaset_skb_rcvd(bcs, skb);
 324                inputstate &= ~INS_have_data;
 325                gigaset_new_rx_skb(bcs);
 326        }
 327
 328        bcs->inputstate = inputstate;
 329        return procbytes;
 330}
 331
 332/* process DLE escapes
 333 * Called whenever a DLE sequence might be encountered in the input stream.
 334 * Either processes the entire DLE sequence or, if that isn't possible,
 335 * notes the fact that an initial DLE has been received in the INS_DLE_char
 336 * inputstate flag and resumes processing of the sequence on the next call.
 337 */
 338static void handle_dle(struct inbuf_t *inbuf)
 339{
 340        struct cardstate *cs = inbuf->cs;
 341
 342        if (cs->mstate == MS_LOCKED)
 343                return;         /* no DLE processing in lock mode */
 344
 345        if (!(inbuf->inputstate & INS_DLE_char)) {
 346                /* no DLE pending */
 347                if (inbuf->data[inbuf->head] == DLE_FLAG &&
 348                    (cs->dle || inbuf->inputstate & INS_DLE_command)) {
 349                        /* start of DLE sequence */
 350                        inbuf->head++;
 351                        if (inbuf->head == inbuf->tail ||
 352                            inbuf->head == RBUFSIZE) {
 353                                /* end of buffer, save for later processing */
 354                                inbuf->inputstate |= INS_DLE_char;
 355                                return;
 356                        }
 357                } else {
 358                        /* regular data byte */
 359                        return;
 360                }
 361        }
 362
 363        /* consume pending DLE */
 364        inbuf->inputstate &= ~INS_DLE_char;
 365
 366        switch (inbuf->data[inbuf->head]) {
 367        case 'X':       /* begin of event message */
 368                if (inbuf->inputstate & INS_command)
 369                        dev_notice(cs->dev,
 370                                   "received <DLE>X in command mode\n");
 371                inbuf->inputstate |= INS_command | INS_DLE_command;
 372                inbuf->head++;  /* byte consumed */
 373                break;
 374        case '.':       /* end of event message */
 375                if (!(inbuf->inputstate & INS_DLE_command))
 376                        dev_notice(cs->dev,
 377                                   "received <DLE>. without <DLE>X\n");
 378                inbuf->inputstate &= ~INS_DLE_command;
 379                /* return to data mode if in DLE mode */
 380                if (cs->dle)
 381                        inbuf->inputstate &= ~INS_command;
 382                inbuf->head++;  /* byte consumed */
 383                break;
 384        case DLE_FLAG:  /* DLE in data stream */
 385                /* mark as quoted */
 386                inbuf->inputstate |= INS_DLE_char;
 387                if (!(cs->dle || inbuf->inputstate & INS_DLE_command))
 388                        dev_notice(cs->dev,
 389                                   "received <DLE><DLE> not in DLE mode\n");
 390                break;  /* quoted byte left in buffer */
 391        default:
 392                dev_notice(cs->dev, "received <DLE><%02x>\n",
 393                           inbuf->data[inbuf->head]);
 394                /* quoted byte left in buffer */
 395        }
 396}
 397
 398/**
 399 * gigaset_m10x_input() - process a block of data received from the device
 400 * @inbuf:      received data and device descriptor structure.
 401 *
 402 * Called by hardware module {ser,usb}_gigaset with a block of received
 403 * bytes. Separates the bytes received over the serial data channel into
 404 * user data and command replies (locked/unlocked) according to the
 405 * current state of the interface.
 406 */
 407void gigaset_m10x_input(struct inbuf_t *inbuf)
 408{
 409        struct cardstate *cs = inbuf->cs;
 410        unsigned numbytes, procbytes;
 411
 412        gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", inbuf->head, inbuf->tail);
 413
 414        while (inbuf->head != inbuf->tail) {
 415                /* check for DLE escape */
 416                handle_dle(inbuf);
 417
 418                /* process a contiguous block of bytes */
 419                numbytes = (inbuf->head > inbuf->tail ?
 420                            RBUFSIZE : inbuf->tail) - inbuf->head;
 421                gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
 422                /*
 423                 * numbytes may be 0 if handle_dle() ate the last byte.
 424                 * This does no harm, *_loop() will just return 0 immediately.
 425                 */
 426
 427                if (cs->mstate == MS_LOCKED)
 428                        procbytes = lock_loop(numbytes, inbuf);
 429                else if (inbuf->inputstate & INS_command)
 430                        procbytes = cmd_loop(numbytes, inbuf);
 431                else if (cs->bcs->proto2 == L2_HDLC)
 432                        procbytes = hdlc_loop(numbytes, inbuf);
 433                else
 434                        procbytes = iraw_loop(numbytes, inbuf);
 435                inbuf->head += procbytes;
 436
 437                /* check for buffer wraparound */
 438                if (inbuf->head >= RBUFSIZE)
 439                        inbuf->head = 0;
 440
 441                gig_dbg(DEBUG_INTR, "head set to %u", inbuf->head);
 442        }
 443}
 444EXPORT_SYMBOL_GPL(gigaset_m10x_input);
 445
 446
 447/* == data output ========================================================== */
 448
 449/*
 450 * Encode a data packet into an octet stuffed HDLC frame with FCS,
 451 * opening and closing flags, preserving headroom data.
 452 * parameters:
 453 *      skb             skb containing original packet (freed upon return)
 454 * Return value:
 455 *      pointer to newly allocated skb containing the result frame
 456 *      and the original link layer header, NULL on error
 457 */
 458static struct sk_buff *HDLC_Encode(struct sk_buff *skb)
 459{
 460        struct sk_buff *hdlc_skb;
 461        __u16 fcs;
 462        unsigned char c;
 463        unsigned char *cp;
 464        int len;
 465        unsigned int stuf_cnt;
 466
 467        stuf_cnt = 0;
 468        fcs = PPP_INITFCS;
 469        cp = skb->data;
 470        len = skb->len;
 471        while (len--) {
 472                if (muststuff(*cp))
 473                        stuf_cnt++;
 474                fcs = crc_ccitt_byte(fcs, *cp++);
 475        }
 476        fcs ^= 0xffff;                  /* complement */
 477
 478        /* size of new buffer: original size + number of stuffing bytes
 479         * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
 480         * + room for link layer header
 481         */
 482        hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + skb->mac_len);
 483        if (!hdlc_skb) {
 484                dev_kfree_skb_any(skb);
 485                return NULL;
 486        }
 487
 488        /* Copy link layer header into new skb */
 489        skb_reset_mac_header(hdlc_skb);
 490        skb_reserve(hdlc_skb, skb->mac_len);
 491        memcpy(skb_mac_header(hdlc_skb), skb_mac_header(skb), skb->mac_len);
 492        hdlc_skb->mac_len = skb->mac_len;
 493
 494        /* Add flag sequence in front of everything.. */
 495        *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
 496
 497        /* Perform byte stuffing while copying data. */
 498        while (skb->len--) {
 499                if (muststuff(*skb->data)) {
 500                        *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
 501                        *(skb_put(hdlc_skb, 1)) = (*skb->data++) ^ PPP_TRANS;
 502                } else
 503                        *(skb_put(hdlc_skb, 1)) = *skb->data++;
 504        }
 505
 506        /* Finally add FCS (byte stuffed) and flag sequence */
 507        c = (fcs & 0x00ff);     /* least significant byte first */
 508        if (muststuff(c)) {
 509                *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
 510                c ^= PPP_TRANS;
 511        }
 512        *(skb_put(hdlc_skb, 1)) = c;
 513
 514        c = ((fcs >> 8) & 0x00ff);
 515        if (muststuff(c)) {
 516                *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
 517                c ^= PPP_TRANS;
 518        }
 519        *(skb_put(hdlc_skb, 1)) = c;
 520
 521        *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
 522
 523        dev_kfree_skb_any(skb);
 524        return hdlc_skb;
 525}
 526
 527/*
 528 * Encode a data packet into an octet stuffed raw bit inverted frame,
 529 * preserving headroom data.
 530 * parameters:
 531 *      skb             skb containing original packet (freed upon return)
 532 * Return value:
 533 *      pointer to newly allocated skb containing the result frame
 534 *      and the original link layer header, NULL on error
 535 */
 536static struct sk_buff *iraw_encode(struct sk_buff *skb)
 537{
 538        struct sk_buff *iraw_skb;
 539        unsigned char c;
 540        unsigned char *cp;
 541        int len;
 542
 543        /* size of new buffer (worst case = every byte must be stuffed):
 544         * 2 * original size + room for link layer header
 545         */
 546        iraw_skb = dev_alloc_skb(2*skb->len + skb->mac_len);
 547        if (!iraw_skb) {
 548                dev_kfree_skb_any(skb);
 549                return NULL;
 550        }
 551
 552        /* copy link layer header into new skb */
 553        skb_reset_mac_header(iraw_skb);
 554        skb_reserve(iraw_skb, skb->mac_len);
 555        memcpy(skb_mac_header(iraw_skb), skb_mac_header(skb), skb->mac_len);
 556        iraw_skb->mac_len = skb->mac_len;
 557
 558        /* copy and stuff data */
 559        cp = skb->data;
 560        len = skb->len;
 561        while (len--) {
 562                c = bitrev8(*cp++);
 563                if (c == DLE_FLAG)
 564                        *(skb_put(iraw_skb, 1)) = c;
 565                *(skb_put(iraw_skb, 1)) = c;
 566        }
 567        dev_kfree_skb_any(skb);
 568        return iraw_skb;
 569}
 570
 571/**
 572 * gigaset_m10x_send_skb() - queue an skb for sending
 573 * @bcs:        B channel descriptor structure.
 574 * @skb:        data to send.
 575 *
 576 * Called by LL to encode and queue an skb for sending, and start
 577 * transmission if necessary.
 578 * Once the payload data has been transmitted completely, gigaset_skb_sent()
 579 * will be called with the skb's link layer header preserved.
 580 *
 581 * Return value:
 582 *      number of bytes accepted for sending (skb->len) if ok,
 583 *      error code < 0 (eg. -ENOMEM) on error
 584 */
 585int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
 586{
 587        struct cardstate *cs = bcs->cs;
 588        unsigned len = skb->len;
 589        unsigned long flags;
 590
 591        if (bcs->proto2 == L2_HDLC)
 592                skb = HDLC_Encode(skb);
 593        else
 594                skb = iraw_encode(skb);
 595        if (!skb) {
 596                dev_err(cs->dev,
 597                        "unable to allocate memory for encoding!\n");
 598                return -ENOMEM;
 599        }
 600
 601        skb_queue_tail(&bcs->squeue, skb);
 602        spin_lock_irqsave(&cs->lock, flags);
 603        if (cs->connected)
 604                tasklet_schedule(&cs->write_tasklet);
 605        spin_unlock_irqrestore(&cs->lock, flags);
 606
 607        return len;     /* ok so far */
 608}
 609EXPORT_SYMBOL_GPL(gigaset_m10x_send_skb);
 610