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