1b725ae77Skettenis /*
2b725ae77Skettenis * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3b725ae77Skettenis *
4b725ae77Skettenis * This software may be freely used, copied, modified, and distributed
5b725ae77Skettenis * provided that the above copyright notice is preserved in all copies of the
6b725ae77Skettenis * software.
7b725ae77Skettenis */
8b725ae77Skettenis
9b725ae77Skettenis /*-*-C-*-
10b725ae77Skettenis *
11*63addd46Skettenis * $Revision: 1.3 $
12*63addd46Skettenis * $Date: 2004/12/27 14:00:54 $
13b725ae77Skettenis *
14b725ae77Skettenis *
15b725ae77Skettenis * Project: ANGEL
16b725ae77Skettenis *
17b725ae77Skettenis * Title: Character reception engine
18b725ae77Skettenis */
19b725ae77Skettenis
20b725ae77Skettenis #include <stdarg.h> /* ANSI varargs support */
21b725ae77Skettenis #include "angel.h" /* Angel system definitions */
22b725ae77Skettenis #include "angel_endian.h" /* Endian independant memory access macros */
23b725ae77Skettenis #include "crc.h" /* crc generation definitions and headers */
24b725ae77Skettenis #include "rxtx.h"
25b725ae77Skettenis #include "channels.h"
26b725ae77Skettenis #include "buffers.h"
27b725ae77Skettenis #ifdef TARGET
28b725ae77Skettenis # include "devdriv.h"
29b725ae77Skettenis #endif
30b725ae77Skettenis #include "logging.h"
31b725ae77Skettenis
32b725ae77Skettenis static re_status unexp_stx(struct re_state *rxstate);
33b725ae77Skettenis static re_status unexp_etx(struct re_state *rxstate);
34b725ae77Skettenis
35b725ae77Skettenis /* bitfield for the rx_engine state */
36b725ae77Skettenis typedef enum rx_state_flag{
37b725ae77Skettenis RST_STX,
38b725ae77Skettenis RST_TYP,
39b725ae77Skettenis RST_LEN,
40b725ae77Skettenis RST_DAT,
41b725ae77Skettenis RST_CRC,
42b725ae77Skettenis RST_ETX,
43b725ae77Skettenis RST_ESC = (0x1 << 0x3)
44b725ae77Skettenis } rx_state_flag;
45b725ae77Skettenis
Angel_RxEngineInit(const struct re_config * rxconfig,struct re_state * rxstate)46b725ae77Skettenis void Angel_RxEngineInit(const struct re_config *rxconfig,
47b725ae77Skettenis struct re_state *rxstate)
48b725ae77Skettenis {
49b725ae77Skettenis rxstate->rx_state = RST_STX;
50b725ae77Skettenis rxstate->field_c = 0;
51b725ae77Skettenis rxstate->index = 0;
52b725ae77Skettenis rxstate->crc = 0;
53b725ae77Skettenis rxstate->error = RE_OKAY;
54b725ae77Skettenis rxstate->config = rxconfig;
55b725ae77Skettenis }
56b725ae77Skettenis
Angel_RxEngine(unsigned char new_ch,struct data_packet * packet,struct re_state * rxstate)57b725ae77Skettenis re_status Angel_RxEngine(unsigned char new_ch, struct data_packet *packet,
58b725ae77Skettenis struct re_state *rxstate)
59b725ae77Skettenis {
60b725ae77Skettenis /*
61b725ae77Skettenis * TODO: add the flow control bits in
62b725ae77Skettenis * Note: We test for the data field in a seperate case so we can
63b725ae77Skettenis * completely avoid entering the switch for most chars
64b725ae77Skettenis */
65b725ae77Skettenis
66b725ae77Skettenis /* see if we're expecting a escaped char */
67b725ae77Skettenis if ((rxstate->rx_state & RST_ESC) == RST_ESC)
68b725ae77Skettenis {
69b725ae77Skettenis /* unescape the char and unset the flag*/
70b725ae77Skettenis new_ch &= ~serial_ESCAPE;
71b725ae77Skettenis #ifdef DO_TRACE
72b725ae77Skettenis __rt_trace("rxe-echar-%2x ", new_ch);
73b725ae77Skettenis #endif
74b725ae77Skettenis rxstate->rx_state &= ~RST_ESC;
75b725ae77Skettenis }
76b725ae77Skettenis else if ( (1 << new_ch) & rxstate->config->esc_set )
77b725ae77Skettenis {
78b725ae77Skettenis /* see if the incoming char is a special one */
79b725ae77Skettenis if (new_ch == rxstate->config->esc)
80b725ae77Skettenis {
81b725ae77Skettenis #ifdef DO_TRACE
82b725ae77Skettenis __rt_trace("rxe-esc ");
83b725ae77Skettenis #endif
84b725ae77Skettenis rxstate->rx_state |= RST_ESC;
85b725ae77Skettenis return RS_IN_PKT;
86b725ae77Skettenis }
87b725ae77Skettenis else
88b725ae77Skettenis {
89b725ae77Skettenis /*
90b725ae77Skettenis * must be a normal packet so do some unexpected etx/stx checking
91b725ae77Skettenis * we haven't been told to escape or received an escape so unless
92b725ae77Skettenis * we are expecting an stx or etx then we can take the unexpected
93b725ae77Skettenis * stx/etx trap
94b725ae77Skettenis */
95b725ae77Skettenis if ((new_ch == (rxstate->config->stx)) && (rxstate->rx_state != RST_STX))
96b725ae77Skettenis return unexp_stx(rxstate);
97b725ae77Skettenis if ((new_ch == (rxstate->config->etx)) && (rxstate->rx_state != RST_ETX))
98b725ae77Skettenis return unexp_etx(rxstate);
99b725ae77Skettenis }
100b725ae77Skettenis }
101b725ae77Skettenis
102b725ae77Skettenis if (rxstate->rx_state == RST_DAT)
103b725ae77Skettenis {
104b725ae77Skettenis /*
105b725ae77Skettenis * do this to speed up the common case, no real penalty for
106b725ae77Skettenis * other cases
107b725ae77Skettenis */
108b725ae77Skettenis #ifdef DO_TRACE
109b725ae77Skettenis __rt_trace("rxe-dat ");
110b725ae77Skettenis #endif
111b725ae77Skettenis
112b725ae77Skettenis rxstate->crc = crc32(&new_ch, 1, rxstate->crc);
113b725ae77Skettenis (packet->data)[rxstate->index++] = (unsigned int)new_ch & 0xff;
114b725ae77Skettenis
115b725ae77Skettenis if (rxstate->index == packet->len)
116b725ae77Skettenis rxstate->rx_state = RST_CRC;
117b725ae77Skettenis
118b725ae77Skettenis return RS_IN_PKT;
119b725ae77Skettenis }
120b725ae77Skettenis
121b725ae77Skettenis /*
122b725ae77Skettenis * Now that the common case is out of the way we can test for everything
123b725ae77Skettenis * else without worrying quite so much about the speed, changing the
124b725ae77Skettenis * order to len,crc,stx,etx,typ might gain a tiny bit of speed but lets
125b725ae77Skettenis * leave that for the moment
126b725ae77Skettenis */
127b725ae77Skettenis switch (rxstate->rx_state)
128b725ae77Skettenis {
129b725ae77Skettenis case RST_STX:
130b725ae77Skettenis if (new_ch == rxstate->config->stx)
131b725ae77Skettenis {
132b725ae77Skettenis rxstate->rx_state = RST_TYP;
133b725ae77Skettenis rxstate->error = RE_OKAY;
134b725ae77Skettenis rxstate->crc = startCRC32;
135b725ae77Skettenis rxstate->index = 0;
136b725ae77Skettenis return RS_IN_PKT;
137b725ae77Skettenis }
138b725ae77Skettenis else
139b725ae77Skettenis {
140b725ae77Skettenis rxstate->error = RE_OKAY;
141b725ae77Skettenis return RS_WAIT_PKT;
142b725ae77Skettenis }
143b725ae77Skettenis
144b725ae77Skettenis case RST_TYP:
145b725ae77Skettenis packet->type = (DevChanID)new_ch;
146b725ae77Skettenis rxstate->rx_state = RST_LEN;
147b725ae77Skettenis rxstate->error = RE_OKAY;
148b725ae77Skettenis rxstate->field_c = 0; /* set up here for the length that follows */
149b725ae77Skettenis #ifdef DO_TRACE
150b725ae77Skettenis __rt_trace("rxe-type-%2x ", packet->type);
151b725ae77Skettenis #endif
152b725ae77Skettenis rxstate->crc = crc32(&new_ch, 1, rxstate->crc);
153b725ae77Skettenis
154b725ae77Skettenis return RS_IN_PKT;
155b725ae77Skettenis
156b725ae77Skettenis case RST_LEN:
157b725ae77Skettenis rxstate->crc = crc32(&new_ch, 1, rxstate->crc);
158b725ae77Skettenis
159b725ae77Skettenis if (rxstate->field_c++ == 0)
160b725ae77Skettenis {
161b725ae77Skettenis /* first length byte */
162b725ae77Skettenis packet->len = ((unsigned int)new_ch) << 8;
163b725ae77Skettenis return RS_IN_PKT;
164b725ae77Skettenis }
165b725ae77Skettenis else
166b725ae77Skettenis {
167b725ae77Skettenis /* got the whole legth */
168b725ae77Skettenis packet->len |= new_ch;
169b725ae77Skettenis #ifdef DO_TRACE
170b725ae77Skettenis __rt_trace("rxe-len-%4x\n", packet->len);
171b725ae77Skettenis #endif
172b725ae77Skettenis
173b725ae77Skettenis /* check that the length is ok */
174b725ae77Skettenis if (packet->len == 0)
175b725ae77Skettenis {
176b725ae77Skettenis /* empty pkt */
177b725ae77Skettenis rxstate->field_c = 0;
178b725ae77Skettenis rxstate->rx_state = RST_CRC;
179b725ae77Skettenis return RS_IN_PKT;
180b725ae77Skettenis }
181b725ae77Skettenis else
182b725ae77Skettenis {
183b725ae77Skettenis if (packet->data == NULL)
184b725ae77Skettenis {
185b725ae77Skettenis /* need to alloc the data buffer */
186b725ae77Skettenis if (!rxstate->config->ba_callback(
187b725ae77Skettenis packet, rxstate->config->ba_data)) {
188b725ae77Skettenis rxstate->rx_state = RST_STX;
189b725ae77Skettenis rxstate->error = RE_INTERNAL;
190b725ae77Skettenis return RS_BAD_PKT;
191b725ae77Skettenis }
192b725ae77Skettenis }
193b725ae77Skettenis
194b725ae77Skettenis if (packet->len > packet->buf_len)
195b725ae77Skettenis {
196b725ae77Skettenis /* pkt bigger than buffer */
197b725ae77Skettenis rxstate->field_c = 0;
198b725ae77Skettenis rxstate->rx_state = RST_STX;
199b725ae77Skettenis rxstate->error = RE_LEN;
200b725ae77Skettenis return RS_BAD_PKT;
201b725ae77Skettenis }
202b725ae77Skettenis else
203b725ae77Skettenis {
204b725ae77Skettenis /* packet ok */
205b725ae77Skettenis rxstate->field_c = 0;
206b725ae77Skettenis rxstate->rx_state = RST_DAT;
207b725ae77Skettenis return RS_IN_PKT;
208b725ae77Skettenis }
209b725ae77Skettenis }
210b725ae77Skettenis }
211b725ae77Skettenis
212b725ae77Skettenis case RST_DAT:
213b725ae77Skettenis /* dummy case (dealt with earlier) */
214b725ae77Skettenis #ifdef ASSERTIONS_ENABLED
215b725ae77Skettenis __rt_warning("ERROR: hit RST_dat in switch\n");
216b725ae77Skettenis #endif
217b725ae77Skettenis rxstate->rx_state = RST_STX;
218b725ae77Skettenis rxstate->error = RE_INTERNAL;
219b725ae77Skettenis return RS_BAD_PKT;
220b725ae77Skettenis
221b725ae77Skettenis case RST_CRC:
222b725ae77Skettenis if (rxstate->field_c == 0)
223b725ae77Skettenis packet->crc = 0;
224b725ae77Skettenis
225b725ae77Skettenis packet->crc |= (new_ch & 0xFF) << ((3 - rxstate->field_c) * 8);
226b725ae77Skettenis rxstate->field_c++;
227b725ae77Skettenis
228b725ae77Skettenis if (rxstate->field_c == 4)
229b725ae77Skettenis {
230b725ae77Skettenis /* last crc field */
231b725ae77Skettenis rxstate->field_c = 0;
232b725ae77Skettenis rxstate->rx_state = RST_ETX;
233b725ae77Skettenis #ifdef DO_TRACE
234b725ae77Skettenis __rt_trace("rxe-rcrc-%8x ", packet->crc);
235b725ae77Skettenis #endif
236b725ae77Skettenis }
237b725ae77Skettenis
238b725ae77Skettenis return RS_IN_PKT;
239b725ae77Skettenis
240b725ae77Skettenis case RST_ETX:
241b725ae77Skettenis if (new_ch == rxstate->config->etx)
242b725ae77Skettenis {
243b725ae77Skettenis #if defined(DEBUG) && !defined(NO_PKT_DATA)
244b725ae77Skettenis {
245b725ae77Skettenis int c;
246b725ae77Skettenis # ifdef DO_TRACE
247b725ae77Skettenis __rt_trace("\n");
248b725ae77Skettenis # endif
249b725ae77Skettenis __rt_info("RXE Data =");
250b725ae77Skettenis for (c=0; c < packet->len; c++)
251b725ae77Skettenis __rt_info("%02x", packet->data[c]);
252b725ae77Skettenis __rt_info("\n");
253b725ae77Skettenis }
254b725ae77Skettenis #endif
255b725ae77Skettenis
256b725ae77Skettenis /* check crc */
257b725ae77Skettenis if (rxstate->crc == packet->crc)
258b725ae77Skettenis {
259b725ae77Skettenis /* crc ok */
260b725ae77Skettenis rxstate->rx_state = RST_STX;
261b725ae77Skettenis rxstate->field_c = 0;
262b725ae77Skettenis return RS_GOOD_PKT;
263b725ae77Skettenis }
264b725ae77Skettenis else
265b725ae77Skettenis {
266b725ae77Skettenis #ifdef ASSERTIONS_ENABLED
267b725ae77Skettenis __rt_warning("Bad crc, rx calculates it should be 0x%x\n", rxstate->crc);
268b725ae77Skettenis #endif
269b725ae77Skettenis rxstate->rx_state = RST_STX;
270b725ae77Skettenis rxstate->error = RE_CRC;
271b725ae77Skettenis return RS_BAD_PKT;
272b725ae77Skettenis }
273b725ae77Skettenis }
274b725ae77Skettenis else if (new_ch == rxstate->config->stx)
275b725ae77Skettenis return unexp_stx(rxstate);
276b725ae77Skettenis else
277b725ae77Skettenis {
278b725ae77Skettenis rxstate->rx_state = RST_STX;
279b725ae77Skettenis rxstate->error = RE_NETX;
280b725ae77Skettenis return RS_BAD_PKT;
281b725ae77Skettenis }
282b725ae77Skettenis
283b725ae77Skettenis default:
284b725ae77Skettenis #ifdef ASSERTIONS_ENABLED
285b725ae77Skettenis __rt_warning("ERROR fell through rxengine\n");
286b725ae77Skettenis #endif
287b725ae77Skettenis rxstate->rx_state = RST_STX;
288b725ae77Skettenis rxstate->error = RE_INTERNAL;
289b725ae77Skettenis return RS_BAD_PKT;
290b725ae77Skettenis }
291b725ae77Skettenis }
292b725ae77Skettenis
unexp_stx(struct re_state * rxstate)293b725ae77Skettenis static re_status unexp_stx(struct re_state *rxstate)
294b725ae77Skettenis {
295b725ae77Skettenis #ifdef ASSERTIONS_ENABLED
296b725ae77Skettenis __rt_warning("Unexpected stx\n");
297b725ae77Skettenis #endif
298b725ae77Skettenis rxstate->crc = startCRC32;
299b725ae77Skettenis rxstate->index = 0;
300b725ae77Skettenis rxstate->rx_state = RST_TYP;
301b725ae77Skettenis rxstate->error = RE_U_STX;
302b725ae77Skettenis rxstate->field_c = 0;
303b725ae77Skettenis return RS_BAD_PKT;
304b725ae77Skettenis }
305b725ae77Skettenis
unexp_etx(struct re_state * rxstate)306b725ae77Skettenis static re_status unexp_etx(struct re_state *rxstate)
307b725ae77Skettenis {
308b725ae77Skettenis #ifdef ASSERTIONS_ENABLED
309b725ae77Skettenis __rt_warning("Unexpected etx, rxstate: index= 0x%2x, field_c=0x%2x, state=0x%2x\n", rxstate->index, rxstate->field_c, rxstate->rx_state);
310b725ae77Skettenis #endif
311b725ae77Skettenis rxstate->crc = 0;
312b725ae77Skettenis rxstate->index = 0;
313b725ae77Skettenis rxstate->rx_state = RST_STX;
314b725ae77Skettenis rxstate->error = RE_U_ETX;
315b725ae77Skettenis rxstate->field_c = 0;
316b725ae77Skettenis return RS_BAD_PKT;
317b725ae77Skettenis }
318b725ae77Skettenis
319b725ae77Skettenis /*
320b725ae77Skettenis * This can be used as the buffer allocation callback for the rx engine,
321b725ae77Skettenis * and makes use of angel_DD_GetBuffer() [in devdrv.h].
322b725ae77Skettenis *
323b725ae77Skettenis * Saves duplicating this callback function in every device driver that
324b725ae77Skettenis * uses the rx engine.
325b725ae77Skettenis *
326b725ae77Skettenis * Note that this REQUIRES that the device id is installed as ba_data
327b725ae77Skettenis * in the rx engine config structure for the driver.
328b725ae77Skettenis */
angel_DD_RxEng_BufferAlloc(struct data_packet * packet,void * cb_data)329b725ae77Skettenis bool angel_DD_RxEng_BufferAlloc( struct data_packet *packet, void *cb_data )
330b725ae77Skettenis {
331b725ae77Skettenis #ifdef TARGET
332b725ae77Skettenis DeviceID devid = (DeviceID)cb_data;
333b725ae77Skettenis #else
334b725ae77Skettenis IGNORE(cb_data);
335b725ae77Skettenis #endif
336b725ae77Skettenis
337b725ae77Skettenis if ( packet->type < DC_NUM_CHANNELS )
338b725ae77Skettenis {
339b725ae77Skettenis /* request a buffer down from the channels layer */
340b725ae77Skettenis #ifdef TARGET
341b725ae77Skettenis packet->data = angel_DD_GetBuffer( devid, packet->type,
342b725ae77Skettenis packet->len );
343b725ae77Skettenis #else
344b725ae77Skettenis packet->data = malloc(packet->len);
345b725ae77Skettenis #endif
346b725ae77Skettenis if ( packet->data == NULL )
347b725ae77Skettenis return FALSE;
348b725ae77Skettenis else
349b725ae77Skettenis {
350b725ae77Skettenis packet->buf_len = packet->len;
351b725ae77Skettenis return TRUE;
352b725ae77Skettenis }
353b725ae77Skettenis }
354b725ae77Skettenis else
355b725ae77Skettenis {
356b725ae77Skettenis /* bad type field */
357b725ae77Skettenis return FALSE;
358b725ae77Skettenis }
359b725ae77Skettenis }
360b725ae77Skettenis
361b725ae77Skettenis /* EOF rx.c */
362