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 * serpardv.c - Serial/Parallel Driver for Angel. 16 */ 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 21 #include "crc.h" 22 #include "devices.h" 23 #include "buffers.h" 24 #include "rxtx.h" 25 #include "hostchan.h" 26 #include "params.h" 27 #include "logging.h" 28 #include "hsys.h" 29 30 #ifdef COMPILING_ON_WINDOWS 31 # undef ERROR 32 # undef IGNORE 33 # include <windows.h> 34 # include "angeldll.h" 35 # include "comb_api.h" 36 #else 37 # ifdef __hpux 38 # define _TERMIOS_INCLUDED 39 # include <sys/termio.h> 40 # undef _TERMIOS_INCLUDED 41 # else 42 # include <termios.h> 43 # endif 44 # include "unixcomm.h" 45 #endif 46 47 #ifndef UNUSED 48 # define UNUSED(x) (x = x) /* Silence compiler warnings */ 49 #endif 50 51 #define MAXREADSIZE 512 52 #define MAXWRITESIZE 512 53 54 #define SERPAR_FC_SET ((1 << serial_XON) | (1 << serial_XOFF)) 55 #define SERPAR_CTL_SET ((1 << serial_STX) | (1 << serial_ETX) | \ 56 (1 << serial_ESC)) 57 #define SERPAR_ESC_SET (SERPAR_FC_SET | SERPAR_CTL_SET) 58 59 static const struct re_config config = { 60 serial_STX, serial_ETX, serial_ESC, /* self-explanatory? */ 61 SERPAR_FC_SET, /* set of flow-control characters */ 62 SERPAR_ESC_SET, /* set of characters to be escaped */ 63 NULL, /* serial_flow_control */ 64 NULL, /* what to do with FC chars */ 65 angel_DD_RxEng_BufferAlloc, NULL /* how to get a buffer */ 66 }; 67 68 static struct re_state rxstate; 69 70 /* 71 * structure used for manipulating transmit data 72 */ 73 typedef struct TxState 74 { 75 struct te_state state; 76 unsigned int index; 77 unsigned char writebuf[MAXWRITESIZE]; 78 } TxState; 79 80 /* 81 * The set of parameter options supported by the device 82 */ 83 static unsigned int baud_options[] = 84 { 85 #ifdef __hpux 86 115200, 57600, 87 #endif 88 38400, 19200, 9600 89 }; 90 91 static ParameterList param_list[] = 92 { 93 { 94 AP_BAUD_RATE, 95 sizeof(baud_options) / sizeof(unsigned int), 96 baud_options 97 } 98 }; 99 100 static const ParameterOptions serpar_options = 101 { 102 sizeof(param_list) / sizeof(ParameterList), 103 param_list 104 }; 105 106 /* 107 * The default parameter config for the device 108 */ 109 static Parameter param_default[] = 110 { 111 { AP_BAUD_RATE, 9600 } 112 }; 113 114 static const ParameterConfig serpar_defaults = 115 { 116 sizeof(param_default)/sizeof(Parameter), 117 param_default 118 }; 119 120 /* 121 * The user-modified options for the device 122 */ 123 static unsigned int user_baud_options[sizeof(baud_options) / 124 sizeof(unsigned int)]; 125 126 static ParameterList param_user_list[] = 127 { 128 { 129 AP_BAUD_RATE, 130 sizeof(user_baud_options) / sizeof(unsigned), 131 user_baud_options 132 } 133 }; 134 135 static ParameterOptions user_options = 136 { 137 sizeof(param_user_list) / sizeof(ParameterList), 138 param_user_list 139 }; 140 141 static bool user_options_set; 142 143 /* forward declarations */ 144 static int serpar_reset(void); 145 static int serpar_set_params(const ParameterConfig *config); 146 static int SerparMatch(const char *name, const char *arg); 147 148 static void process_baud_rate(unsigned int target_baud_rate) 149 { 150 const ParameterList *full_list; 151 ParameterList *user_list; 152 153 /* create subset of full options */ 154 full_list = Angel_FindParamList(&serpar_options, AP_BAUD_RATE); 155 user_list = Angel_FindParamList(&user_options, AP_BAUD_RATE); 156 157 if (full_list != NULL && user_list != NULL) 158 { 159 unsigned int i, j; 160 unsigned int def_baud = 0; 161 162 /* find lower or equal to */ 163 for (i = 0; i < full_list->num_options; ++i) 164 if (target_baud_rate >= full_list->option[i]) 165 { 166 /* copy remaining */ 167 for (j = 0; j < (full_list->num_options - i); ++j) 168 user_list->option[j] = full_list->option[i+j]; 169 user_list->num_options = j; 170 171 /* check this is not the default */ 172 Angel_FindParam(AP_BAUD_RATE, &serpar_defaults, &def_baud); 173 if ((j == 1) && (user_list->option[0] == def_baud)) 174 { 175 #ifdef DEBUG 176 printf("user selected default\n"); 177 #endif 178 } 179 else 180 { 181 user_options_set = TRUE; 182 #ifdef DEBUG 183 printf("user options are: "); 184 for (j = 0; j < user_list->num_options; ++j) 185 printf("%u ", user_list->option[j]); 186 printf("\n"); 187 #endif 188 } 189 190 break; /* out of i loop */ 191 } 192 193 #ifdef DEBUG 194 if (i >= full_list->num_options) 195 printf("couldn't match baud rate %u\n", target_baud_rate); 196 #endif 197 } 198 #ifdef DEBUG 199 else 200 printf("failed to find lists\n"); 201 #endif 202 } 203 204 static int SerparOpen(const char *name, const char *arg) 205 { 206 char *sername = NULL; 207 char *parname = NULL; 208 209 #ifdef DEBUG 210 printf("SerparOpen: name %s arg %s\n", name, arg ? arg : "<NULL>"); 211 #endif 212 213 #ifdef COMPILING_ON_WINDOWS 214 if (IsOpenSerial() || IsOpenParallel()) return -1; 215 #else 216 if (Unix_IsSerialInUse() || Unix_IsParallelInUse()) return -1; 217 #endif 218 219 #ifdef COMPILING_ON_WINDOWS 220 if (SerparMatch(name, arg) == -1) 221 return -1; 222 #else 223 Unix_IsValidParallelDevice(name,&sername,&parname); 224 # ifdef DEBUG 225 printf("translated %s to serial %s and parallel %s\n", 226 name==0 ? "NULL" : name, 227 sername==0 ? "NULL" : sername, 228 parname==0 ? "NULL" : parname); 229 # endif 230 if (sername==NULL || parname==NULL) return -1; 231 #endif 232 233 user_options_set = FALSE; 234 235 /* interpret and store the arguments */ 236 if (arg != NULL) 237 { 238 unsigned int target_baud_rate; 239 240 target_baud_rate = (unsigned int)strtoul(arg, NULL, 10); 241 242 if (target_baud_rate > 0) 243 { 244 #ifdef DEBUG 245 printf("user selected baud rate %u\n", target_baud_rate); 246 #endif 247 process_baud_rate(target_baud_rate); 248 } 249 #ifdef DEBUG 250 else 251 printf("could not understand baud rate %s\n", arg); 252 #endif 253 } 254 255 #ifdef COMPILING_ON_WINDOWS 256 { 257 /* 258 * The serial port number is in name[0] followed by 259 * the parallel port number in name[1] 260 */ 261 262 int sport = name[0] - '0'; 263 int pport = name[1] - '0'; 264 265 if (OpenParallel(pport) != COM_OK) 266 return -1; 267 268 if (OpenSerial(sport, FALSE) != COM_OK) 269 { 270 CloseParallel(); 271 return -1; 272 } 273 } 274 #else 275 Unix_OpenParallel(parname); 276 Unix_OpenSerial(sername); 277 #endif 278 279 serpar_reset(); 280 281 #if defined(__unix) || defined(__CYGWIN__) 282 Unix_ioctlNonBlocking(); 283 #endif 284 285 Angel_RxEngineInit(&config, &rxstate); 286 287 return 0; 288 } 289 290 #ifdef COMPILING_ON_WINDOWS 291 static int SerparMatch(const char *name, const char *arg) 292 { 293 char sername[2]; 294 char parname[2]; 295 296 UNUSED(arg); 297 298 sername[0] = name[0]; 299 parname[0] = name[1]; 300 sername[1] = parname[1] = 0; 301 302 if (IsValidDevice(sername) == COM_DEVICENOTVALID || 303 IsValidDevice(parname) == COM_DEVICENOTVALID) 304 return -1; 305 else 306 return 0; 307 } 308 #else 309 static int SerparMatch(const char *portstring, const char *arg) 310 { 311 char *sername=NULL, *parname=NULL; 312 UNUSED(arg); 313 314 Unix_IsValidParallelDevice(portstring,&sername,&parname); 315 316 /* Match failed if either sername or parname are still NULL */ 317 if (sername==NULL || parname==NULL) return -1; 318 return 0; 319 } 320 #endif 321 322 static void SerparClose(void) 323 { 324 #ifdef COMPILING_ON_WINDOWS 325 CloseParallel(); 326 CloseSerial(); 327 #else 328 Unix_CloseParallel(); 329 Unix_CloseSerial(); 330 #endif 331 } 332 333 static int SerparRead(DriverCall *dc, bool block) 334 { 335 static unsigned char readbuf[MAXREADSIZE]; 336 static int rbindex = 0; 337 338 int nread; 339 int read_errno; 340 int c = 0; 341 re_status restatus; 342 int ret_code = -1; /* assume bad packet or error */ 343 344 /* 345 * we must not overflow buffer, and must start after 346 * the existing data 347 */ 348 #ifdef COMPILING_ON_WINDOWS 349 { 350 BOOL dummy = FALSE; 351 nread = BytesInRXBufferSerial(); 352 353 if (nread > MAXREADSIZE - rbindex) 354 nread = MAXREADSIZE - rbindex; 355 read_errno = ReadSerial(readbuf+rbindex, nread, &dummy); 356 if (pfnProgressCallback != NULL && read_errno == COM_OK) 357 { 358 progressInfo.nRead += nread; 359 (*pfnProgressCallback)(&progressInfo); 360 } 361 } 362 #else 363 nread = Unix_ReadSerial(readbuf+rbindex, MAXREADSIZE-rbindex, block); 364 read_errno = errno; 365 #endif 366 367 if ((nread > 0) || (rbindex > 0)) 368 { 369 #ifdef DO_TRACE 370 printf("[%d@%d] ", nread, rbindex); 371 #endif 372 373 if (nread > 0) 374 rbindex = rbindex + nread; 375 376 do 377 { 378 restatus = Angel_RxEngine(readbuf[c], &(dc->dc_packet), &rxstate); 379 380 #ifdef DO_TRACE 381 printf("<%02X ",readbuf[c]); 382 #endif 383 c++; 384 } while (c < rbindex && 385 ((restatus == RS_IN_PKT) || (restatus == RS_WAIT_PKT))); 386 387 #ifdef DO_TRACE 388 printf("\n"); 389 #endif 390 391 switch(restatus) 392 { 393 case RS_GOOD_PKT: 394 ret_code = 1; 395 /* fall through to: */ 396 397 case RS_BAD_PKT: 398 /* 399 * We now need to shuffle any left over data down to the 400 * beginning of our private buffer ready to be used 401 *for the next packet 402 */ 403 #ifdef DO_TRACE 404 printf("SerparRead() processed %d, moving down %d\n", 405 c, rbindex - c); 406 #endif 407 408 if (c != rbindex) 409 memmove((char *) readbuf, (char *) (readbuf + c), rbindex - c); 410 411 rbindex -= c; 412 413 break; 414 415 case RS_IN_PKT: 416 case RS_WAIT_PKT: 417 rbindex = 0; /* will have processed all we had */ 418 ret_code = 0; 419 break; 420 421 default: 422 #ifdef DEBUG 423 printf("Bad re_status in SerparRead()\n"); 424 #endif 425 break; 426 } 427 } 428 else if (nread == 0) 429 /* nothing to read */ 430 ret_code = 0; 431 else if (read_errno == ERRNO_FOR_BLOCKED_IO) /* nread < 0 */ 432 ret_code = 0; 433 434 #ifdef DEBUG 435 if ((nread < 0) && (read_errno != ERRNO_FOR_BLOCKED_IO)) 436 perror("read() error in SerparRead()"); 437 #endif 438 439 return ret_code; 440 } 441 442 /* 443 * Function: send_packet 444 * Purpose: Send a stream of bytes to Angel through the parallel port 445 * 446 * Algorithm: We need to present the data in a form that all boards can 447 * swallow. With the PID board, this is a problem: for reasons 448 * described in the driver (angel/pid/st16c552.c), data are 449 * sent a nybble at a time on D0-D2 and D4; D3 is wired to ACK, 450 * which generates an interrupt when it goes low. This routine 451 * fills in an array of nybbles, with ACK clear in all but the 452 * last one. If, for whatever reason, the write fails, then 453 * ACK is forced high (thereby enabling the next write a chance 454 * to be noticed when the falling edge of ACK generates an 455 * interrupt (hopefully). 456 * 457 * Params: 458 * Input: txstate Contains the packet to be sent 459 * 460 * Returns: Number of *complete* bytes written 461 */ 462 463 static int SerparWrite(DriverCall *dc) 464 { 465 te_status status; 466 int nwritten = 0; 467 static TxState txstate; 468 469 /* 470 * is this a new packet? 471 */ 472 if (dc->dc_context == NULL) 473 { 474 /* 475 * yes - initialise TxEngine 476 */ 477 Angel_TxEngineInit(&config, &dc->dc_packet, &txstate.state); 478 479 txstate.index = 0; 480 dc->dc_context = &txstate; 481 } 482 483 /* 484 * fill the buffer using the Tx Engine 485 */ 486 do 487 { 488 status = Angel_TxEngine(&dc->dc_packet, &txstate.state, 489 &txstate.writebuf[txstate.index]); 490 if (status != TS_IDLE) txstate.index++; 491 492 } while (status == TS_IN_PKT && txstate.index < MAXWRITESIZE); 493 494 #ifdef DO_TRACE 495 { 496 unsigned int i = 0; 497 498 while (i < txstate.index) 499 { 500 printf(">%02X ", txstate.writebuf[i]); 501 502 if (!(++i % 16)) 503 putc('\n', stdout); 504 } 505 506 if (i % 16) 507 putc('\n', stdout); 508 } 509 #endif 510 511 /* 512 * the data are ready, all we need now is to send them out 513 * in a form that Angel can swallow. 514 */ 515 #ifdef COMPILING_ON_WINDOWS 516 if (WriteParallel(txstate.writebuf, txstate.index) == COM_OK) 517 { 518 nwritten = txstate.index; 519 if (pfnProgressCallback != NULL) 520 { 521 progressInfo.nWritten += nwritten; 522 (*pfnProgressCallback)(&progressInfo); 523 } 524 } 525 else 526 { 527 MessageBox(GetFocus(), "Write error\n", "Angel", MB_OK | MB_ICONSTOP); 528 return -1; /* SJ - This really needs to return a value, which is picked up in */ 529 /* DevSW_Read as meaning stop debugger but don't kill. */ 530 } 531 #else 532 nwritten = Unix_WriteParallel(txstate.writebuf, txstate.index); 533 #endif 534 535 if (nwritten < 0) nwritten = 0; 536 537 #ifdef DO_TRACE 538 printf("SerparWrite: wrote %d out of %d bytes\n", 539 nwritten, txstate.index); 540 #endif 541 542 /* 543 * has the whole packet gone? 544 */ 545 if (nwritten == (int)txstate.index && 546 (status == TS_DONE_PKT || status == TS_IDLE)) 547 /* 548 * yes it has 549 */ 550 return 1; 551 else 552 { 553 /* 554 * if some data are left, shuffle them 555 * to the start of the buffer 556 */ 557 if (nwritten != (int)txstate.index && nwritten != 0) 558 { 559 txstate.index -= nwritten; 560 (void)memmove((char *) txstate.writebuf, 561 (char *) (txstate.writebuf + nwritten), 562 txstate.index); 563 } 564 else if (nwritten == (int)txstate.index) 565 txstate.index = 0; 566 567 return 0; 568 } 569 } 570 571 static int serpar_reset(void) 572 { 573 #ifdef COMPILING_ON_WINDOWS 574 FlushParallel(); 575 FlushSerial(); 576 #else 577 Unix_ResetParallel(); 578 Unix_ResetSerial(); 579 #endif 580 581 return serpar_set_params(&serpar_defaults); 582 } 583 584 static int find_baud_rate(unsigned int *speed) 585 { 586 static struct 587 { 588 unsigned int baud; 589 int termiosValue; 590 } possibleBaudRates[] = 591 { 592 #if defined(__hpux) 593 {115200, _B115200}, {57600, _B57600}, 594 #endif 595 #ifdef COMPILING_ON_WINDOWS 596 {38400, CBR_38400}, {19200, CBR_19200}, {9600, CBR_9600}, {0, 0} 597 #else 598 {38400, B38400}, {19200, B19200}, {9600, B9600}, {0, 0} 599 #endif 600 }; 601 unsigned int i; 602 603 /* look for lower or matching -- will always terminate at 0 end marker */ 604 for (i = 0; possibleBaudRates[i].baud > *speed; ++i) 605 /* do nothing */ 606 ; 607 608 if (possibleBaudRates[i].baud > 0) 609 *speed = possibleBaudRates[i].baud; 610 611 return possibleBaudRates[i].termiosValue; 612 } 613 614 static int serpar_set_params(const ParameterConfig *config) 615 { 616 unsigned int speed; 617 int termios_value; 618 619 #ifdef DEBUG 620 printf("serpar_set_params\n"); 621 #endif 622 623 if (!Angel_FindParam(AP_BAUD_RATE, config, &speed)) 624 { 625 #ifdef DEBUG 626 printf("speed not found in config\n"); 627 #endif 628 return DE_OKAY; 629 } 630 631 termios_value = find_baud_rate(&speed); 632 if (termios_value == 0) 633 { 634 #ifdef DEBUG 635 printf("speed not valid: %u\n", speed); 636 #endif 637 return DE_OKAY; 638 } 639 640 #ifdef DEBUG 641 printf("setting speed to %u\n", speed); 642 #endif 643 644 #ifdef COMPILING_ON_WINDOWS 645 SetBaudRate((WORD)termios_value); 646 #else 647 Unix_SetSerialBaudRate(termios_value); 648 #endif 649 650 return DE_OKAY; 651 } 652 653 654 static int serpar_get_user_params(ParameterOptions **p_options) 655 { 656 #ifdef DEBUG 657 printf("serpar_get_user_params\n"); 658 #endif 659 660 if (user_options_set) 661 { 662 *p_options = &user_options; 663 } 664 else 665 { 666 *p_options = NULL; 667 } 668 669 return DE_OKAY; 670 } 671 672 673 static int serial_get_default_params( const ParameterConfig **p_config ) 674 { 675 #ifdef DEBUG 676 printf( "serial_get_default_params\n" ); 677 #endif 678 679 *p_config = &serpar_defaults; 680 return DE_OKAY; 681 } 682 683 684 static int SerparIoctl(const int opcode, void *args) 685 { 686 int ret_code; 687 688 #ifdef DEBUG 689 printf("SerparIoctl: op %d arg %p\n", opcode, args ? args : "<NULL>"); 690 #endif 691 692 switch (opcode) 693 { 694 case DC_RESET: 695 ret_code = serpar_reset(); 696 break; 697 698 case DC_SET_PARAMS: 699 ret_code = serpar_set_params((const ParameterConfig *)args); 700 break; 701 702 case DC_GET_USER_PARAMS: 703 ret_code = serpar_get_user_params((ParameterOptions **)args); 704 break; 705 706 case DC_GET_DEFAULT_PARAMS: 707 ret_code = 708 serial_get_default_params((const ParameterConfig **)args); 709 break; 710 711 default: 712 ret_code = DE_BAD_OP; 713 break; 714 } 715 716 return ret_code; 717 } 718 719 DeviceDescr angel_SerparDevice = 720 { 721 "SERPAR", 722 SerparOpen, 723 SerparMatch, 724 SerparClose, 725 SerparRead, 726 SerparWrite, 727 SerparIoctl 728 }; 729 730 /* EOF serpardr.c */ 731