Annotation of embedaddon/ntp/ports/winnt/ntpd/win32_io.c, revision 1.1
1.1 ! misho 1: /* This file implements system calls that are not compatible with UNIX */
! 2:
! 3: #include <config.h>
! 4: #include <io.h>
! 5: #include <stdio.h>
! 6: #include "ntp_machine.h"
! 7: #include "ntp_stdlib.h"
! 8: #include "ntp_syslog.h"
! 9: #include "ntp_assert.h"
! 10: #include "ntp_debug.h"
! 11: #include "ntp_fp.h"
! 12: #include "ntp.h"
! 13: #include "ntp_refclock.h"
! 14: #include "win32_io.h"
! 15:
! 16: #define MAX_SERIAL 255 /* COM1: - COM255: */
! 17:
! 18:
! 19: /*
! 20: * common_serial_open ensures duplicate opens of the same port
! 21: * work by duplicating the handle for the 2nd open, allowing
! 22: * refclock_atom to share a GPS refclock's comm port.
! 23: */
! 24:
! 25: HANDLE common_serial_open(
! 26: char * dev,
! 27: char ** pwindev
! 28: )
! 29: {
! 30: static HANDLE * hnds = NULL; /* handle array */
! 31: static int c_hnd = 0; /* current array size */
! 32: static char windev[32]; /* return pointer into this */
! 33: HANDLE handle;
! 34: int unit;
! 35: int prev_c_hnd;
! 36: char * pch;
! 37:
! 38: /*
! 39: * This is odd, but we'll take any unix device path
! 40: * by looking for the initial '/' and strip off everything
! 41: * before the final digits, then translate that to COM__:
! 42: * maintaining backward compatibility with NTP practice of
! 43: * mapping unit 0 to the nonfunctional COM0:
! 44: *
! 45: * To ease the job of taking the windows COMx: device names
! 46: * out of reference clocks, we'll also work with those
! 47: * equanimously.
! 48: */
! 49:
! 50: DPRINTF(1, ("common_serial_open given %s\n", dev));
! 51:
! 52: pch = NULL;
! 53: if ('/' == dev[0]) {
! 54: pch = dev + strlen(dev) - 1;
! 55:
! 56: //DPRINTF(1, ("common_serial_open initial %s\n", pch));
! 57: if (isdigit(pch[0])) {
! 58: while (isdigit(pch[0])) {
! 59: pch--;
! 60: //DPRINTF(1, ("common_serial_open backed up to %s\n", pch));
! 61: }
! 62: pch++;
! 63: }
! 64: DPRINTF(1, ("common_serial_open skipped to ending digits leaving %s\n", pch));
! 65: } else if ('c' == tolower(dev[0])
! 66: && 'o' == tolower(dev[1])
! 67: && 'm' == tolower(dev[2])) {
! 68: pch = dev + 3;
! 69: DPRINTF(1, ("common_serial_open skipped COM leaving %s\n", pch));
! 70: }
! 71:
! 72: if (!pch || !isdigit(pch[0])) {
! 73: DPRINTF(1, ("not a digit: %s\n", pch ? pch : "[NULL]"));
! 74: return INVALID_HANDLE_VALUE;
! 75: }
! 76:
! 77: if (1 != sscanf(pch, "%d", &unit)
! 78: || unit > MAX_SERIAL
! 79: || unit < 0) {
! 80: DPRINTF(1, ("sscanf failure of %s\n", pch));
! 81: return INVALID_HANDLE_VALUE;
! 82: }
! 83:
! 84:
! 85: if (c_hnd < unit + 1) {
! 86: prev_c_hnd = c_hnd;
! 87: c_hnd = unit + 1;
! 88: /* round up to closest multiple of 4 to avoid churn */
! 89: c_hnd = (c_hnd + 3) & ~3;
! 90: hnds = erealloc(hnds, c_hnd * sizeof hnds[0]);
! 91: memset(&hnds[prev_c_hnd], 0,
! 92: (c_hnd - prev_c_hnd) * sizeof hnds[0]);
! 93: }
! 94:
! 95: if (NULL == hnds[unit]) {
! 96: snprintf(windev, sizeof(windev), "\\\\.\\COM%d", unit);
! 97: DPRINTF(1, ("windows device %s\n", windev));
! 98: *pwindev = windev;
! 99: hnds[unit] = CreateFile(
! 100: windev,
! 101: GENERIC_READ | GENERIC_WRITE,
! 102: 0, /* sharing prohibited */
! 103: NULL, /* default security */
! 104: OPEN_EXISTING,
! 105: FILE_ATTRIBUTE_NORMAL
! 106: | FILE_FLAG_OVERLAPPED,
! 107: NULL);
! 108: }
! 109:
! 110: if (INVALID_HANDLE_VALUE == hnds[unit]) {
! 111: hnds[unit] = NULL;
! 112: handle = INVALID_HANDLE_VALUE;
! 113: } else
! 114: DuplicateHandle(
! 115: GetCurrentProcess(),
! 116: hnds[unit],
! 117: GetCurrentProcess(),
! 118: &handle,
! 119: 0,
! 120: FALSE,
! 121: DUPLICATE_SAME_ACCESS
! 122: );
! 123:
! 124: return handle;
! 125: }
! 126:
! 127: /*
! 128: * tty_open - open serial port for refclock special uses
! 129: *
! 130: * This routine opens a serial port for and returns the
! 131: * file descriptor if success and -1 if failure.
! 132: */
! 133: int tty_open(
! 134: char *dev, /* device name pointer */
! 135: int access, /* O_RDWR */
! 136: int mode /* unused */
! 137: )
! 138: {
! 139: HANDLE Handle;
! 140: char * windev;
! 141:
! 142: /*
! 143: * open communication port handle
! 144: */
! 145: windev = NULL;
! 146: Handle = common_serial_open(dev, &windev);
! 147: windev = (windev) ? windev : dev;
! 148:
! 149: if (Handle == INVALID_HANDLE_VALUE) {
! 150: msyslog(LOG_ERR, "tty_open: device %s CreateFile error: %m", windev);
! 151: errno = EMFILE; /* lie, lacking conversion from GetLastError() */
! 152: return -1;
! 153: }
! 154:
! 155: return (int) _open_osfhandle((int)Handle, _O_TEXT);
! 156: }
! 157:
! 158: /*
! 159: * refclock_open - open serial port for reference clock
! 160: *
! 161: * This routine opens a serial port for I/O and sets default options. It
! 162: * returns the file descriptor or 0 indicating failure.
! 163: */
! 164: int refclock_open(
! 165: char * dev, /* device name pointer */
! 166: u_int speed, /* serial port speed (code) */
! 167: u_int flags /* line discipline flags */
! 168: )
! 169: {
! 170: char * windev;
! 171: HANDLE h;
! 172: COMMTIMEOUTS timeouts;
! 173: DCB dcb;
! 174: int fd;
! 175:
! 176: /*
! 177: * open communication port handle
! 178: */
! 179: windev = NULL;
! 180: h = common_serial_open(dev, &windev);
! 181: windev = (windev) ? windev : dev;
! 182:
! 183: if (INVALID_HANDLE_VALUE == h) {
! 184: msyslog(LOG_ERR, "Device %s CreateFile error: %m", windev);
! 185: return 0;
! 186: }
! 187:
! 188: /* Change the input/output buffers to be large. */
! 189: if (!SetupComm(h, 1024, 1024)) {
! 190: msyslog(LOG_ERR, "Device %s SetupComm error: %m", windev);
! 191: return 0;
! 192: }
! 193:
! 194: dcb.DCBlength = sizeof(dcb);
! 195:
! 196: if (!GetCommState(h, &dcb)) {
! 197: msyslog(LOG_ERR, "Device %s GetCommState error: %m",
! 198: windev);
! 199: return 0;
! 200: }
! 201:
! 202: switch (speed) {
! 203:
! 204: case B300:
! 205: dcb.BaudRate = 300;
! 206: break;
! 207:
! 208: case B1200:
! 209: dcb.BaudRate = 1200;
! 210: break;
! 211:
! 212: case B2400:
! 213: dcb.BaudRate = 2400;
! 214: break;
! 215:
! 216: case B4800:
! 217: dcb.BaudRate = 4800;
! 218: break;
! 219:
! 220: case B9600:
! 221: dcb.BaudRate = 9600;
! 222: break;
! 223:
! 224: case B19200:
! 225: dcb.BaudRate = 19200;
! 226: break;
! 227:
! 228: case B38400:
! 229: dcb.BaudRate = 38400;
! 230: break;
! 231:
! 232: case B57600:
! 233: dcb.BaudRate = 57600;
! 234: break;
! 235:
! 236: case B115200:
! 237: dcb.BaudRate = 115200;
! 238: break;
! 239:
! 240: default:
! 241: msyslog(LOG_ERR, "Device %s unsupported baud rate "
! 242: "code %u", windev, speed);
! 243: return 0;
! 244: }
! 245:
! 246:
! 247: dcb.fBinary = TRUE;
! 248: dcb.fParity = TRUE;
! 249: dcb.fOutxCtsFlow = 0;
! 250: dcb.fOutxDsrFlow = 0;
! 251: dcb.fDtrControl = DTR_CONTROL_DISABLE;
! 252: dcb.fDsrSensitivity = 0;
! 253: dcb.fTXContinueOnXoff = TRUE;
! 254: dcb.fOutX = 0;
! 255: dcb.fInX = 0;
! 256: dcb.fErrorChar = 0;
! 257: dcb.fNull = 0;
! 258: dcb.fRtsControl = RTS_CONTROL_DISABLE;
! 259: dcb.fAbortOnError = 0;
! 260: dcb.ByteSize = 8;
! 261: dcb.StopBits = ONESTOPBIT;
! 262: dcb.Parity = NOPARITY;
! 263: dcb.ErrorChar = 0;
! 264: dcb.EvtChar = 13; /* CR */
! 265: dcb.EofChar = 0;
! 266:
! 267: if (!SetCommState(h, &dcb)) {
! 268: msyslog(LOG_ERR, "Device %s SetCommState error: %m", windev);
! 269: return 0;
! 270: }
! 271:
! 272: /* watch out for CR (dcb.EvtChar) as well as the CD line */
! 273: if (!SetCommMask(h, EV_RXFLAG | EV_RLSD)) {
! 274: msyslog(LOG_ERR, "Device %s SetCommMask error: %m", windev);
! 275: return 0;
! 276: }
! 277:
! 278: /* configure the handle to never block */
! 279: timeouts.ReadIntervalTimeout = MAXDWORD;
! 280: timeouts.ReadTotalTimeoutMultiplier = 0;
! 281: timeouts.ReadTotalTimeoutConstant = 0;
! 282: timeouts.WriteTotalTimeoutMultiplier = 0;
! 283: timeouts.WriteTotalTimeoutConstant = 0;
! 284:
! 285: if (!SetCommTimeouts(h, &timeouts)) {
! 286: msyslog(LOG_ERR, "Device %s SetCommTimeouts error: %m", windev);
! 287: return 0;
! 288: }
! 289:
! 290: fd = _open_osfhandle((int)h, _O_TEXT);
! 291: if (fd < 0)
! 292: return 0;
! 293: NTP_INSIST(fd != 0);
! 294: return fd;
! 295: }
! 296:
! 297:
! 298: int
! 299: ioctl_tiocmget(
! 300: HANDLE h,
! 301: int *pi
! 302: )
! 303: {
! 304: DWORD dw;
! 305:
! 306: if (!GetCommModemStatus(h, &dw)) {
! 307: errno = ENOTTY;
! 308: return -1;
! 309: }
! 310:
! 311: *pi = ((dw & MS_CTS_ON) ? TIOCM_CTS : 0)
! 312: | ((dw & MS_DSR_ON) ? TIOCM_DSR : 0)
! 313: | ((dw & MS_RLSD_ON) ? TIOCM_CAR : 0)
! 314: | ((dw & MS_RING_ON) ? TIOCM_RI : 0);
! 315:
! 316: return 0;
! 317: }
! 318:
! 319:
! 320: int
! 321: ioctl_tiocmset(
! 322: HANDLE h,
! 323: int *pi
! 324: )
! 325: {
! 326: BOOL failed;
! 327: int result;
! 328:
! 329: failed = EscapeCommFunction(
! 330: h,
! 331: (*pi & TIOCM_RTS)
! 332: ? SETRTS
! 333: : CLRRTS
! 334: );
! 335:
! 336: if (!failed)
! 337: failed = EscapeCommFunction(
! 338: h,
! 339: (*pi & TIOCM_DTR)
! 340: ? SETDTR
! 341: : CLRDTR
! 342: );
! 343:
! 344: if (failed) {
! 345: errno = ENOTTY;
! 346: result = -1;
! 347: } else
! 348: result = 0;
! 349:
! 350: return result;
! 351: }
! 352:
! 353:
! 354: int
! 355: ioctl(
! 356: int fd,
! 357: int op,
! 358: int *pi
! 359: )
! 360: {
! 361: HANDLE h;
! 362: int result;
! 363:
! 364: h = (HANDLE)_get_osfhandle(fd);
! 365:
! 366: if (INVALID_HANDLE_VALUE == h) {
! 367: /* errno already set */
! 368: return -1;
! 369: }
! 370:
! 371: switch (op) {
! 372:
! 373: case TIOCMGET:
! 374: result = ioctl_tiocmget(h, pi);
! 375: break;
! 376:
! 377: case TIOCMSET:
! 378: result = ioctl_tiocmset(h, pi);
! 379: break;
! 380:
! 381: default:
! 382: errno = EINVAL;
! 383: result = -1;
! 384: }
! 385:
! 386: return result;
! 387: }
! 388:
! 389:
! 390: int
! 391: tcsetattr(
! 392: int fd,
! 393: int optional_actions,
! 394: const struct termios * tios
! 395: )
! 396: {
! 397: DCB dcb;
! 398: HANDLE h;
! 399:
! 400: UNUSED_ARG(optional_actions);
! 401:
! 402: h = (HANDLE)_get_osfhandle(fd);
! 403:
! 404: if (INVALID_HANDLE_VALUE == h) {
! 405: /* errno already set */
! 406: return -1;
! 407: }
! 408:
! 409: dcb.DCBlength = sizeof(dcb);
! 410: if (!GetCommState(h, &dcb)) {
! 411: errno = ENOTTY;
! 412: return -1;
! 413: }
! 414:
! 415: switch (max(tios->c_ospeed, tios->c_ispeed)) {
! 416:
! 417: case B300:
! 418: dcb.BaudRate = 300;
! 419: break;
! 420:
! 421: case B1200:
! 422: dcb.BaudRate = 1200;
! 423: break;
! 424:
! 425: case B2400:
! 426: dcb.BaudRate = 2400;
! 427: break;
! 428:
! 429: case B4800:
! 430: dcb.BaudRate = 4800;
! 431: break;
! 432:
! 433: case B9600:
! 434: dcb.BaudRate = 9600;
! 435: break;
! 436:
! 437: case B19200:
! 438: dcb.BaudRate = 19200;
! 439: break;
! 440:
! 441: case B38400:
! 442: dcb.BaudRate = 38400;
! 443: break;
! 444:
! 445: case B57600:
! 446: dcb.BaudRate = 57600;
! 447: break;
! 448:
! 449: case B115200:
! 450: dcb.BaudRate = 115200;
! 451: break;
! 452:
! 453: default:
! 454: msyslog(LOG_ERR, "unsupported serial baud rate");
! 455: errno = EINVAL;
! 456: return -1;
! 457: }
! 458:
! 459: switch (tios->c_cflag & CSIZE) {
! 460:
! 461: case CS5:
! 462: dcb.ByteSize = 5;
! 463: break;
! 464:
! 465: case CS6:
! 466: dcb.ByteSize = 6;
! 467: break;
! 468:
! 469: case CS7:
! 470: dcb.ByteSize = 7;
! 471: break;
! 472:
! 473: case CS8:
! 474: dcb.ByteSize = 8;
! 475: break;
! 476:
! 477: default:
! 478: msyslog(LOG_ERR, "unsupported serial word size");
! 479: errno = EINVAL;
! 480: return FALSE;
! 481: }
! 482:
! 483: if (PARENB & tios->c_cflag) {
! 484: dcb.fParity = TRUE;
! 485: dcb.Parity = (tios->c_cflag & PARODD)
! 486: ? ODDPARITY
! 487: : EVENPARITY;
! 488: } else {
! 489: dcb.fParity = FALSE;
! 490: dcb.Parity = NOPARITY;
! 491: }
! 492:
! 493: dcb.StopBits = (CSTOPB & tios->c_cflag)
! 494: ? TWOSTOPBITS
! 495: : ONESTOPBIT;
! 496:
! 497: if (!SetCommState(h, &dcb)) {
! 498: errno = ENOTTY;
! 499: return -1;
! 500: }
! 501:
! 502: return 0;
! 503: }
! 504:
! 505:
! 506: int
! 507: tcgetattr(
! 508: int fd,
! 509: struct termios *tios
! 510: )
! 511: {
! 512: DCB dcb;
! 513: HANDLE h;
! 514:
! 515: h = (HANDLE)_get_osfhandle(fd);
! 516:
! 517: if (INVALID_HANDLE_VALUE == h) {
! 518: /* errno already set */
! 519: return -1;
! 520: }
! 521:
! 522: dcb.DCBlength = sizeof(dcb);
! 523:
! 524: if (!GetCommState(h, &dcb)) {
! 525: errno = ENOTTY;
! 526: return -1;
! 527: }
! 528:
! 529: /* Set c_ispeed & c_ospeed */
! 530:
! 531: switch (dcb.BaudRate) {
! 532:
! 533: case 300:
! 534: tios->c_ispeed = tios->c_ospeed = B300;
! 535: break;
! 536:
! 537: case 1200:
! 538: tios->c_ispeed = tios->c_ospeed = B1200;
! 539: break;
! 540:
! 541: case 2400:
! 542: tios->c_ispeed = tios->c_ospeed = B2400;
! 543: break;
! 544:
! 545: case 4800:
! 546: tios->c_ispeed = tios->c_ospeed = B4800;
! 547: break;
! 548:
! 549: case 9600:
! 550: tios->c_ispeed = tios->c_ospeed = B9600;
! 551: break;
! 552:
! 553: case 19200:
! 554: tios->c_ispeed = tios->c_ospeed = B19200;
! 555: break;
! 556:
! 557: case 38400:
! 558: tios->c_ispeed = tios->c_ospeed = B38400;
! 559: break;
! 560:
! 561: case 57600:
! 562: tios->c_ispeed = tios->c_ospeed = B57600;
! 563: break;
! 564:
! 565: case 115200:
! 566: tios->c_ispeed = tios->c_ospeed = B115200;
! 567: break;
! 568:
! 569: default:
! 570: tios->c_ispeed = tios->c_ospeed = B9600;
! 571: }
! 572:
! 573:
! 574: switch (dcb.ByteSize) {
! 575: case 5:
! 576: tios->c_cflag = CS5;
! 577: break;
! 578:
! 579: case 6:
! 580: tios->c_cflag = CS6;
! 581: break;
! 582:
! 583: case 7:
! 584: tios->c_cflag = CS7;
! 585: break;
! 586:
! 587: case 8:
! 588: default:
! 589: tios->c_cflag = CS8;
! 590: }
! 591:
! 592: if (dcb.fParity) {
! 593: tios->c_cflag |= PARENB;
! 594:
! 595: if (ODDPARITY == dcb.Parity)
! 596: tios->c_cflag |= PARODD;
! 597: }
! 598:
! 599: if (TWOSTOPBITS == dcb.StopBits)
! 600: tios->c_cflag |= CSTOPB;
! 601:
! 602: tios->c_iflag = 0;
! 603: tios->c_lflag = 0;
! 604: tios->c_line = 0;
! 605: tios->c_oflag = 0;
! 606:
! 607: return 0;
! 608: }
! 609:
! 610:
! 611: int
! 612: tcflush(
! 613: int fd,
! 614: int mode
! 615: )
! 616: {
! 617: HANDLE h;
! 618: BOOL success;
! 619: DWORD flags;
! 620: int result;
! 621:
! 622: h = (HANDLE)_get_osfhandle(fd);
! 623:
! 624: if (INVALID_HANDLE_VALUE == h) {
! 625: /* errno already set */
! 626: return -1;
! 627: }
! 628:
! 629: switch (mode) {
! 630:
! 631: case TCIFLUSH:
! 632: flags = PURGE_RXCLEAR;
! 633: break;
! 634:
! 635: case TCOFLUSH:
! 636: flags = PURGE_TXABORT;
! 637: break;
! 638:
! 639: case TCIOFLUSH:
! 640: flags = PURGE_RXCLEAR | PURGE_TXABORT;
! 641: break;
! 642:
! 643: default:
! 644: errno = EINVAL;
! 645: return -1;
! 646: }
! 647:
! 648: success = PurgeComm(h, flags);
! 649:
! 650: if (success)
! 651: result = 0;
! 652: else {
! 653: errno = ENOTTY;
! 654: result = -1;
! 655: }
! 656:
! 657: return result;
! 658: }
! 659:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>