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
  20/* check if byte must be stuffed/escaped
  21 * I'm not sure which data should be encoded.
  22 * Therefore I will go the hard way and decode every value
  23 * less than 0x20, the flag sequence and the control escape char.
  24 */
  25static inline int muststuff(unsigned char c)
  26{
  27        if (c < PPP_TRANS) return 1;
  28        if (c == PPP_FLAG) return 1;
  29        if (c == PPP_ESCAPE) return 1;
  30        /* other possible candidates: */
  31        /* 0x91: XON with parity set */
  32        /* 0x93: XOFF with parity set */
  33        return 0;
  34}
  35
  36/* == data input =========================================================== */
  37
  38/* process a block of received bytes in command mode (modem response)
  39 * Return value:
  40 *      number of processed bytes
  41 */
  42static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes,
  43                           struct inbuf_t *inbuf)
  44{
  45        struct cardstate *cs = inbuf->cs;
  46        unsigned cbytes      = cs->cbytes;
  47        int inputstate = inbuf->inputstate;
  48        int startbytes = numbytes;
  49
  50        for (;;) {
  51                cs->respdata[cbytes] = c;
  52                if (c == 10 || c == 13) {
  53                        gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
  54                                __func__, cbytes);
  55                        cs->cbytes = cbytes;
  56                        gigaset_handle_modem_response(cs); /* can change
  57                                                              cs->dle */
  58                        cbytes = 0;
  59
  60                        if (cs->dle &&
  61                            !(inputstate & INS_DLE_command)) {
  62                                inputstate &= ~INS_command;
  63                                break;
  64                        }
  65                } else {
  66                        /* advance in line buffer, checking for overflow */
  67                        if (cbytes < MAX_RESP_SIZE - 1)
  68                                cbytes++;
  69                        else
  70                                dev_warn(cs->dev, "response too large\n");
  71                }
  72
  73                if (!numbytes)
  74                        break;
  75                c = *src++;
  76                --numbytes;
  77                if (c == DLE_FLAG &&
  78                    (cs->dle || inputstate & INS_DLE_command)) {
  79                        inputstate |= INS_DLE_char;
  80                        break;
  81                }
  82        }
  83
  84        cs->cbytes = cbytes;
  85        inbuf->inputstate = inputstate;
  86
  87        return startbytes - numbytes;
  88}
  89
  90/* process a block of received bytes in lock mode (tty i/f)
  91 * Return value:
  92 *      number of processed bytes
  93 */
  94static inline int lock_loop(unsigned char *src, int numbytes,
  95                            struct inbuf_t *inbuf)
  96{
  97        struct cardstate *cs = inbuf->cs;
  98
  99        gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
 100                           numbytes, src);
 101        gigaset_if_receive(cs, src, numbytes);
 102
 103        return numbytes;
 104}
 105
 106/* process a block of received bytes in HDLC data mode
 107 * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes.
 108 * When a frame is complete, check the FCS and pass valid frames to the LL.
 109 * If DLE is encountered, return immediately to let the caller handle it.
 110 * Return value:
 111 *      number of processed bytes
 112 *      numbytes (all bytes processed) on error --FIXME
 113 */
 114static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes,
 115                            struct inbuf_t *inbuf)
 116{
 117        struct cardstate *cs = inbuf->cs;
 118        struct bc_state *bcs = inbuf->bcs;
 119        int inputstate = bcs->inputstate;
 120        __u16 fcs = bcs->fcs;
 121        struct sk_buff *skb = bcs->skb;
 122        unsigned char error;
 123        struct sk_buff *compskb;
 124        int startbytes = numbytes;
 125        int l;
 126
 127        if (unlikely(inputstate & INS_byte_stuff)) {
 128                inputstate &= ~INS_byte_stuff;
 129                goto byte_stuff;
 130        }
 131        for (;;) {
 132                if (unlikely(c == PPP_ESCAPE)) {
 133                        if (unlikely(!numbytes)) {
 134                                inputstate |= INS_byte_stuff;
 135                                break;
 136                        }
 137                        c = *src++;
 138                        --numbytes;
 139                        if (unlikely(c == DLE_FLAG &&
 140                                     (cs->dle ||
 141                                      inbuf->inputstate & INS_DLE_command))) {
 142                                inbuf->inputstate |= INS_DLE_char;
 143                                inputstate |= INS_byte_stuff;
 144                                break;
 145                        }
 146byte_stuff:
 147                        c ^= PPP_TRANS;
 148                        if (unlikely(!muststuff(c)))
 149                                gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c);
 150                } else if (unlikely(c == PPP_FLAG)) {
 151                        if (unlikely(inputstate & INS_skip_frame)) {
 152#ifdef CONFIG_GIGASET_DEBUG
 153                                if (!(inputstate & INS_have_data)) { /* 7E 7E */
 154                                        ++bcs->emptycount;
 155                                } else
 156                                        gig_dbg(DEBUG_HDLC,
 157                                            "7e----------------------------");
 158#endif
 159
 160                                /* end of frame */
 161                                error = 1;
 162                                gigaset_rcv_error(NULL, cs, bcs);
 163                        } else if (!(inputstate & INS_have_data)) { /* 7E 7E */
 164#ifdef CONFIG_GIGASET_DEBUG
 165                                ++bcs->emptycount;
 166#endif
 167                                break;
 168                        } else {
 169                                gig_dbg(DEBUG_HDLC,
 170                                        "7e----------------------------");
 171
 172                                /* end of frame */
 173                                error = 0;
 174
 175                                if (unlikely(fcs != PPP_GOODFCS)) {
 176                                        dev_err(cs->dev,
 177                                "Checksum failed, %u bytes corrupted!\n",
 178                                                skb->len);
 179                                        compskb = NULL;
 180                                        gigaset_rcv_error(compskb, cs, bcs);
 181                                        error = 1;
 182                                } else {
 183                                        if (likely((l = skb->len) > 2)) {
 184                                                skb->tail -= 2;
 185                                                skb->len -= 2;
 186                                        } else {
 187                                                dev_kfree_skb(skb);
 188                                                skb = NULL;
 189                                                inputstate |= INS_skip_frame;
 190                                                if (l == 1) {
 191                                                        dev_err(cs->dev,
 192                                                  "invalid packet size (1)!\n");
 193                                                        error = 1;
 194                                                        gigaset_rcv_error(NULL,
 195                                                                cs, bcs);
 196                                                }
 197                                        }
 198                                        if (likely(!(error ||
 199                                                     (inputstate &
 200                                                      INS_skip_frame)))) {
 201                                                gigaset_rcv_skb(skb, cs, bcs);
 202                                        }
 203                                }
 204                        }
 205
 206                        if (unlikely(error))
 207                                if (skb)
 208                                        dev_kfree_skb(skb);
 209
 210                        fcs = PPP_INITFCS;
 211                        inputstate &= ~(INS_have_data | INS_skip_frame);
 212                        if (unlikely(bcs->ignore)) {
 213                                inputstate |= INS_skip_frame;
 214                                skb = NULL;
 215                        } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) {
 216                                skb_reserve(skb, HW_HDR_LEN);
 217                        } else {
 218                                dev_warn(cs->dev,
 219                                         "could not allocate new skb\n");
 220                                inputstate |= INS_skip_frame;
 221                        }
 222
 223                        break;
 224                } else if (unlikely(muststuff(c))) {
 225                        /* Should not happen. Possible after ZDLE=1<CR><LF>. */
 226                        gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
 227                }
 228
 229                /* add character */
 230
 231#ifdef CONFIG_GIGASET_DEBUG
 232                if (unlikely(!(inputstate & INS_have_data))) {
 233                        gig_dbg(DEBUG_HDLC, "7e (%d x) ================",
 234                                bcs->emptycount);
 235                        bcs->emptycount = 0;
 236                }
 237#endif
 238
 239                inputstate |= INS_have_data;
 240
 241                if (likely(!(inputstate & INS_skip_frame))) {
 242                        if (unlikely(skb->len == SBUFSIZE)) {
 243                                dev_warn(cs->dev, "received packet too long\n");
 244                                dev_kfree_skb_any(skb);
 245                                skb = NULL;
 246                                inputstate |= INS_skip_frame;
 247                                break;
 248                        }
 249                        *__skb_put(skb, 1) = c;
 250                        fcs = crc_ccitt_byte(fcs, c);
 251                }
 252
 253                if (unlikely(!numbytes))
 254                        break;
 255                c = *src++;
 256                --numbytes;
 257                if (unlikely(c == DLE_FLAG &&
 258                             (cs->dle ||
 259                              inbuf->inputstate & INS_DLE_command))) {
 260                        inbuf->inputstate |= INS_DLE_char;
 261                        break;
 262                }
 263        }
 264        bcs->inputstate = inputstate;
 265        bcs->fcs = fcs;
 266        bcs->skb = skb;
 267        return startbytes - numbytes;
 268}
 269
 270/* process a block of received bytes in transparent data mode
 271 * Invert bytes, undoing byte stuffing and watching for DLE escapes.
 272 * If DLE is encountered, return immediately to let the caller handle it.
 273 * Return value:
 274 *      number of processed bytes
 275 *      numbytes (all bytes processed) on error --FIXME
 276 */
 277static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
 278                            struct inbuf_t *inbuf)
 279{
 280        struct cardstate *cs = inbuf->cs;
 281        struct bc_state *bcs = inbuf->bcs;
 282        int inputstate = bcs->inputstate;
 283        struct sk_buff *skb = bcs->skb;
 284        int startbytes = numbytes;
 285
 286        for (;;) {
 287                /* add character */
 288                inputstate |= INS_have_data;
 289
 290                if (likely(!(inputstate & INS_skip_frame))) {
 291                        if (unlikely(skb->len == SBUFSIZE)) {
 292                                //FIXME just pass skb up and allocate a new one
 293                                dev_warn(cs->dev, "received packet too long\n");
 294                                dev_kfree_skb_any(skb);
 295                                skb = NULL;
 296                                inputstate |= INS_skip_frame;
 297                                break;
 298                        }
 299                        *__skb_put(skb, 1) = bitrev8(c);
 300                }
 301
 302                if (unlikely(!numbytes))
 303                        break;
 304                c = *src++;
 305                --numbytes;
 306                if (unlikely(c == DLE_FLAG &&
 307                             (cs->dle ||
 308                              inbuf->inputstate & INS_DLE_command))) {
 309                        inbuf->inputstate |= INS_DLE_char;
 310                        break;
 311                }
 312        }
 313
 314        /* pass data up */
 315        if (likely(inputstate & INS_have_data)) {
 316                if (likely(!(inputstate & INS_skip_frame))) {
 317                        gigaset_rcv_skb(skb, cs, bcs);
 318                }
 319                inputstate &= ~(INS_have_data | INS_skip_frame);
 320                if (unlikely(bcs->ignore)) {
 321                        inputstate |= INS_skip_frame;
 322                        skb = NULL;
 323                } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN))
 324                                  != NULL)) {
 325                        skb_reserve(skb, HW_HDR_LEN);
 326                } else {
 327                        dev_warn(cs->dev, "could not allocate new skb\n");
 328                        inputstate |= INS_skip_frame;
 329                }
 330        }
 331
 332        bcs->inputstate = inputstate;
 333        bcs->skb = skb;
 334        return startbytes - numbytes;
 335}
 336
 337/**
 338 * gigaset_m10x_input() - process a block of data received from the device
 339 * @inbuf:      received data and device descriptor structure.
 340 *
 341 * Called by hardware module {ser,usb}_gigaset with a block of received
 342 * bytes. Separates the bytes received over the serial data channel into
 343 * user data and command replies (locked/unlocked) according to the
 344 * current state of the interface.
 345 */
 346void gigaset_m10x_input(struct inbuf_t *inbuf)
 347{
 348        struct cardstate *cs;
 349        unsigned tail, head, numbytes;
 350        unsigned char *src, c;
 351        int procbytes;
 352
 353        head = inbuf->head;
 354        tail = inbuf->tail;
 355        gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
 356
 357        if (head != tail) {
 358                cs = inbuf->cs;
 359                src = inbuf->data + head;
 360                numbytes = (head > tail ? RBUFSIZE : tail) - head;
 361                gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
 362
 363                while (numbytes) {
 364                        if (cs->mstate == MS_LOCKED) {
 365                                procbytes = lock_loop(src, numbytes, inbuf);
 366                                src += procbytes;
 367                                numbytes -= procbytes;
 368                        } else {
 369                                c = *src++;
 370                                --numbytes;
 371                                if (c == DLE_FLAG && (cs->dle ||
 372                                    inbuf->inputstate & INS_DLE_command)) {
 373                                        if (!(inbuf->inputstate & INS_DLE_char)) {
 374                                                inbuf->inputstate |= INS_DLE_char;
 375                                                goto nextbyte;
 376                                        }
 377                                        /* <DLE> <DLE> => <DLE> in data stream */
 378                                        inbuf->inputstate &= ~INS_DLE_char;
 379                                }
 380
 381                                if (!(inbuf->inputstate & INS_DLE_char)) {
 382
 383                                        /* FIXME use function pointers?  */
 384                                        if (inbuf->inputstate & INS_command)
 385                                                procbytes = cmd_loop(c, src, numbytes, inbuf);
 386                                        else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC)
 387                                                procbytes = hdlc_loop(c, src, numbytes, inbuf);
 388                                        else
 389                                                procbytes = iraw_loop(c, src, numbytes, inbuf);
 390
 391                                        src += procbytes;
 392                                        numbytes -= procbytes;
 393                                } else {  /* DLE char */
 394                                        inbuf->inputstate &= ~INS_DLE_char;
 395                                        switch (c) {
 396                                        case 'X': /*begin of command*/
 397                                                if (inbuf->inputstate & INS_command)
 398                                                        dev_warn(cs->dev,
 399                                        "received <DLE> 'X' in command mode\n");
 400                                                inbuf->inputstate |=
 401                                                        INS_command | INS_DLE_command;
 402                                                break;
 403                                        case '.': /*end of command*/
 404                                                if (!(inbuf->inputstate & INS_command))
 405                                                        dev_warn(cs->dev,
 406                                        "received <DLE> '.' in hdlc mode\n");
 407                                                inbuf->inputstate &= cs->dle ?
 408                                                        ~(INS_DLE_command|INS_command)
 409                                                        : ~INS_DLE_command;
 410                                                break;
 411                                        //case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */
 412                                        default:
 413                                                dev_err(cs->dev,
 414                                                      "received 0x10 0x%02x!\n",
 415                                                        (int) c);
 416                                                /* FIXME: reset driver?? */
 417                                        }
 418                                }
 419                        }
 420nextbyte:
 421                        if (!numbytes) {
 422                                /* end of buffer, check for wrap */
 423                                if (head > tail) {
 424                                        head = 0;
 425                                        src = inbuf->data;
 426                                        numbytes = tail;
 427                                } else {
 428                                        head = tail;
 429                                        break;
 430                                }
 431                        }
 432                }
 433
 434                gig_dbg(DEBUG_INTR, "setting head to %u", head);
 435                inbuf->head = head;
 436        }
 437}
 438EXPORT_SYMBOL_GPL(gigaset_m10x_input);
 439
 440
 441/* == data output ========================================================== */
 442
 443/* Encoding of a PPP packet into an octet stuffed HDLC frame
 444 * with FCS, opening and closing flags.
 445 * parameters:
 446 *      skb     skb containing original packet (freed upon return)
 447 *      head    number of headroom bytes to allocate in result skb
 448 *      tail    number of tailroom bytes to allocate in result skb
 449 * Return value:
 450 *      pointer to newly allocated skb containing the result frame
 451 */
 452static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
 453{
 454        struct sk_buff *hdlc_skb;
 455        __u16 fcs;
 456        unsigned char c;
 457        unsigned char *cp;
 458        int len;
 459        unsigned int stuf_cnt;
 460
 461        stuf_cnt = 0;
 462        fcs = PPP_INITFCS;
 463        cp = skb->data;
 464        len = skb->len;
 465        while (len--) {
 466                if (muststuff(*cp))
 467                        stuf_cnt++;
 468                fcs = crc_ccitt_byte(fcs, *cp++);
 469        }
 470        fcs ^= 0xffff;                  /* complement */
 471
 472        /* size of new buffer: original size + number of stuffing bytes
 473         * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
 474         */
 475        hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head);
 476        if (!hdlc_skb) {
 477                dev_kfree_skb(skb);
 478                return NULL;
 479        }
 480        skb_reserve(hdlc_skb, head);
 481
 482        /* Copy acknowledge request into new skb */
 483        memcpy(hdlc_skb->head, skb->head, 2);
 484
 485        /* Add flag sequence in front of everything.. */
 486        *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
 487
 488        /* Perform byte stuffing while copying data. */
 489        while (skb->len--) {
 490                if (muststuff(*skb->data)) {
 491                        *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
 492                        *(skb_put(hdlc_skb, 1)) = (*skb->data++) ^ PPP_TRANS;
 493                } else
 494                        *(skb_put(hdlc_skb, 1)) = *skb->data++;
 495        }
 496
 497        /* Finally add FCS (byte stuffed) and flag sequence */
 498        c = (fcs & 0x00ff);     /* least significant byte first */
 499        if (muststuff(c)) {
 500                *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
 501                c ^= PPP_TRANS;
 502        }
 503        *(skb_put(hdlc_skb, 1)) = c;
 504
 505        c = ((fcs >> 8) & 0x00ff);
 506        if (muststuff(c)) {
 507                *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
 508                c ^= PPP_TRANS;
 509        }
 510        *(skb_put(hdlc_skb, 1)) = c;
 511
 512        *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
 513
 514        dev_kfree_skb(skb);
 515        return hdlc_skb;
 516}
 517
 518/* Encoding of a raw packet into an octet stuffed bit inverted frame
 519 * parameters:
 520 *      skb     skb containing original packet (freed upon return)
 521 *      head    number of headroom bytes to allocate in result skb
 522 *      tail    number of tailroom bytes to allocate in result skb
 523 * Return value:
 524 *      pointer to newly allocated skb containing the result frame
 525 */
 526static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
 527{
 528        struct sk_buff *iraw_skb;
 529        unsigned char c;
 530        unsigned char *cp;
 531        int len;
 532
 533        /* worst case: every byte must be stuffed */
 534        iraw_skb = dev_alloc_skb(2*skb->len + tail + head);
 535        if (!iraw_skb) {
 536                dev_kfree_skb(skb);
 537                return NULL;
 538        }
 539        skb_reserve(iraw_skb, head);
 540
 541        cp = skb->data;
 542        len = skb->len;
 543        while (len--) {
 544                c = bitrev8(*cp++);
 545                if (c == DLE_FLAG)
 546                        *(skb_put(iraw_skb, 1)) = c;
 547                *(skb_put(iraw_skb, 1)) = c;
 548        }
 549        dev_kfree_skb(skb);
 550        return iraw_skb;
 551}
 552
 553/**
 554 * gigaset_m10x_send_skb() - queue an skb for sending
 555 * @bcs:        B channel descriptor structure.
 556 * @skb:        data to send.
 557 *
 558 * Called by i4l.c to encode and queue an skb for sending, and start
 559 * transmission if necessary.
 560 *
 561 * Return value:
 562 *      number of bytes accepted for sending (skb->len) if ok,
 563 *      error code < 0 (eg. -ENOMEM) on error
 564 */
 565int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
 566{
 567        unsigned len = skb->len;
 568        unsigned long flags;
 569
 570        if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
 571                skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
 572        else
 573                skb = iraw_encode(skb, HW_HDR_LEN, 0);
 574        if (!skb) {
 575                dev_err(bcs->cs->dev,
 576                        "unable to allocate memory for encoding!\n");
 577                return -ENOMEM;
 578        }
 579
 580        skb_queue_tail(&bcs->squeue, skb);
 581        spin_lock_irqsave(&bcs->cs->lock, flags);
 582        if (bcs->cs->connected)
 583                tasklet_schedule(&bcs->cs->write_tasklet);
 584        spin_unlock_irqrestore(&bcs->cs->lock, flags);
 585
 586        return len;     /* ok so far */
 587}
 588EXPORT_SYMBOL_GPL(gigaset_m10x_send_skb);
 589