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>