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