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>