linux/drivers/net/ethernet/qualcomm/qca_7k_common.c
<<
>>
Prefs
   1/*
   2 *   Copyright (c) 2011, 2012, Atheros Communications Inc.
   3 *   Copyright (c) 2014, I2SE GmbH
   4 *
   5 *   Permission to use, copy, modify, and/or distribute this software
   6 *   for any purpose with or without fee is hereby granted, provided
   7 *   that the above copyright notice and this permission notice appear
   8 *   in all copies.
   9 *
  10 *   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  11 *   WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  12 *   WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  13 *   THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
  14 *   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  15 *   LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  16 *   NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  17 *   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18 */
  19
  20/*   Atheros ethernet framing. Every Ethernet frame is surrounded
  21 *   by an atheros frame while transmitted over a serial channel;
  22 */
  23
  24#include <linux/init.h>
  25#include <linux/kernel.h>
  26#include <linux/module.h>
  27
  28#include "qca_7k_common.h"
  29
  30u16
  31qcafrm_create_header(u8 *buf, u16 length)
  32{
  33        __le16 len;
  34
  35        if (!buf)
  36                return 0;
  37
  38        len = cpu_to_le16(length);
  39
  40        buf[0] = 0xAA;
  41        buf[1] = 0xAA;
  42        buf[2] = 0xAA;
  43        buf[3] = 0xAA;
  44        buf[4] = len & 0xff;
  45        buf[5] = (len >> 8) & 0xff;
  46        buf[6] = 0;
  47        buf[7] = 0;
  48
  49        return QCAFRM_HEADER_LEN;
  50}
  51EXPORT_SYMBOL_GPL(qcafrm_create_header);
  52
  53u16
  54qcafrm_create_footer(u8 *buf)
  55{
  56        if (!buf)
  57                return 0;
  58
  59        buf[0] = 0x55;
  60        buf[1] = 0x55;
  61        return QCAFRM_FOOTER_LEN;
  62}
  63EXPORT_SYMBOL_GPL(qcafrm_create_footer);
  64
  65/*   Gather received bytes and try to extract a full ethernet frame by
  66 *   following a simple state machine.
  67 *
  68 * Return:   QCAFRM_GATHER       No ethernet frame fully received yet.
  69 *           QCAFRM_NOHEAD       Header expected but not found.
  70 *           QCAFRM_INVLEN       Atheros frame length is invalid
  71 *           QCAFRM_NOTAIL       Footer expected but not found.
  72 *           > 0                 Number of byte in the fully received
  73 *                               Ethernet frame
  74 */
  75
  76s32
  77qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_byte)
  78{
  79        s32 ret = QCAFRM_GATHER;
  80        u16 len;
  81
  82        switch (handle->state) {
  83        case QCAFRM_HW_LEN0:
  84        case QCAFRM_HW_LEN1:
  85                /* by default, just go to next state */
  86                handle->state--;
  87
  88                if (recv_byte != 0x00) {
  89                        /* first two bytes of length must be 0 */
  90                        handle->state = handle->init;
  91                }
  92                break;
  93        case QCAFRM_HW_LEN2:
  94        case QCAFRM_HW_LEN3:
  95                handle->state--;
  96                break;
  97        /* 4 bytes header pattern */
  98        case QCAFRM_WAIT_AA1:
  99        case QCAFRM_WAIT_AA2:
 100        case QCAFRM_WAIT_AA3:
 101        case QCAFRM_WAIT_AA4:
 102                if (recv_byte != 0xAA) {
 103                        ret = QCAFRM_NOHEAD;
 104                        handle->state = handle->init;
 105                } else {
 106                        handle->state--;
 107                }
 108                break;
 109                /* 2 bytes length. */
 110                /* Borrow offset field to hold length for now. */
 111        case QCAFRM_WAIT_LEN_BYTE0:
 112                handle->offset = recv_byte;
 113                handle->state = QCAFRM_WAIT_LEN_BYTE1;
 114                break;
 115        case QCAFRM_WAIT_LEN_BYTE1:
 116                handle->offset = handle->offset | (recv_byte << 8);
 117                handle->state = QCAFRM_WAIT_RSVD_BYTE1;
 118                break;
 119        case QCAFRM_WAIT_RSVD_BYTE1:
 120                handle->state = QCAFRM_WAIT_RSVD_BYTE2;
 121                break;
 122        case QCAFRM_WAIT_RSVD_BYTE2:
 123                len = handle->offset;
 124                if (len > buf_len || len < QCAFRM_MIN_LEN) {
 125                        ret = QCAFRM_INVLEN;
 126                        handle->state = handle->init;
 127                } else {
 128                        handle->state = (enum qcafrm_state)(len + 1);
 129                        /* Remaining number of bytes. */
 130                        handle->offset = 0;
 131                }
 132                break;
 133        default:
 134                /* Receiving Ethernet frame itself. */
 135                buf[handle->offset] = recv_byte;
 136                handle->offset++;
 137                handle->state--;
 138                break;
 139        case QCAFRM_WAIT_551:
 140                if (recv_byte != 0x55) {
 141                        ret = QCAFRM_NOTAIL;
 142                        handle->state = handle->init;
 143                } else {
 144                        handle->state = QCAFRM_WAIT_552;
 145                }
 146                break;
 147        case QCAFRM_WAIT_552:
 148                if (recv_byte != 0x55) {
 149                        ret = QCAFRM_NOTAIL;
 150                        handle->state = handle->init;
 151                } else {
 152                        ret = handle->offset;
 153                        /* Frame is fully received. */
 154                        handle->state = handle->init;
 155                }
 156                break;
 157        }
 158
 159        return ret;
 160}
 161EXPORT_SYMBOL_GPL(qcafrm_fsm_decode);
 162
 163MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 common");
 164MODULE_AUTHOR("Qualcomm Atheros Communications");
 165MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
 166MODULE_LICENSE("Dual BSD/GPL");
 167