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 30 u16 31 qcafrm_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 } 51 EXPORT_SYMBOL_GPL(qcafrm_create_header); 52 53 u16 54 qcafrm_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 } 63 EXPORT_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 76 s32 77 qcafrm_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 } 161 EXPORT_SYMBOL_GPL(qcafrm_fsm_decode); 162 163 MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 common"); 164 MODULE_AUTHOR("Qualcomm Atheros Communications"); 165 MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>"); 166 MODULE_LICENSE("Dual BSD/GPL"); 167