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