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 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 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 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 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 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 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 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 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 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 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 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 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