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  * serdrv.c - Synchronous Serial Driver for Angel.
16  *            This is nice and simple just to get something going.
17  */
18 
19 #ifdef __hpux
20 #  define _POSIX_SOURCE 1
21 #endif
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "crc.h"
28 #include "devices.h"
29 #include "buffers.h"
30 #include "rxtx.h"
31 #include "hostchan.h"
32 #include "params.h"
33 #include "logging.h"
34 
35 extern int baud_rate;   /* From gdb/top.c */
36 
37 #ifdef COMPILING_ON_WINDOWS
38 #  undef   ERROR
39 #  undef   IGNORE
40 #  include <windows.h>
41 #  include "angeldll.h"
42 #  include "comb_api.h"
43 #else
44 #  ifdef __hpux
45 #    define _TERMIOS_INCLUDED
46 #    include <sys/termio.h>
47 #    undef _TERMIOS_INCLUDED
48 #  else
49 #    include <termios.h>
50 #  endif
51 #  include "unixcomm.h"
52 #endif
53 
54 #ifndef UNUSED
55 #  define UNUSED(x) (x = x)      /* Silence compiler warnings */
56 #endif
57 
58 #define MAXREADSIZE 512
59 #define MAXWRITESIZE 512
60 
61 #define SERIAL_FC_SET  ((1<<serial_XON)|(1<<serial_XOFF))
62 #define SERIAL_CTL_SET ((1<<serial_STX)|(1<<serial_ETX)|(1<<serial_ESC))
63 #define SERIAL_ESC_SET (SERIAL_FC_SET|SERIAL_CTL_SET)
64 
65 static const struct re_config config = {
66     serial_STX, serial_ETX, serial_ESC, /* self-explanatory?               */
67     SERIAL_FC_SET,                      /* set of flow-control characters  */
68     SERIAL_ESC_SET,                     /* set of characters to be escaped */
69     NULL /* serial_flow_control */, NULL  ,    /* what to do with FC chars */
70     angel_DD_RxEng_BufferAlloc, NULL                /* how to get a buffer */
71 };
72 
73 static struct re_state rxstate;
74 
75 typedef struct writestate {
76   unsigned int wbindex;
77   /*  static te_status testatus;*/
78   unsigned char writebuf[MAXWRITESIZE];
79   struct te_state txstate;
80 } writestate;
81 
82 static struct writestate wstate;
83 
84 /*
85  * The set of parameter options supported by the device
86  */
87 static unsigned int baud_options[] = {
88 #if defined(B115200) || defined(__hpux)
89     115200,
90 #endif
91 #if defined(B57600) || defined(__hpux)
92     57600,
93 #endif
94     38400, 19200, 9600
95 };
96 
97 static ParameterList param_list[] = {
98     { AP_BAUD_RATE,
99       sizeof(baud_options)/sizeof(unsigned int),
100       baud_options }
101 };
102 
103 static const ParameterOptions serial_options = {
104     sizeof(param_list)/sizeof(ParameterList), param_list };
105 
106 /*
107  * The default parameter config for the device
108  */
109 static Parameter param_default[] = {
110     { AP_BAUD_RATE, 9600 }
111 };
112 
113 static ParameterConfig serial_defaults = {
114     sizeof(param_default)/sizeof(Parameter), param_default };
115 
116 /*
117  * The user-modified options for the device
118  */
119 static unsigned int user_baud_options[sizeof(baud_options)/sizeof(unsigned)];
120 
121 static ParameterList param_user_list[] = {
122     { AP_BAUD_RATE,
123       sizeof(user_baud_options)/sizeof(unsigned),
124       user_baud_options }
125 };
126 
127 static ParameterOptions user_options = {
128     sizeof(param_user_list)/sizeof(ParameterList), param_user_list };
129 
130 static bool user_options_set;
131 
132 /* forward declarations */
133 static int serial_reset( void );
134 static int serial_set_params( const ParameterConfig *config );
135 static int SerialMatch(const char *name, const char *arg);
136 
process_baud_rate(unsigned int target_baud_rate)137 static void process_baud_rate( unsigned int target_baud_rate )
138 {
139     const ParameterList *full_list;
140     ParameterList       *user_list;
141 
142     /* create subset of full options */
143     full_list = Angel_FindParamList( &serial_options, AP_BAUD_RATE );
144     user_list = Angel_FindParamList( &user_options,   AP_BAUD_RATE );
145 
146     if ( full_list != NULL && user_list != NULL )
147     {
148         unsigned int i, j;
149         unsigned int def_baud = 0;
150 
151         /* find lower or equal to */
152         for ( i = 0; i < full_list->num_options; ++i )
153            if ( target_baud_rate >= full_list->option[i] )
154            {
155                /* copy remaining */
156                for ( j = 0; j < (full_list->num_options - i); ++j )
157                   user_list->option[j] = full_list->option[i+j];
158                user_list->num_options = j;
159 
160                /* check this is not the default */
161                Angel_FindParam( AP_BAUD_RATE, &serial_defaults, &def_baud );
162                if ( (j == 1) && (user_list->option[0] == def_baud) )
163                {
164 #ifdef DEBUG
165                    printf( "user selected default\n" );
166 #endif
167                }
168                else
169                {
170                    user_options_set = TRUE;
171 #ifdef DEBUG
172                    printf( "user options are: " );
173                    for ( j = 0; j < user_list->num_options; ++j )
174                       printf( "%u ", user_list->option[j] );
175                    printf( "\n" );
176 #endif
177                }
178 
179                break;   /* out of i loop */
180            }
181 
182 #ifdef DEBUG
183         if ( i >= full_list->num_options )
184            printf( "couldn't match baud rate %u\n", target_baud_rate );
185 #endif
186     }
187 #ifdef DEBUG
188     else
189        printf( "failed to find lists\n" );
190 #endif
191 }
192 
SerialOpen(const char * name,const char * arg)193 static int SerialOpen(const char *name, const char *arg)
194 {
195     const char *port_name = name;
196 
197 #ifdef DEBUG
198     printf("SerialOpen: name %s arg %s\n", name, arg ? arg : "<NULL>");
199 #endif
200 
201 #ifdef COMPILING_ON_WINDOWS
202     if (IsOpenSerial()) return -1;
203 #else
204     if (Unix_IsSerialInUse()) return -1;
205 #endif
206 
207 #ifdef COMPILING_ON_WINDOWS
208     if (SerialMatch(name, arg) != adp_ok)
209         return adp_failed;
210 #else
211     port_name = Unix_MatchValidSerialDevice(port_name);
212 # ifdef DEBUG
213     printf("translated port to %s\n", port_name == 0 ? "NULL" : port_name);
214 # endif
215     if (port_name == 0) return adp_failed;
216 #endif
217 
218     user_options_set = FALSE;
219 
220     /* interpret and store the arguments */
221     if ( arg != NULL )
222     {
223         unsigned int target_baud_rate;
224         target_baud_rate = (unsigned int)strtoul(arg, NULL, 10);
225         if (target_baud_rate > 0)
226         {
227 #ifdef DEBUG
228             printf( "user selected baud rate %u\n", target_baud_rate );
229 #endif
230             process_baud_rate( target_baud_rate );
231         }
232 #ifdef DEBUG
233         else
234            printf( "could not understand baud rate %s\n", arg );
235 #endif
236     }
237     else if (baud_rate > 0)
238     {
239       /* If the user specified a baud rate on the command line "-b" or via
240          the "set remotebaud" command then try to use that one */
241       process_baud_rate( baud_rate );
242     }
243 
244 #ifdef COMPILING_ON_WINDOWS
245     {
246         int port = IsValidDevice(name);
247         if (OpenSerial(port, FALSE) != COM_OK)
248             return -1;
249     }
250 #else
251     if (Unix_OpenSerial(port_name) < 0)
252       return -1;
253 #endif
254 
255     serial_reset();
256 
257 #if defined(__unix) || defined(__CYGWIN__)
258     Unix_ioctlNonBlocking();
259 #endif
260 
261     Angel_RxEngineInit(&config, &rxstate);
262     /*
263      * DANGER!: passing in NULL as the packet is ok for now as it is just
264      * IGNOREd but this may well change
265      */
266     Angel_TxEngineInit(&config, NULL, &wstate.txstate);
267     return 0;
268 }
269 
SerialMatch(const char * name,const char * arg)270 static int SerialMatch(const char *name, const char *arg)
271 {
272     UNUSED(arg);
273 #ifdef COMPILING_ON_WINDOWS
274     if (IsValidDevice(name) == COM_DEVICENOTVALID)
275         return -1;
276     else
277         return 0;
278 #else
279     return Unix_MatchValidSerialDevice(name) == 0 ? -1 : 0;
280 #endif
281 }
282 
SerialClose(void)283 static void SerialClose(void)
284 {
285 #ifdef DO_TRACE
286     printf("SerialClose()\n");
287 #endif
288 
289 #ifdef COMPILING_ON_WINDOWS
290     CloseSerial();
291 #else
292     Unix_CloseSerial();
293 #endif
294 }
295 
SerialRead(DriverCall * dc,bool block)296 static int SerialRead(DriverCall *dc, bool block) {
297   static unsigned char readbuf[MAXREADSIZE];
298   static int rbindex=0;
299 
300   int nread;
301   int read_errno;
302   int c=0;
303   re_status restatus;
304   int ret_code = -1;            /* assume bad packet or error */
305 
306   /* must not overflow buffer and must start after the existing data */
307 #ifdef COMPILING_ON_WINDOWS
308   {
309     BOOL dummy = FALSE;
310     nread = BytesInRXBufferSerial();
311 
312     if (nread > MAXREADSIZE - rbindex)
313       nread = MAXREADSIZE - rbindex;
314 
315     if ((read_errno = ReadSerial(readbuf+rbindex, nread, &dummy)) == COM_READFAIL)
316     {
317         MessageBox(GetFocus(), "Read error\n", "Angel", MB_OK | MB_ICONSTOP);
318         return -1;   /* SJ - This really needs to return a value, which is picked up in */
319                      /*      DevSW_Read as meaning stop debugger but don't kill. */
320     }
321     else if (pfnProgressCallback != NULL && read_errno == COM_OK)
322     {
323       progressInfo.nRead += nread;
324       (*pfnProgressCallback)(&progressInfo);
325     }
326   }
327 #else
328   nread = Unix_ReadSerial(readbuf+rbindex, MAXREADSIZE-rbindex, block);
329   read_errno = errno;
330 #endif
331 
332   if ((nread > 0) || (rbindex > 0)) {
333 
334 #ifdef DO_TRACE
335     printf("[%d@%d] ", nread, rbindex);
336 #endif
337 
338     if (nread>0)
339        rbindex = rbindex+nread;
340 
341     do {
342       restatus = Angel_RxEngine(readbuf[c], &(dc->dc_packet), &rxstate);
343 #ifdef DO_TRACE
344       printf("<%02X ",readbuf[c]);
345       if (!(++c % 16))
346           printf("\n");
347 #else
348       c++;
349 #endif
350     } while (c<rbindex &&
351              ((restatus == RS_IN_PKT) || (restatus == RS_WAIT_PKT)));
352 
353 #ifdef DO_TRACE
354    if (c % 16)
355         printf("\n");
356 #endif
357 
358     switch(restatus) {
359 
360       case RS_GOOD_PKT:
361         ret_code = 1;
362         /* fall through to: */
363 
364       case RS_BAD_PKT:
365         /*
366          * We now need to shuffle any left over data down to the
367          * beginning of our private buffer ready to be used
368          *for the next packet
369          */
370 #ifdef DO_TRACE
371         printf("SerialRead() processed %d, moving down %d\n", c, rbindex-c);
372 #endif
373         if (c != rbindex) memmove((char *) readbuf, (char *) (readbuf+c),
374                                   rbindex-c);
375         rbindex -= c;
376         break;
377 
378       case RS_IN_PKT:
379       case RS_WAIT_PKT:
380         rbindex = 0;            /* will have processed all we had */
381         ret_code = 0;
382         break;
383 
384       default:
385 #ifdef DEBUG
386         printf("Bad re_status in serialRead()\n");
387 #endif
388         break;
389     }
390   } else if (nread == 0)
391     ret_code = 0;               /* nothing to read */
392   else if (read_errno == ERRNO_FOR_BLOCKED_IO) /* nread < 0 */
393     ret_code = 0;
394 
395 #ifdef DEBUG
396   if ((nread<0) && (read_errno!=ERRNO_FOR_BLOCKED_IO))
397     perror("read() error in serialRead()");
398 #endif
399 
400   return ret_code;
401 }
402 
403 
SerialWrite(DriverCall * dc)404 static int SerialWrite(DriverCall *dc) {
405   int nwritten = 0;
406   te_status testatus = TS_IN_PKT;
407 
408   if (dc->dc_context == NULL) {
409     Angel_TxEngineInit(&config, &(dc->dc_packet), &(wstate.txstate));
410     wstate.wbindex = 0;
411     dc->dc_context = &wstate;
412   }
413 
414   while ((testatus == TS_IN_PKT) && (wstate.wbindex < MAXWRITESIZE))
415   {
416     /* send the raw data through the tx engine to escape and encapsulate */
417     testatus = Angel_TxEngine(&(dc->dc_packet), &(wstate.txstate),
418                               &(wstate.writebuf)[wstate.wbindex]);
419     if (testatus != TS_IDLE) wstate.wbindex++;
420   }
421 
422   if (testatus == TS_IDLE) {
423 #ifdef DEBUG
424     printf("SerialWrite: testatus is TS_IDLE during preprocessing\n");
425 #endif
426   }
427 
428 #ifdef DO_TRACE
429   {
430     int i = 0;
431 
432     while (i<wstate.wbindex)
433     {
434         printf(">%02X ",wstate.writebuf[i]);
435 
436         if (!(++i % 16))
437             printf("\n");
438     }
439     if (i % 16)
440         printf("\n");
441   }
442 #endif
443 
444 #ifdef COMPILING_ON_WINDOWS
445   if (WriteSerial(wstate.writebuf, wstate.wbindex) == COM_OK)
446   {
447     nwritten = wstate.wbindex;
448     if (pfnProgressCallback != NULL)
449     {
450       progressInfo.nWritten += nwritten;
451       (*pfnProgressCallback)(&progressInfo);
452     }
453   }
454   else
455   {
456       MessageBox(GetFocus(), "Write error\n", "Angel", MB_OK | MB_ICONSTOP);
457       return -1;   /* SJ - This really needs to return a value, which is picked up in */
458                    /*      DevSW_Read as meaning stop debugger but don't kill. */
459   }
460 #else
461   nwritten = Unix_WriteSerial(wstate.writebuf, wstate.wbindex);
462 
463   if (nwritten < 0) {
464     nwritten=0;
465   }
466 #endif
467 
468 #ifdef DEBUG
469   if (nwritten > 0)
470     printf("Wrote %#04x bytes\n", nwritten);
471 #endif
472 
473   if ((unsigned) nwritten == wstate.wbindex &&
474       (testatus == TS_DONE_PKT || testatus == TS_IDLE)) {
475 
476     /* finished sending the packet */
477 
478 #ifdef DEBUG
479     printf("SerialWrite: calling Angel_TxEngineInit after sending packet (len=%i)\n",wstate.wbindex);
480 #endif
481     testatus = TS_IN_PKT;
482     wstate.wbindex = 0;
483     return 1;
484   }
485   else {
486 #ifdef DEBUG
487     printf("SerialWrite: Wrote part of packet wbindex=%i, nwritten=%i\n",
488            wstate.wbindex, nwritten);
489 #endif
490 
491     /*
492      *  still some data left to send shuffle whats left down and reset
493      * the ptr
494      */
495     memmove((char *) wstate.writebuf, (char *) (wstate.writebuf+nwritten),
496             wstate.wbindex-nwritten);
497     wstate.wbindex -= nwritten;
498     return 0;
499   }
500   return -1;
501 }
502 
503 
serial_reset(void)504 static int serial_reset( void )
505 {
506 #ifdef DEBUG
507     printf( "serial_reset\n" );
508 #endif
509 
510 #ifdef COMPILING_ON_WINDOWS
511     FlushSerial();
512 #else
513     Unix_ResetSerial();
514 #endif
515 
516     return serial_set_params( &serial_defaults );
517 }
518 
519 
find_baud_rate(unsigned int * speed)520 static int find_baud_rate( unsigned int *speed )
521 {
522     static struct {
523           unsigned int baud;
524           int termiosValue;
525     } possibleBaudRates[] = {
526 #if defined(__hpux)
527         {115200,_B115200}, {57600,_B57600},
528 #else
529 #ifdef B115200
530         {115200,B115200},
531 #endif
532 #ifdef B57600
533 	{57600,B57600},
534 #endif
535 #endif
536 #ifdef COMPILING_ON_WINDOWS
537         {38400,CBR_38400}, {19200,CBR_19200}, {9600, CBR_9600}, {0,0}
538 #else
539         {38400,B38400}, {19200,B19200}, {9600, B9600}, {0,0}
540 #endif
541     };
542     unsigned int i;
543 
544     /* look for lower or matching -- will always terminate at 0 end marker */
545     for ( i = 0; possibleBaudRates[i].baud > *speed; ++i )
546        /* do nothing */ ;
547 
548     if ( possibleBaudRates[i].baud > 0 )
549        *speed = possibleBaudRates[i].baud;
550 
551     return possibleBaudRates[i].termiosValue;
552 }
553 
554 
serial_set_params(const ParameterConfig * config)555 static int serial_set_params( const ParameterConfig *config )
556 {
557     unsigned int speed;
558     int termios_value;
559 
560 #ifdef DEBUG
561     printf( "serial_set_params\n" );
562 #endif
563 
564     if ( ! Angel_FindParam( AP_BAUD_RATE, config, &speed ) )
565     {
566 #ifdef DEBUG
567         printf( "speed not found in config\n" );
568 #endif
569         return DE_OKAY;
570     }
571 
572     termios_value = find_baud_rate( &speed );
573     if ( termios_value == 0 )
574     {
575 #ifdef DEBUG
576         printf( "speed not valid: %u\n", speed );
577 #endif
578         return DE_OKAY;
579     }
580 
581 #ifdef DEBUG
582     printf( "setting speed to %u\n", speed );
583 #endif
584 
585 #ifdef COMPILING_ON_WINDOWS
586     SetBaudRate((WORD)termios_value);
587 #else
588     Unix_SetSerialBaudRate(termios_value);
589 #endif
590 
591     return DE_OKAY;
592 }
593 
594 
serial_get_user_params(ParameterOptions ** p_options)595 static int serial_get_user_params( ParameterOptions **p_options )
596 {
597 #ifdef DEBUG
598     printf( "serial_get_user_params\n" );
599 #endif
600 
601     if ( user_options_set )
602     {
603         *p_options = &user_options;
604     }
605     else
606     {
607         *p_options = NULL;
608     }
609 
610     return DE_OKAY;
611 }
612 
613 
serial_get_default_params(ParameterConfig ** p_config)614 static int serial_get_default_params( ParameterConfig **p_config )
615 {
616 #ifdef DEBUG
617     printf( "serial_get_default_params\n" );
618 #endif
619 
620     *p_config = (ParameterConfig *) &serial_defaults;
621     return DE_OKAY;
622 }
623 
624 
SerialIoctl(const int opcode,void * args)625 static int SerialIoctl(const int opcode, void *args) {
626 
627     int ret_code;
628 
629 #ifdef DEBUG
630     printf( "SerialIoctl: op %d arg %p\n", opcode, args ? args : "<NULL>");
631 #endif
632 
633     switch (opcode)
634     {
635        case DC_RESET:
636            ret_code = serial_reset();
637            break;
638 
639        case DC_SET_PARAMS:
640            ret_code = serial_set_params((const ParameterConfig *)args);
641            break;
642 
643        case DC_GET_USER_PARAMS:
644            ret_code = serial_get_user_params((ParameterOptions **)args);
645            break;
646 
647        case DC_GET_DEFAULT_PARAMS:
648            ret_code = serial_get_default_params((ParameterConfig **)args);
649            break;
650 
651        default:
652            ret_code = DE_BAD_OP;
653            break;
654     }
655 
656   return ret_code;
657 }
658 
659 DeviceDescr angel_SerialDevice = {
660     "SERIAL",
661     SerialOpen,
662     SerialMatch,
663     SerialClose,
664     SerialRead,
665     SerialWrite,
666     SerialIoctl
667 };
668