Annotation of embedaddon/ntp/ports/winnt/ntpd/win32_io.c, revision 1.1.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>