blob: 74dcb6bd249d76087c0e7c4d7fab01b4b25d7758 [file] [log] [blame]
Shalabh Jain1c99e4c2012-03-26 18:47:59 -07001/* Copyright (c) 2008-2009, 2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/cdev.h>
17#include <linux/fs.h>
18#include <linux/device.h>
19#include <linux/uaccess.h>
20#include <linux/crc-ccitt.h>
21#include "diagchar_hdlc.h"
Shalabh Jain1c99e4c2012-03-26 18:47:59 -070022#include "diagchar.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023
24
25MODULE_LICENSE("GPL v2");
26
27#define CRC_16_L_SEED 0xFFFF
28
29#define CRC_16_L_STEP(xx_crc, xx_c) \
30 crc_ccitt_byte(xx_crc, xx_c)
31
32void diag_hdlc_encode(struct diag_send_desc_type *src_desc,
33 struct diag_hdlc_dest_type *enc)
34{
35 uint8_t *dest;
36 uint8_t *dest_last;
37 const uint8_t *src;
38 const uint8_t *src_last;
39 uint16_t crc;
40 unsigned char src_byte = 0;
41 enum diag_send_state_enum_type state;
42 unsigned int used = 0;
43
44 if (src_desc && enc) {
45
46 /* Copy parts to local variables. */
47 src = src_desc->pkt;
48 src_last = src_desc->last;
49 state = src_desc->state;
50 dest = enc->dest;
51 dest_last = enc->dest_last;
52
53 if (state == DIAG_STATE_START) {
54 crc = CRC_16_L_SEED;
55 state++;
56 } else {
57 /* Get a local copy of the CRC */
58 crc = enc->crc;
59 }
60
61 /* dest or dest_last may be NULL to trigger a
62 state transition only */
63 if (dest && dest_last) {
64 /* This condition needs to include the possibility
65 of 2 dest bytes for an escaped byte */
66 while (src <= src_last && dest <= dest_last) {
67
68 src_byte = *src++;
69
70 if ((src_byte == CONTROL_CHAR) ||
71 (src_byte == ESC_CHAR)) {
72
73 /* If the escape character is not the
74 last byte */
75 if (dest != dest_last) {
76 crc = CRC_16_L_STEP(crc,
77 src_byte);
78
79 *dest++ = ESC_CHAR;
80 used++;
81
82 *dest++ = src_byte
83 ^ ESC_MASK;
84 used++;
85 } else {
86
87 src--;
88 break;
89 }
90
91 } else {
92 crc = CRC_16_L_STEP(crc, src_byte);
93 *dest++ = src_byte;
94 used++;
95 }
96 }
97
98 if (src > src_last) {
99
100 if (state == DIAG_STATE_BUSY) {
101 if (src_desc->terminate) {
102 crc = ~crc;
103 state++;
104 } else {
105 /* Done with fragment */
106 state = DIAG_STATE_COMPLETE;
107 }
108 }
109
110 while (dest <= dest_last &&
111 state >= DIAG_STATE_CRC1 &&
112 state < DIAG_STATE_TERM) {
113 /* Encode a byte of the CRC next */
114 src_byte = crc & 0xFF;
115
116 if ((src_byte == CONTROL_CHAR)
117 || (src_byte == ESC_CHAR)) {
118
119 if (dest != dest_last) {
120
121 *dest++ = ESC_CHAR;
122 used++;
123 *dest++ = src_byte ^
124 ESC_MASK;
125 used++;
126
127 crc >>= 8;
128 } else {
129
130 break;
131 }
132 } else {
133
134 crc >>= 8;
135 *dest++ = src_byte;
136 used++;
137 }
138
139 state++;
140 }
141
142 if (state == DIAG_STATE_TERM) {
143 if (dest_last >= dest) {
144 *dest++ = CONTROL_CHAR;
145 used++;
146 state++; /* Complete */
147 }
148 }
149 }
150 }
151 /* Copy local variables back into the encode structure. */
152
153 enc->dest = dest;
154 enc->dest_last = dest_last;
155 enc->crc = crc;
156 src_desc->pkt = src;
157 src_desc->last = src_last;
158 src_desc->state = state;
159 }
160
161 return;
162}
163
164
165int diag_hdlc_decode(struct diag_hdlc_decode_type *hdlc)
166{
167 uint8_t *src_ptr = NULL, *dest_ptr = NULL;
168 unsigned int src_length = 0, dest_length = 0;
169
170 unsigned int len = 0;
171 unsigned int i;
172 uint8_t src_byte;
173
174 int pkt_bnd = 0;
175
176 if (hdlc && hdlc->src_ptr && hdlc->dest_ptr &&
177 (hdlc->src_size - hdlc->src_idx > 0) &&
178 (hdlc->dest_size - hdlc->dest_idx > 0)) {
179
180 src_ptr = hdlc->src_ptr;
181 src_ptr = &src_ptr[hdlc->src_idx];
182 src_length = hdlc->src_size - hdlc->src_idx;
183
184 dest_ptr = hdlc->dest_ptr;
185 dest_ptr = &dest_ptr[hdlc->dest_idx];
186 dest_length = hdlc->dest_size - hdlc->dest_idx;
187
188 for (i = 0; i < src_length; i++) {
189
190 src_byte = src_ptr[i];
191
192 if (hdlc->escaping) {
193 dest_ptr[len++] = src_byte ^ ESC_MASK;
194 hdlc->escaping = 0;
195 } else if (src_byte == ESC_CHAR) {
196 if (i == (src_length - 1)) {
197 hdlc->escaping = 1;
198 i++;
199 break;
200 } else {
201 dest_ptr[len++] = src_ptr[++i]
202 ^ ESC_MASK;
203 }
204 } else if (src_byte == CONTROL_CHAR) {
205 dest_ptr[len++] = src_byte;
206 pkt_bnd = 1;
207 i++;
208 break;
209 } else {
210 dest_ptr[len++] = src_byte;
211 }
212
213 if (len >= dest_length) {
214 i++;
215 break;
216 }
217 }
218
219 hdlc->src_idx += i;
220 hdlc->dest_idx += len;
221 }
222
223 return pkt_bnd;
224}