1 #ifdef HAVE_CONFIG_H
2 #include "hamlib/rig.h"
3 #include <config.h>
4 #endif
5 
6 #if defined(WIN32) && !defined(HAVE_TERMIOS_H)
7 
8 #undef DEBUG
9 #undef TRACE
10 
11 #ifdef DEBUG
12 #define DEBUG_VERBOSE
13 #define DEBUG_ERRORS
14 #define report(a) fprintf(stderr,a)
15 #define report_warning(a) fprintf(stderr,a)
16 #define report_error(a) fprintf(stderr,a)
17 #else
18 #define report(a) do {} while (0)
19 #define report_warning(a) do {} while (0)
20 #define report_error(a) do {} while (0)
21 #endif /* DEBUG */
22 /*-------------------------------------------------------------------------
23 |   rxtx is a native interface to serial ports in java.
24 |   Copyright 1997-2002 by Trent Jarvi taj@www.linux.org.uk.
25 |   Copyright 1997-2006 by Trent Jarvi taj@www.linux.org.uk.
26 |
27 |   This library is free software; you can redistribute it and/or
28 |   modify it under the terms of the GNU Lesser General Public
29 |   License as published by the Free Software Foundation; either
30 |   version 2.1 of the License, or (at your option) any later version.
31 |
32 |   If you compile this program with cygwin32 tools this package falls
33 |   under the GPL.  See COPYING.CYGNUS for details.
34 |
35 |   This library is distributed in the hope that it will be useful,
36 |   but WITHOUT ANY WARRANTY; without even the implied warranty of
37 |   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
38 |   Lesser General Public License for more details.
39 |
40 |   You should have received a copy of the GNU Lesser General Public
41 |   License along with this library; if not, write to the Free Software
42 |   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
43 |
44 | This file was taken from rxtx-2.1-7 and adapted for Hamlib.
45 --------------------------------------------------------------------------*/
46 #include <windows.h>
47 #include <stdio.h>
48 #include <errno.h>
49 #include <time.h>
50 #include <limits.h>
51 #include "win32termios.h"
52 
53 /*
54  * odd malloc.h error with lcc compiler
55  * winsock has FIONREAD with lcc
56  */
57 
58 #ifdef __LCC__
59 #   include <winsock.h>
60 #else
61 #   include <malloc.h>
62 #endif /* __LCC__ */
63 
64 #define SIGIO 0
65 
66 int my_errno;
67 #if 0
68 extern int errno;
69 #endif
70 struct termios_list
71 {
72     char filename[512];
73     int my_errno;
74     int interrupt;
75     int event_flag;
76     int tx_happened;
77     unsigned long *hComm;
78     struct termios *ttyset;
79     struct serial_struct *sstruct;
80     /* for DTR DSR */
81     unsigned char MSR;
82     struct async_struct *astruct;
83     struct serial_icounter_struct *sis;
84     int open_flags;
85     OVERLAPPED rol;
86     OVERLAPPED wol;
87     OVERLAPPED sol;
88     int fd;
89     struct termios_list *next;
90     struct termios_list *prev;
91 };
92 struct termios_list *first_tl = NULL;
93 
94 static struct termios_list *find_port(int);
95 
96 /*----------------------------------------------------------
97 serial_test
98 
99    accept: filename to test
100    perform:
101    return:      1 on success 0 on failure
102    exceptions:
103    win32api:    CreateFile CloseHandle
104    comments:    if the file opens it should be ok.
105 ----------------------------------------------------------*/
win32_serial_test(char * filename)106 int win32_serial_test(char *filename)
107 {
108     unsigned long *hcomm;
109     int ret;
110     hcomm = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
111                        0, 0);
112 
113     if (hcomm == INVALID_HANDLE_VALUE)
114     {
115         if (GetLastError() == ERROR_ACCESS_DENIED)
116         {
117             ret = 1;
118         }
119         else
120         {
121             ret = 0;
122         }
123     }
124     else
125     {
126         ret = 1;
127     }
128 
129     CloseHandle(hcomm);
130     return (ret);
131 }
132 
termios_setflags(int fd,int termios_flags[])133 static void termios_setflags(int fd, int termios_flags[])
134 {
135     struct termios_list *index = find_port(fd);
136     int i, result;
137     int windows_flags[11] = { 0, EV_RXCHAR, EV_TXEMPTY, EV_CTS, EV_DSR,
138                               EV_RING | 0x2000, EV_RLSD, EV_ERR,
139                               EV_ERR, EV_ERR, EV_BREAK
140                             };
141 
142     if (!index)
143     {
144         LEAVE("termios_setflags");
145         return;
146     }
147 
148     index->event_flag = 0;
149 
150     for (i = 0; i < 11; i++)
151         if (termios_flags[i])
152         {
153             index->event_flag |= windows_flags[i];
154         }
155 
156     result = SetCommMask(index->hComm, index->event_flag);
157 
158     /*
159        This is rank.  0x2000 was used to detect the trailing edge of ring.
160        The leading edge is detedted by EV_RING.
161 
162        The trailing edge is reliable.  The leading edge is not.
163        Softie no longer allows the trailing edge to be detected in NTsp2
164        and beyond.
165 
166        So... Try the reliable option above and if it fails, use the less
167        reliable means.
168 
169        The screams for a giveio solution that bypasses the kernel.
170     */
171     if (index->event_flag & 0x2000 && result == 0)
172     {
173         index->event_flag &= ~0x2000;
174         SetCommMask(index->hComm, index->event_flag);
175     }
176 }
177 
178 #if 0
179 /*----------------------------------------------------------
180 get_fd()
181 
182    accept:      filename
183    perform:     find the file descriptor associated with the filename
184    return:      fd
185    exceptions:
186    win32api:    None
187    comments:    This is not currently called by anything
188 ----------------------------------------------------------*/
189 
190 int get_fd(char *filename)
191 {
192     struct termios_list *index = first_tl;
193 
194     ENTER("get_fd");
195 
196     if (!index)
197     {
198         return -1;
199     }
200 
201     while (strcmp(index->filename, filename))
202     {
203         index = index->next;
204 
205         if (!index->next)
206         {
207             return (-1);
208         }
209     }
210 
211     LEAVE("get_fd");
212     return (index->fd);
213 }
214 
215 /*----------------------------------------------------------
216 get_filename()
217 
218    accept:      file descriptor
219    perform:     find the filename associated with the file descriptor
220    return:      the filename associated with the fd
221    exceptions:  None
222    win32api:    None
223    comments:    This is not currently called by anything
224 ----------------------------------------------------------*/
225 
226 char *get_filename(int fd)
227 {
228     struct termios_list *index = first_tl;
229 
230     ENTER("get_filename");
231 
232     if (!index)
233     {
234         return ("bad");
235     }
236 
237     while (index->fd != fd)
238     {
239         if (index->next == NULL)
240         {
241             return ("bad");
242         }
243 
244         index = index->next;
245     }
246 
247     LEAVE("get_filename");
248     return (index->filename);
249 }
250 
251 /*----------------------------------------------------------
252 dump_termios_list()
253 
254    accept:      string to print out.
255    perform:
256    return:
257    exceptions:
258    win32api:    None
259    comments:    used only for debugging eg serial_close()
260 ----------------------------------------------------------*/
261 
262 void dump_termios_list(char *foo)
263 {
264 #ifdef DEBUG
265     struct termios_list *index = first_tl;
266     printf("============== %s start ===============\n", foo);
267 
268     if (index)
269     {
270         printf("%i filename | %s\n", index->fd, index->filename);
271     }
272 
273     /*
274         if ( index->next )
275         {
276             printf( "%i filename | %s\n", index->fd, index->filename );
277         }
278     */
279     printf("============== %s end  ===============\n", foo);
280 #endif
281 }
282 #endif
283 
284 /*----------------------------------------------------------
285 set_errno()
286 
287    accept:
288    perform:
289    return:
290    exceptions:
291    win32api:    None
292    comments:   FIXME
293 ----------------------------------------------------------*/
294 
set_errno(int error)295 static void set_errno(int error)
296 {
297     my_errno = error;
298 }
299 
300 #if 0
301 /*----------------------------------------------------------
302 usleep()
303 
304    accept:
305    perform:
306    return:
307    exceptions:
308    win32api:    Sleep()
309    comments:
310 ----------------------------------------------------------*/
311 
312 static void usleep(unsigned long usec)
313 {
314     Sleep(usec / 1000);
315 }
316 #endif
317 
318 /*----------------------------------------------------------
319 CBR_toB()
320 
321    accept:
322    perform:
323    return:
324    exceptions:
325    win32api:     None
326    comments:
327 ----------------------------------------------------------*/
328 
CBR_to_B(int Baud)329 static int CBR_to_B(int Baud)
330 {
331     ENTER("CBR_to_B");
332 
333     switch (Baud)
334     {
335 
336     case 0:         return (B0);
337 
338     case 50:        return (B50);
339 
340     case 75:        return (B75);
341 
342     case CBR_110:       return (B110);
343 
344     case 134:       return (B134);
345 
346     case 150:       return (B150);
347 
348     case 200:       return (B200);
349 
350     case CBR_300:       return (B300);
351 
352     case CBR_600:       return (B600);
353 
354     case CBR_1200:      return (B1200);
355 
356     case 1800:      return (B1800);
357 
358     case CBR_2400:      return (B2400);
359 
360     case CBR_4800:      return (B4800);
361 
362     case CBR_9600:      return (B9600);
363 
364     case CBR_14400:     return (B14400);
365 
366     case CBR_19200:     return (B19200);
367 
368     case CBR_28800:     return (B28800);
369 
370     case CBR_38400:     return (B38400);
371 
372     case CBR_57600:     return (B57600);
373 
374     case CBR_115200:    return (B115200);
375 
376     case CBR_128000:    return (B128000);
377 
378     case CBR_230400:    return (B230400);
379 
380     case CBR_256000:    return (B256000);
381 
382     case CBR_460800:    return (B460800);
383 
384     case CBR_500000:    return (B500000);
385 
386     case CBR_576000:    return (B576000);
387 
388     case CBR_921600:    return (B921600);
389 
390     case CBR_1000000:   return (B1000000);
391 
392     case CBR_1152000:   return (B1152000);
393 
394     case CBR_1500000:   return (B1500000);
395 
396     case CBR_2000000:   return (B2000000);
397 
398     case CBR_2500000:   return (B2500000);
399 
400     case CBR_3000000:   return (B3000000);
401 
402     case CBR_3500000:   return (B3500000);
403 
404     case CBR_4000000:   return (B4000000);
405 
406     default:
407         /* assume custom baudrate */
408         return (Baud);
409     }
410 }
411 
412 /*----------------------------------------------------------
413 B_to_CBR()
414 
415    accept:
416    perform:
417    return:
418    exceptions:
419    win32api:
420    comments:      None
421 ----------------------------------------------------------*/
422 
B_to_CBR(int Baud)423 static int B_to_CBR(int Baud)
424 {
425     int ret;
426     ENTER("B_to_CBR");
427 
428     switch (Baud)
429     {
430     case 0:     ret = 0;        break;
431 
432     case B50:   ret = 50;       break;
433 
434     case B75:   ret = 75;       break;
435 
436     case B110:  ret = CBR_110;      break;
437 
438     case B134:  ret = 134;      break;
439 
440     case B150:  ret = 150;      break;
441 
442     case B200:  ret = 200;      break;
443 
444     case B300:  ret = CBR_300;      break;
445 
446     case B600:  ret = CBR_600;      break;
447 
448     case B1200: ret = CBR_1200;     break;
449 
450     case B1800: ret = 1800;     break;
451 
452     case B2400: ret = CBR_2400;     break;
453 
454     case B4800: ret = CBR_4800;     break;
455 
456     case B9600: ret = CBR_9600;     break;
457 
458     case B14400:    ret = CBR_14400;    break;
459 
460     case B19200:    ret = CBR_19200;    break;
461 
462     case B28800:    ret = CBR_28800;    break;
463 
464     case B38400:    ret = CBR_38400;    break;
465 
466     case B57600:    ret = CBR_57600;    break;
467 
468     case B115200:   ret = CBR_115200;   break;
469 
470     case B128000:   ret = CBR_128000;   break;
471 
472     case B230400:   ret = CBR_230400;   break;
473 
474     case B256000:   ret = CBR_256000;   break;
475 
476     case B460800:   ret = CBR_460800;   break;
477 
478     case B500000:   ret = CBR_500000;   break;
479 
480     case B576000:   ret = CBR_576000;   break;
481 
482     case B921600:   ret = CBR_921600;   break;
483 
484     case B1000000:  ret = CBR_1000000;  break;
485 
486     case B1152000:  ret = CBR_1152000;  break;
487 
488     case B1500000:  ret = CBR_1500000;  break;
489 
490     case B2000000:  ret = CBR_2000000;  break;
491 
492     case B2500000:  ret = CBR_2500000;  break;
493 
494     case B3000000:  ret = CBR_3000000;  break;
495 
496     case B3500000:  ret = CBR_3500000;  break;
497 
498     case B4000000:  ret = CBR_4000000;  break;
499 
500     default:
501         /* assume custom baudrate */
502         return Baud;
503     }
504 
505     LEAVE("B_to_CBR");
506     return ret;
507 }
508 
509 /*----------------------------------------------------------
510 bytesize_to_termios()
511 
512    accept:
513    perform:
514    return:
515    exceptions:
516    win32api:      None
517    comments:
518 ----------------------------------------------------------*/
519 
bytesize_to_termios(int ByteSize)520 static int bytesize_to_termios(int ByteSize)
521 {
522     ENTER("bytesize_to_termios");
523 
524     switch (ByteSize)
525     {
526     case 5: return (CS5);
527 
528     case 6: return (CS6);
529 
530     case 7: return (CS7);
531 
532     case 8:
533     default: return (CS8);
534     }
535 }
536 
537 /*----------------------------------------------------------
538 termios_to_bytesize()
539 
540    accept:
541    perform:
542    return:
543    exceptions:
544    win32api:     None
545    comments:
546 ----------------------------------------------------------*/
547 
termios_to_bytesize(int cflag)548 static int termios_to_bytesize(int cflag)
549 {
550     ENTER("termios_to_bytesize");
551 
552     switch (cflag & CSIZE)
553     {
554     case CS5: return (5);
555 
556     case CS6: return (6);
557 
558     case CS7: return (7);
559 
560     case CS8:
561     default: return (8);
562     }
563 }
564 
565 #if 0
566 /*----------------------------------------------------------
567 get_dos_port()
568 
569    accept:
570    perform:
571    return:
572    exceptions:
573    win32api:     None
574    comments:
575 ----------------------------------------------------------*/
576 
577 static const char *get_dos_port(char const *name)
578 {
579     ENTER("get_dos_port");
580 
581     if (!strcmp(name, "/dev/cua0")) { return ("COM1"); }
582 
583     if (!strcmp(name, "/dev/cua1")) { return ("COM2"); }
584 
585     if (!strcmp(name, "/dev/cua2")) { return ("COM3"); }
586 
587     if (!strcmp(name, "/dev/cua3")) { return ("COM4"); }
588 
589     LEAVE("get_dos_port");
590     return ((const char *) name);
591 }
592 #endif
593 
594 /*----------------------------------------------------------
595 ClearErrors()
596 
597    accept:
598    perform:      keep track of errors for the eventLoop() (SerialImp.c)
599    return:       the return value of ClearCommError()
600    exceptions:
601    win32api:     ClearCommError()
602    comments:
603 ----------------------------------------------------------*/
604 
ClearErrors(struct termios_list * index,COMSTAT * Stat)605 static int ClearErrors(struct termios_list *index, COMSTAT *Stat)
606 {
607     unsigned long ErrCode;
608     int ret;
609 
610     ret = ClearCommError(index->hComm, &ErrCode, Stat);
611 
612     if (ret == 0)
613     {
614         YACK();
615         return (ret);
616     }
617 
618 #ifdef DEBUG_ERRORS
619 
620     if (ErrCode)
621     {
622         printf("%i frame %i %i overrun %li %i  parity %u %i brk %i %i\n",
623                (int) ErrCode,
624                (int) ErrCode & CE_FRAME,
625                index->sis->frame,
626                (int)(ErrCode & CE_OVERRUN) | (ErrCode & CE_RXOVER),
627                index->sis->overrun,
628                (int) ErrCode & CE_RXPARITY,
629                index->sis->parity,
630                (int) ErrCode & CE_BREAK,
631                index->sis->brk
632               );
633     }
634 
635 #endif /* DEBUG_ERRORS */
636 
637     if (ErrCode & CE_FRAME)
638     {
639         index->sis->frame++;
640         ErrCode &= ~CE_FRAME;
641     }
642 
643 #ifdef LIFE_IS_GOOD
644     FIXME OVERRUN is spewing
645 
646     if (ErrCode & CE_OVERRUN)
647     {
648         index->sis->overrun++;
649         ErrCode &= ~CE_OVERRUN;
650     }
651     /* should this be here? */
652     else if (ErrCode & CE_RXOVER)
653     {
654         index->sis->overrun++;
655         ErrCode &= ~CE_OVERRUN;
656     }
657 
658 #endif /* LIFE_IS_GOOD */
659 
660     if (ErrCode & CE_RXPARITY)
661     {
662         index->sis->parity++;
663         ErrCode &= ~CE_RXPARITY;
664     }
665 
666     if (ErrCode & CE_BREAK)
667     {
668         index->sis->brk++;
669         ErrCode &= ~CE_BREAK;
670     }
671 
672     return (ret);
673 }
674 
675 #if 0
676 /*----------------------------------------------------------
677 FillDCB()
678 
679    accept:
680    perform:
681    return:
682    exceptions:
683    win32api:     GetCommState(),  SetCommState(), SetCommTimeouts()
684    comments:
685 ----------------------------------------------------------*/
686 
687 static BOOL FillDCB(DCB *dcb, unsigned long *hCommPort, COMMTIMEOUTS Timeout)
688 {
689 
690     ENTER("FillDCB");
691     dcb->DCBlength = sizeof(dcb);
692 
693     if (!GetCommState(hCommPort, dcb))
694     {
695         report("GetCommState\n");
696         return (-1);
697     }
698 
699     dcb->BaudRate        = CBR_9600 ;
700     dcb->ByteSize        = 8;
701     dcb->Parity          = NOPARITY;
702     dcb->StopBits        = ONESTOPBIT;
703     dcb->fDtrControl     = DTR_CONTROL_ENABLE;
704     dcb->fRtsControl     = RTS_CONTROL_ENABLE;
705     dcb->fOutxCtsFlow    = FALSE;
706     dcb->fOutxDsrFlow    = FALSE;
707     dcb->fDsrSensitivity = FALSE;
708     dcb->fOutX           = FALSE;
709     dcb->fInX            = FALSE;
710     dcb->fTXContinueOnXoff = FALSE;
711     dcb->XonChar         = 0x11;
712     dcb->XoffChar        = 0x13;
713     dcb->XonLim          = 0;
714     dcb->XoffLim         = 0;
715     dcb->fParity = TRUE;
716 
717     if (EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | (EV_RLSD & EV_RXFLAG))
718     {
719         dcb->EvtChar = '\n';
720     }
721     else { dcb->EvtChar = '\0'; }
722 
723     if (!SetCommState(hCommPort, dcb))
724     {
725         report("SetCommState\n");
726         YACK();
727         return (-1);
728     }
729 
730     if (!SetCommTimeouts(hCommPort, &Timeout))
731     {
732         YACK();
733         report("SetCommTimeouts\n");
734         return (-1);
735     }
736 
737     LEAVE("FillDCB");
738     return (TRUE) ;
739 }
740 #endif
741 
742 /*----------------------------------------------------------
743 serial_close()
744 
745    accept:
746    perform:
747    return:
748    exceptions:
749    win32api:      SetCommMask(), CloseHandle()
750    comments:
751 ----------------------------------------------------------*/
752 
win32_serial_close(int fd)753 int win32_serial_close(int fd)
754 {
755     struct termios_list *index;
756     /* char message[80]; */
757 
758     ENTER("serial_close");
759 
760     if (!first_tl || !first_tl->hComm)
761     {
762         report("gotit!");
763         return (0);
764     }
765 
766     index = find_port(fd);
767 
768     if (!index)
769     {
770         LEAVE("serial_close");
771         return -1;
772     }
773 
774     /* WaitForSingleObject( index->wol.hEvent, INFINITE ); */
775     /*
776         if ( index->hComm != INVALID_HANDLE_VALUE )
777         {
778             if ( !SetCommMask( index->hComm, EV_RXCHAR ) )
779             {
780                 YACK();
781                 report( "eventLoop hung\n" );
782             }
783             CloseHandle( index->hComm );
784         }
785         else
786         {
787             sprintf( message, "serial_ close():  Invalid Port Reference for %s\n",
788                 index->filename );
789             report( message );
790         }
791     */
792     if (index->next  && index->prev)
793     {
794         index->next->prev = index->prev;
795         index->prev->next = index->next;
796     }
797     else if (index->prev)
798     {
799         index->prev->next = NULL;
800     }
801     else if (index->next)
802     {
803         index->next->prev = NULL;
804         first_tl = index->next;
805     }
806     else
807     {
808         first_tl = NULL;
809     }
810 
811     if (index->rol.hEvent) { CloseHandle(index->rol.hEvent); }
812 
813     if (index->wol.hEvent) { CloseHandle(index->wol.hEvent); }
814 
815     if (index->sol.hEvent) { CloseHandle(index->sol.hEvent); }
816 
817     if (index->hComm) { CloseHandle(index->hComm); }
818 
819     if (index->ttyset) { free(index->ttyset); }
820 
821     if (index->astruct) { free(index->astruct); }
822 
823     if (index->sstruct) { free(index->sstruct); }
824 
825     if (index->sis) { free(index->sis); }
826 
827     /* had problems with strdup
828     if ( index->filename ) free( index->filename );
829     */
830     free(index);
831 
832 
833     LEAVE("serial_close");
834     return 0;
835 }
836 
837 /*----------------------------------------------------------
838 cfmakeraw()
839 
840    accept:
841    perform:
842    return:
843    exceptions:
844    win32api:     None
845    comments:
846 ----------------------------------------------------------*/
847 
cfmakeraw(struct termios * s_termios)848 void cfmakeraw(struct termios *s_termios)
849 {
850     ENTER("cfmakeraw");
851     s_termios->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
852                             | INLCR | IGNCR | ICRNL | IXON);
853     s_termios->c_oflag &= ~OPOST;
854     s_termios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
855     s_termios->c_cflag &= ~(CSIZE | PARENB);
856     s_termios->c_cflag |= CS8;
857     LEAVE("cfmakeraw");
858 }
859 
860 /*----------------------------------------------------------
861 init_serial_struct()
862 
863    accept:
864    perform:
865    return:
866    exceptions:
867    win32api:
868    comments:
869 ----------------------------------------------------------*/
870 
init_serial_struct(struct serial_struct * sstruct)871 static BOOL init_serial_struct(struct serial_struct *sstruct)
872 {
873     ENTER("init_serial_struct");
874 
875     /*
876     FIXME
877 
878     This needs to use inb() to read the actual baud_base
879     and divisor from the UART registers.  Question is how
880     far do we take this?
881 
882     */
883 
884     sstruct->custom_divisor = 0;
885     sstruct->baud_base = 115200;
886 
887     /* not currently used check values before using */
888 
889     /* unsigned short */
890 
891     sstruct->close_delay = 0;
892     sstruct->closing_wait = 0;
893     sstruct->iomem_reg_shift = 0;
894 
895     /* int */
896 
897     sstruct->type = 0;
898     sstruct->line = 0;
899     sstruct->irq = 0;
900     sstruct->flags = 0;
901     sstruct->xmit_fifo_size = 0;
902     sstruct->hub6 = 0;
903 
904     /* unsigned int */
905 
906     sstruct->port = 0;
907     sstruct->port_high = 0;
908 
909     /* char */
910 
911     sstruct->io_type = 0;
912 
913     /* unsigned char * */
914 
915     sstruct->iomem_base = NULL;
916 
917     LEAVE("init_serial_struct");
918     return TRUE;
919 
920 }
921 /*----------------------------------------------------------
922 init_termios()
923 
924    accept:
925    perform:
926    return:
927    exceptions:
928    win32api:
929    comments:
930 ----------------------------------------------------------*/
931 
init_termios(struct termios * ttyset)932 static BOOL init_termios(struct termios *ttyset)
933 {
934     ENTER("init_termios");
935 
936     if (!ttyset)
937     {
938         return FALSE;
939     }
940 
941     memset(ttyset, 0, sizeof(struct termios));
942     cfsetospeed(ttyset, B9600);
943     cfmakeraw(ttyset);
944     ttyset->c_cc[VINTR] = 0x03; /* 0: C-c */
945     ttyset->c_cc[VQUIT] = 0x1c; /* 1: C-\ */
946     ttyset->c_cc[VERASE] = 0x7f;    /* 2: <del> */
947     ttyset->c_cc[VKILL] = 0x15; /* 3: C-u */
948     ttyset->c_cc[VEOF] = 0x04;  /* 4: C-d */
949     ttyset->c_cc[VTIME] = 0;    /* 5: read timeout */
950     ttyset->c_cc[VMIN] = 1;     /* 6: read returns after this
951                         many bytes */
952     ttyset->c_cc[VSUSP] = 0x1a; /* 10: C-z */
953     ttyset->c_cc[VEOL] = '\r';  /* 11: */
954     ttyset->c_cc[VREPRINT] = 0x12;  /* 12: C-r */
955     /*
956         ttyset->c_cc[VDISCARD] = 0x;       13: IEXTEN only
957     */
958     ttyset->c_cc[VWERASE] = 0x17;   /* 14: C-w */
959     ttyset->c_cc[VLNEXT] = 0x16;    /* 15: C-w */
960     ttyset->c_cc[VEOL2] = '\n'; /* 16: */
961     LEAVE("init_termios");
962     return TRUE;
963     /* default VTIME = 0, VMIN = 1: read blocks forever until one byte */
964 }
965 
966 /*----------------------------------------------------------
967 port_opened()
968 
969    accept:
970    perform:
971    return:
972    exceptions:
973    win32api:     None
974    comments:
975 ----------------------------------------------------------*/
976 
port_opened(const char * filename)977 static int port_opened(const char *filename)
978 {
979     struct termios_list *index = first_tl;
980 
981     ENTER("port_opened");
982 
983     if (! index)
984     {
985         return 0;
986     }
987 
988     if (!strcmp(index->filename, filename))
989     {
990         return index->fd;
991     }
992 
993     while (index->next)
994     {
995         index = index->next;
996 
997         if (!strcmp(index->filename, filename))
998         {
999             return index->fd;
1000         }
1001     }
1002 
1003     LEAVE("port_opened");
1004     return 0;
1005 }
1006 
1007 /*----------------------------------------------------------
1008 open_port()
1009 
1010    accept:
1011    perform:
1012    return:
1013    exceptions:
1014    win32api:   CreateFile(), SetupComm(), CreateEvent()
1015    comments:
1016     FILE_FLAG_OVERLAPPED allows one to break out the select()
1017     so RXTXPort.close() does not hang.
1018 
1019     The setDTR() and setDSR() are the functions that noticed
1020     to be blocked in the java close.  Basically ioctl(TIOCM[GS]ET)
1021     are where it hangs.
1022 
1023     FILE_FLAG_OVERLAPPED also means we need to create valid OVERLAPPED
1024     structure in Serial_select.
1025 ----------------------------------------------------------*/
1026 
open_port(struct termios_list * port)1027 static int open_port(struct termios_list *port)
1028 {
1029     ENTER("open_port");
1030     port->hComm = CreateFile(port->filename,
1031                              GENERIC_READ | GENERIC_WRITE,
1032                              0,
1033                              0,
1034                              OPEN_EXISTING,
1035                              FILE_FLAG_OVERLAPPED,
1036                              0
1037                             );
1038 
1039     if (port->hComm == INVALID_HANDLE_VALUE)
1040     {
1041         YACK();
1042         set_errno(EINVAL);
1043         /*
1044                 printf( "serial_open failed %s\n", port->filename );
1045         */
1046         return -1;
1047     }
1048 
1049     if (!SetupComm(port->hComm, 2048, 1024))
1050     {
1051         YACK();
1052         return -1;
1053     }
1054 
1055     memset(&port->rol, 0, sizeof(OVERLAPPED));
1056     memset(&port->wol, 0, sizeof(OVERLAPPED));
1057     memset(&port->sol, 0, sizeof(OVERLAPPED));
1058 
1059     port->rol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1060 
1061     if (!port->rol.hEvent)
1062     {
1063         YACK();
1064         report("Could not create read overlapped\n");
1065         goto fail;
1066     }
1067 
1068     port->sol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1069 
1070     if (!port->sol.hEvent)
1071     {
1072         YACK();
1073         report("Could not create select overlapped\n");
1074         goto fail;
1075     }
1076 
1077     port->wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1078 
1079     if (!port->wol.hEvent)
1080     {
1081         YACK();
1082         report("Could not create write overlapped\n");
1083         goto fail;
1084     }
1085 
1086     LEAVE("open_port");
1087     return (0);
1088 fail:
1089     return (-1);
1090 }
1091 
1092 /*----------------------------------------------------------
1093 termios_list()
1094 
1095    accept:       fd which is a fake # for the port assigned when the port
1096          is opened
1097    perform:      walk through a double linked list to see if the given
1098          fd is in any of the termios_list members.
1099    return:       the termios_list if it is found.
1100          NULL if no matches are found.
1101    exceptions:   None
1102    win32api:     None
1103    comments:
1104 ----------------------------------------------------------*/
1105 
find_port(int fd)1106 static struct termios_list *find_port(int fd)
1107 {
1108 
1109     char message[80];
1110     struct termios_list *index = first_tl;
1111 
1112     ENTER("find_port");
1113 
1114     if (fd <= 0 || !first_tl) { goto fail; }
1115 
1116     while (index->fd)
1117     {
1118         if (index->fd == fd)
1119         {
1120             LEAVE("find_port");
1121             return index;
1122         }
1123 
1124         if (!index->next)
1125         {
1126             break;
1127         }
1128 
1129         index = index->next;
1130     }
1131 
1132 fail:
1133     sprintf(message, "No info known about the port. %i\n", fd);
1134     report(message);
1135     set_errno(EBADF);
1136     LEAVE("find_port");
1137     return NULL;
1138 }
1139 
1140 /*----------------------------------------------------------
1141 get_free_fd()
1142 
1143    accept:
1144    perform:
1145    return:
1146    exceptions:
1147    win32api:       None
1148    comments:
1149 ----------------------------------------------------------*/
1150 
get_free_fd()1151 static int get_free_fd()
1152 {
1153     int next, last;
1154     struct termios_list *index = first_tl;
1155 
1156     ENTER("get_free_fd");
1157 
1158     if (!index)
1159     {
1160         return (1);
1161     }
1162 
1163     if (!index->fd)
1164     {
1165         report("!index->fd\n");
1166         return (1);
1167     }
1168 
1169     if (index->fd > 1)
1170     {
1171         first_tl = index;
1172         return (1);
1173     }
1174 
1175     last = index->fd;
1176 
1177     while (index->next)
1178     {
1179         next = index->next->fd;
1180 
1181         if (next !=  last + 1)
1182         {
1183             return (last + 1);
1184 
1185         }
1186 
1187         index = index->next;
1188         last = next;
1189     }
1190 
1191     LEAVE("get_free_fd");
1192     return (index->fd + 1);
1193 }
1194 
1195 /*----------------------------------------------------------
1196 add_port()
1197 
1198    accept:
1199    perform:
1200    return:
1201    exceptions:
1202    win32api:      None
1203    comments:
1204 ----------------------------------------------------------*/
1205 
add_port(const char * filename)1206 static struct termios_list *add_port(const char *filename)
1207 {
1208     struct termios_list *index = first_tl;
1209     struct termios_list *port;
1210 
1211     ENTER("add_port");
1212 
1213     port = malloc(sizeof(struct termios_list));
1214 
1215     if (!port)
1216     {
1217         goto fail;
1218     }
1219 
1220     memset(port, 0, sizeof(struct termios_list));
1221 
1222     port->ttyset = malloc(sizeof(struct termios));
1223 
1224     if (! port->ttyset)
1225     {
1226         goto fail;
1227     }
1228 
1229     memset(port->ttyset, 0, sizeof(struct termios));
1230 
1231     port->sstruct = malloc(sizeof(struct serial_struct));
1232 
1233     if (! port->sstruct)
1234     {
1235         goto fail;
1236     }
1237 
1238     memset(port->sstruct, 0, sizeof(struct serial_struct));
1239     port->sis = malloc(sizeof(struct serial_icounter_struct));
1240 
1241     if (! port->sis)
1242     {
1243         goto fail;
1244     }
1245 
1246     memset(port->sis, 0, sizeof(struct serial_icounter_struct));
1247 
1248     /*  FIXME  the async_struct is being defined by mingw32 headers?
1249         port->astruct = malloc( sizeof( struct async_struct ) );
1250         if( ! port->astruct )
1251             goto fail;
1252         memset( port->astruct, 0, sizeof( struct async_struct ) );
1253     */
1254     port->MSR = 0;
1255 
1256     strncpy(port->filename, filename, sizeof(port->filename) - 1);
1257 
1258     /* didn't free well? strdup( filename ); */
1259     if (! port->filename)
1260     {
1261         goto fail;
1262     }
1263 
1264     port->fd = get_free_fd();
1265 
1266 
1267     if (!first_tl)
1268     {
1269         port->prev = NULL;
1270         first_tl = port;
1271     }
1272     else
1273     {
1274         while (index->next)
1275         {
1276             index = index->next;
1277         }
1278 
1279         if (port == first_tl)
1280         {
1281             port->prev = NULL;
1282             port->next = first_tl;
1283             first_tl->prev = port;
1284             first_tl = port;
1285         }
1286         else
1287         {
1288             port->prev = index;
1289             index->next = port;
1290         }
1291     }
1292 
1293     port->next = NULL;
1294     LEAVE("add_port");
1295     return port;
1296 
1297 fail:
1298     report("add_port:  Out Of Memory\n");
1299 
1300     if (port->ttyset) { free(port->ttyset); }
1301 
1302     if (port->astruct) { free(port->astruct); }
1303 
1304     if (port->sstruct) { free(port->sstruct); }
1305 
1306     if (port->sis) { free(port->sis); }
1307 
1308     /* had problems with strdup
1309     if ( port->filename ) free( port->filename );
1310     */
1311     if (port) { free(port); }
1312 
1313     return port;
1314 }
1315 
1316 /*----------------------------------------------------------
1317 check_port_capabilities()
1318 
1319    accept:
1320    perform:
1321    return:
1322    exceptions:
1323    win32api:      GetCommProperties(), GetCommState()
1324    comments:
1325 ----------------------------------------------------------*/
1326 
check_port_capabilities(struct termios_list * index)1327 static int check_port_capabilities(struct termios_list *index)
1328 {
1329     COMMPROP cp;
1330     DCB dcb;
1331     char message[80];
1332 
1333     ENTER("check_port_capabilities");
1334     /* check for capabilities */
1335     GetCommProperties(index->hComm, &cp);
1336 
1337     if (!(cp.dwProvCapabilities & PCF_DTRDSR))
1338     {
1339         sprintf(message,
1340                 "%s: no DTR & DSR support\n", __func__);
1341         report(message);
1342     }
1343 
1344     if (!(cp.dwProvCapabilities & PCF_RLSD))
1345     {
1346         sprintf(message, "%s: no carrier detect (RLSD) support\n",
1347                 __func__);
1348         report(message);
1349     }
1350 
1351     if (!(cp.dwProvCapabilities & PCF_RTSCTS))
1352     {
1353         sprintf(message,
1354                 "%s: no RTS & CTS support\n", __func__);
1355         report(message);
1356     }
1357 
1358     if (!(cp.dwProvCapabilities & PCF_TOTALTIMEOUTS))
1359     {
1360         sprintf(message, "%s: no timeout support\n", __func__);
1361         report(message);
1362     }
1363 
1364     if (!GetCommState(index->hComm, &dcb))
1365     {
1366         YACK();
1367         report("GetCommState\n");
1368         return -1;
1369     }
1370 
1371     LEAVE("check_port_capabilities");
1372     return 0;
1373 
1374 }
1375 
1376 /*----------------------------------------------------------
1377 serial_open()
1378 
1379    accept:
1380    perform:
1381    return:
1382    exceptions:
1383    win32api:    None
1384    comments:
1385 ----------------------------------------------------------*/
1386 
win32_serial_open(const char * filename,int flags,...)1387 int win32_serial_open(const char *filename, int flags, ...)
1388 {
1389     struct termios_list *index;
1390     char message[756];
1391     char fullfilename[256];
1392 
1393     ENTER("serial_open");
1394 
1395     fullfilename[sizeof(fullfilename) - 1] = '\0';
1396 
1397     /* according to http://support.microsoft.com/kb/115831
1398      * this is necessary for COM ports larger than COM9 */
1399     if (memcmp(filename, "\\\\.\\", 4) != 0)
1400     {
1401         snprintf(fullfilename, sizeof(fullfilename) - 1, "\\\\.\\%s", filename);
1402     }
1403     else
1404     {
1405         strncpy(fullfilename, filename, sizeof(fullfilename) - 1);
1406     }
1407 
1408     if (port_opened(fullfilename))
1409     {
1410         report("Port is already opened\n");
1411         return (-1);
1412     }
1413 
1414     index = add_port(fullfilename);
1415 
1416     if (!index)
1417     {
1418         report("serial_open !index\n");
1419         return (-1);
1420     }
1421 
1422     index->interrupt = 0;
1423     index->tx_happened = 0;
1424 
1425     if (open_port(index))
1426     {
1427         sprintf(message, "serial_open():  Invalid Port Reference for %s\n",
1428                 fullfilename);
1429         report(message);
1430         win32_serial_close(index->fd);
1431         return -1;
1432     }
1433 
1434     if (check_port_capabilities(index))
1435     {
1436         report("check_port_capabilities!");
1437         win32_serial_close(index->fd);
1438         return -1;
1439     }
1440 
1441     init_termios(index->ttyset);
1442     init_serial_struct(index->sstruct);
1443 
1444     /* set default condition */
1445     tcsetattr(index->fd, 0, index->ttyset);
1446 
1447     /* if opened with non-blocking, then operating non-blocking */
1448     if (flags & O_NONBLOCK)
1449     {
1450         index->open_flags = O_NONBLOCK;
1451     }
1452     else
1453     {
1454         index->open_flags = 0;
1455     }
1456 
1457 
1458     if (!first_tl->hComm)
1459     {
1460         sprintf(message, "open():  Invalid Port Reference for %s\n",
1461                 index->filename);
1462         report(message);
1463     }
1464 
1465     if (first_tl->hComm == INVALID_HANDLE_VALUE)
1466     {
1467         report("serial_open: test\n");
1468     }
1469 
1470     LEAVE("serial_open");
1471     return (index->fd);
1472 }
1473 
1474 
1475 /*----------------------------------------------------------
1476 serial_write()
1477 
1478    accept:
1479    perform:
1480    return:
1481    exceptions:
1482    win32api:     WriteFile(), GetLastError(),
1483                  WaitForSingleObject(),  GetOverlappedResult(),
1484                  FlushFileBuffers(), Sleep()
1485    comments:
1486 ----------------------------------------------------------*/
1487 
win32_serial_write(int fd,const char * Str,int length)1488 int win32_serial_write(int fd, const char *Str, int length)
1489 {
1490     unsigned long nBytes;
1491     struct termios_list *index;
1492     /* COMSTAT Stat; */
1493     int old_flag;
1494 
1495     ENTER("serial_write");
1496 
1497     if (fd <= 0)
1498     {
1499         return 0;
1500     }
1501 
1502     index = find_port(fd);
1503 
1504     if (!index)
1505     {
1506         LEAVE("serial_write");
1507         return -1;
1508     }
1509 
1510     old_flag = index->event_flag;
1511     /*
1512         index->event_flag &= ~EV_TXEMPTY;
1513         SetCommMask( index->hComm, index->event_flag );
1514         index->tx_happened = 1;
1515     */
1516     index->wol.Offset = index->wol.OffsetHigh = 0;
1517     ResetEvent(index->wol.hEvent);
1518 
1519     if (!WriteFile(index->hComm, Str, length, &nBytes, &index->wol))
1520     {
1521         WaitForSingleObject(index->wol.hEvent, 100);
1522 
1523         if (GetLastError() != ERROR_IO_PENDING)
1524         {
1525             /* ClearErrors( index, &Stat ); */
1526             report("serial_write error\n");
1527             /* report("Condition 1 Detected in write()\n"); */
1528             YACK();
1529             errno = EIO;
1530             nBytes = -1;
1531             goto end;
1532         }
1533         /* This is breaking on Win2K, WinXP for some reason */
1534         else while (!GetOverlappedResult(index->hComm, &index->wol,
1535                                              &nBytes, TRUE))
1536             {
1537                 if (GetLastError() != ERROR_IO_INCOMPLETE)
1538                 {
1539                     /* report("Condition 2 Detected in write()\n"); */
1540                     YACK();
1541                     errno = EIO;
1542                     nBytes = -1;
1543                     goto end;
1544                     /* ClearErrors( index, &Stat ); */
1545                 }
1546             }
1547     }
1548     else
1549     {
1550         /* Write finished synchronously.  That is ok!
1551          * I have seen this with USB to Serial
1552          * devices like TI's.
1553          */
1554     }
1555 
1556 end:
1557     /* FlushFileBuffers( index->hComm ); */
1558     index->event_flag |= EV_TXEMPTY;
1559     /* ClearErrors( index, &Stat ); */
1560     SetCommMask(index->hComm, index->event_flag);
1561     /* ClearErrors( index, &Stat ); */
1562     index->event_flag = old_flag;
1563     index->tx_happened = 1;
1564     LEAVE("serial_write");
1565     return nBytes;
1566 }
1567 
1568 /*----------------------------------------------------------
1569 serial_read()
1570 
1571    accept:
1572    perform:
1573    return:
1574    exceptions:
1575    win32api:      ReadFile(), GetLastError(), WaitForSingleObject()
1576                   GetOverLappedResult()
1577    comments:    If setting errno make sure not to use EWOULDBLOCK
1578                 In that case use EAGAIN.  See SerialImp.c:testRead()
1579 ----------------------------------------------------------*/
1580 
win32_serial_read(int fd,void * vb,int size)1581 int win32_serial_read(int fd, void *vb, int size)
1582 {
1583     long start, now;
1584     unsigned long nBytes = 0, total = 0;
1585     /* unsigned long waiting = 0; */
1586     int err;
1587     struct termios_list *index;
1588     char message[80];
1589     COMSTAT stat;
1590     clock_t c;
1591     unsigned char *dest = vb;
1592 
1593     start = GetTickCount();
1594     ENTER("serial_read");
1595 
1596     if (fd <= 0)
1597     {
1598         return 0;
1599     }
1600 
1601     index = find_port(fd);
1602 
1603     if (!index)
1604     {
1605         LEAVE("serial_read");
1606         return -1;
1607     }
1608 
1609     /* FIXME: CREAD: without this, data cannot be read
1610        FIXME: PARMRK: mark framing & parity errors
1611        FIXME: IGNCR: ignore \r
1612        FIXME: ICRNL: convert \r to \n
1613        FIXME: INLCR: convert \n to \r
1614     */
1615 
1616     if (index->open_flags & O_NONBLOCK)
1617     {
1618         /* pull mucho-cpu here? */
1619         do
1620         {
1621 #ifdef DEBUG_VERBOSE
1622             report("vmin=0\n");
1623 #endif /* DEBUG_VERBOSE */
1624             ClearErrors(index, &stat);
1625 
1626             if (stat.cbInQue < index->ttyset->c_cc[VMIN])
1627             {
1628                 /*
1629                   hl_usleep(50);
1630                 */
1631                 hl_usleep(100);     /* don't hog the CPU while waiting */
1632 
1633                 /* we should use -1 instead of 0 for disabled timeout */
1634                 now = GetTickCount();
1635 
1636                 if (index->ttyset->c_cc[VTIME] &&
1637                         now - start >= (index->ttyset->c_cc[VTIME] * 100))
1638                 {
1639                     /*
1640                       sprintf( message, "now = %i start = %i time = %i total =%i\n", now, start, index->ttyset->c_cc[VTIME]*100, total);
1641                       report( message );
1642                     */
1643                     return total; /* read timeout */
1644                 }
1645             }
1646         }
1647         while (size > 1 && stat.cbInQue < index->ttyset->c_cc[VMIN]);
1648     }
1649     else
1650     {
1651         /* VTIME is in units of 0.1 seconds */
1652 
1653 #ifdef DEBUG_VERBOSE
1654         report("vmin!=0\n");
1655 #endif /* DEBUG_VERBOSE */
1656         /* vmin = index->ttyset->c_cc[VMIN]; */
1657 
1658         c = clock() + index->ttyset->c_cc[VTIME] * CLOCKS_PER_SEC / 10;
1659 
1660         do
1661         {
1662             ClearErrors(index, &stat);
1663             hl_usleep(1000);
1664         }
1665         while (stat.cbInQue < index->ttyset->c_cc[VMIN] && c > clock());
1666 
1667     }
1668 
1669     total = 0;
1670 
1671     while (size > 0)
1672     {
1673         nBytes = 0;
1674         /* ClearErrors( index, &stat); */
1675 
1676         index->rol.Offset = index->rol.OffsetHigh = 0;
1677         ResetEvent(index->rol.hEvent);
1678 
1679         err = ReadFile(index->hComm, dest + total, size, &nBytes, &index->rol);
1680 #ifdef DEBUG_VERBOSE
1681         /* warning Roy Rogers! */
1682         sprintf(message, " ========== ReadFile = %i 0x%x\n",
1683                 (int) nBytes, *((char *) dest + total));
1684         report(message);
1685 #endif /* DEBUG_VERBOSE */
1686 
1687         if (!err)
1688         {
1689             switch (GetLastError())
1690             {
1691             case ERROR_BROKEN_PIPE:
1692                 report("ERROR_BROKEN_PIPE\n ");
1693                 nBytes = 0;
1694                 break;
1695 
1696             case ERROR_MORE_DATA:
1697                 /*
1698                   hl_usleep(1000);
1699                 */
1700                 report("ERROR_MORE_DATA\n");
1701                 break;
1702 
1703             case ERROR_IO_PENDING:
1704                 while (! GetOverlappedResult(
1705                             index->hComm,
1706                             &index->rol,
1707                             &nBytes,
1708                             TRUE))
1709                 {
1710                     if (GetLastError() !=
1711                             ERROR_IO_INCOMPLETE)
1712                     {
1713                         ClearErrors(
1714                             index,
1715                             &stat);
1716                         return (total);
1717                     }
1718                 }
1719 
1720                 size -= nBytes;
1721                 total += nBytes;
1722 
1723                 if (size > 0)
1724                 {
1725                     now = GetTickCount();
1726                     sprintf(message, "size > 0: spent=%ld have=%d\n", now - start,
1727                             index->ttyset->c_cc[VTIME] * 100);
1728                     report(message);
1729 
1730                     /* we should use -1 for disabled
1731                        timouts */
1732                     if (index->ttyset->c_cc[VTIME]
1733                             && now - start >= (index->ttyset->c_cc[VTIME] * 100))
1734                     {
1735                         report("TO ");
1736                         /* read timeout */
1737                         return total;
1738                     }
1739                 }
1740 
1741                 sprintf(message, "end nBytes=%lu] ", nBytes);
1742                 report(message);
1743                 /*
1744                   hl_usleep(1000);
1745                 */
1746                 report("ERROR_IO_PENDING\n");
1747                 break;
1748 
1749             default:
1750                 /*
1751                   hl_usleep(1000);
1752                 */
1753                 YACK();
1754                 return -1;
1755             }
1756         }
1757         else
1758         {
1759             size -= nBytes;
1760             total += nBytes;
1761 
1762             /*
1763               hl_usleep(1000);
1764             */
1765             ClearErrors(index, &stat);
1766             return (total);
1767         }
1768     }
1769 
1770     LEAVE("serial_read");
1771     return total;
1772 }
1773 
1774 #ifdef asdf
win32_serial_read(int fd,void * vb,int size)1775 int win32_serial_read(int fd, void *vb, int size)
1776 {
1777     long start, now;
1778     unsigned long nBytes = 0, total = 0, error;
1779     /* unsigned long waiting = 0; */
1780     int err, vmin;
1781     struct termios_list *index;
1782     char message[80];
1783     COMSTAT Stat;
1784     clock_t c;
1785     unsigned char *dest = vb;
1786 
1787     start = GetTickCount();
1788     ENTER("serial_read");
1789 
1790     if (fd <= 0)
1791     {
1792         printf("1\n");
1793         return 0;
1794     }
1795 
1796     index = find_port(fd);
1797 
1798     if (!index)
1799     {
1800         LEAVE("serial_read 7");
1801         errno = EIO;
1802         printf("2\n");
1803         return -1;
1804     }
1805 
1806     /* FIXME: CREAD: without this, data cannot be read
1807        FIXME: PARMRK: mark framing & parity errors
1808        FIXME: IGNCR: ignore \r
1809        FIXME: ICRNL: convert \r to \n
1810        FIXME: INLCR: convert \n to \r
1811     */
1812 
1813     ClearErrors(index, &Stat);
1814 
1815     if (index->open_flags & O_NONBLOCK)
1816     {
1817         vmin = 0;
1818 
1819         /* pull mucho-cpu here? */
1820         do
1821         {
1822 #ifdef DEBUG_VERBOSE
1823             report("vmin=0\n");
1824 #endif /* DEBUG_VERBOSE */
1825             ClearErrors(index, &Stat);
1826             /*
1827                         hl_usleep(1000);
1828                         hl_usleep(50);
1829             */
1830             /* we should use -1 instead of 0 for disabled timeout */
1831             now = GetTickCount();
1832 
1833             if (index->ttyset->c_cc[VTIME] &&
1834                     now - start >= (index->ttyset->c_cc[VTIME] * 100))
1835             {
1836                 /*
1837                                 sprintf( message, "now = %i start = %i time = %i total =%i\n", now, start, index->ttyset->c_cc[VTIME]*100, total);
1838                                 report( message );
1839                 */
1840                 errno = EAGAIN;
1841                 printf("3\n");
1842                 return -1;  /* read timeout */
1843             }
1844         }
1845         while (Stat.cbInQue < size && size > 1);
1846     }
1847     else
1848     {
1849         /* VTIME is in units of 0.1 seconds */
1850 
1851 #ifdef DEBUG_VERBOSE
1852         report("vmin!=0\n");
1853 #endif /* DEBUG_VERBOSE */
1854         vmin = index->ttyset->c_cc[VMIN];
1855 
1856         c = clock() + index->ttyset->c_cc[VTIME] * CLOCKS_PER_SEC / 10;
1857 
1858         do
1859         {
1860             error = ClearErrors(index, &Stat);
1861             hl_usleep(1000);
1862         }
1863         while (c > clock());
1864 
1865     }
1866 
1867     total = 0;
1868 
1869     while (size > 0)
1870     {
1871         nBytes = 0;
1872         /* ClearErrors( index, &Stat); */
1873 
1874         index->rol.Offset = index->rol.OffsetHigh = 0;
1875         ResetEvent(index->rol.hEvent);
1876 
1877         err = ReadFile(index->hComm, dest + total, size, &nBytes, &index->rol);
1878 #ifdef DEBUG_VERBOSE
1879         /* warning Roy Rogers! */
1880         sprintf(message, " ========== ReadFile = %i %s\n",
1881                 (int) nBytes, (char *) dest + total);
1882         report(message);
1883 #endif /* DEBUG_VERBOSE */
1884 
1885         if (!err)
1886         {
1887             switch (GetLastError())
1888             {
1889             case ERROR_BROKEN_PIPE:
1890                 report("ERROR_BROKEN_PIPE\n ");
1891                 nBytes = 0;
1892                 break;
1893 
1894             case ERROR_MORE_DATA:
1895                 /*
1896                                     hl_usleep(1000);
1897                 */
1898                 report("ERROR_MORE_DATA\n");
1899                 break;
1900 
1901             case ERROR_IO_PENDING:
1902                 while (! GetOverlappedResult(
1903                             index->hComm,
1904                             &index->rol,
1905                             &nBytes,
1906                             TRUE))
1907                 {
1908                     if (GetLastError() !=
1909                             ERROR_IO_INCOMPLETE)
1910                     {
1911                         ClearErrors(
1912                             index,
1913                             &Stat);
1914                         printf("4\n");
1915                         return (total);
1916                     }
1917                 }
1918 
1919                 size -= nBytes;
1920                 total += nBytes;
1921 
1922                 if (size > 0)
1923                 {
1924                     now = GetTickCount();
1925                     sprintf(message, "size > 0: spent=%ld have=%d\n", now - start,
1926                             index->ttyset->c_cc[VTIME] * 100);
1927                     report(message);
1928 
1929                     /* we should use -1 for disabled
1930                        timouts */
1931                     if (index->ttyset->c_cc[VTIME]
1932                             && now - start >= (index->ttyset->c_cc[VTIME] * 100))
1933                     {
1934                         report("TO ");
1935                         /* read timeout */
1936                         printf("5\n");
1937                         return total;
1938                     }
1939                 }
1940 
1941                 sprintf(message, "end nBytes=%ld] ", nBytes);
1942                 report(message);
1943                 /*
1944                                     hl_usleep(1000);
1945                 */
1946                 report("ERROR_IO_PENDING\n");
1947                 break;
1948 
1949             default:
1950                 /*
1951                                     hl_usleep(1000);
1952                 */
1953                 YACK();
1954                 errno = EIO;
1955                 printf("6\n");
1956                 return -1;
1957             }
1958         }
1959         else
1960         {
1961             size -= nBytes;
1962             total += nBytes;
1963 
1964             /*
1965                         hl_usleep(1000);
1966             */
1967             ClearErrors(index, &Stat);
1968             printf("7\n");
1969             return (total);
1970         }
1971     }
1972 
1973     LEAVE("serial_read");
1974     ClearErrors(index, &Stat);
1975     return total;
1976 }
1977 #endif /* asdf */
1978 
1979 /*----------------------------------------------------------
1980 cfsetospeed()
1981 
1982    accept:
1983    perform:
1984    return:
1985    exceptions:
1986    win32api:     None
1987    comments:
1988 ----------------------------------------------------------*/
1989 
cfsetospeed(struct termios * s_termios,speed_t speed)1990 int cfsetospeed(struct termios *s_termios, speed_t speed)
1991 {
1992     char message[80];
1993     ENTER("cfsetospeed");
1994     /* clear baudrate */
1995     s_termios->c_cflag &= ~CBAUD;
1996 
1997     if (speed & ~CBAUD)
1998     {
1999         sprintf(message, "cfsetospeed: not speed: %#o\n", speed);
2000         report(message);
2001         /* continue assuming its a custom baudrate */
2002         s_termios->c_cflag |= B38400;  /* use 38400 during custom */
2003         s_termios->c_cflag |= CBAUDEX; /* use CBAUDEX for custom */
2004     }
2005     else if (speed)
2006     {
2007         s_termios->c_cflag |= speed;
2008     }
2009     else
2010     {
2011         /* PC blows up with speed 0 handled in Java */
2012         s_termios->c_cflag |= B9600;
2013     }
2014 
2015     s_termios->c_ispeed = s_termios->c_ospeed = speed;
2016     LEAVE("cfsetospeed");
2017     return 1;
2018 }
2019 
2020 /*----------------------------------------------------------
2021 cfsetispeed()
2022 
2023    accept:
2024    perform:
2025    return:
2026    exceptions:
2027    win32api:     None
2028    comments:
2029 ----------------------------------------------------------*/
2030 
cfsetispeed(struct termios * s_termios,speed_t speed)2031 int cfsetispeed(struct termios *s_termios, speed_t speed)
2032 {
2033     return cfsetospeed(s_termios, speed);
2034 }
2035 
2036 /*----------------------------------------------------------
2037 cfsetspeed()
2038 
2039    accept:
2040    perform:
2041    return:
2042    exceptions:
2043    win32api:     None
2044    comments:
2045 ----------------------------------------------------------*/
2046 
cfsetspeed(struct termios * s_termios,speed_t speed)2047 int cfsetspeed(struct termios *s_termios, speed_t speed)
2048 {
2049     return cfsetospeed(s_termios, speed);
2050 }
2051 
2052 /*----------------------------------------------------------
2053 cfgetospeed()
2054 
2055    accept:
2056    perform:
2057    return:
2058    exceptions:
2059    win32api:     None
2060    comments:
2061 ----------------------------------------------------------*/
2062 
cfgetospeed(struct termios * s_termios)2063 speed_t cfgetospeed(struct termios *s_termios)
2064 {
2065     ENTER("cfgetospeed");
2066     return s_termios->c_ospeed;
2067 }
2068 
2069 /*----------------------------------------------------------
2070 cfgetispeed()
2071 
2072    accept:
2073    perform:
2074    return:
2075    exceptions:
2076    win32api:     None
2077    comments:
2078 ----------------------------------------------------------*/
2079 
cfgetispeed(struct termios * s_termios)2080 speed_t cfgetispeed(struct termios *s_termios)
2081 {
2082     ENTER("cfgetospeed");
2083     return s_termios->c_ispeed;
2084 }
2085 
2086 /*----------------------------------------------------------
2087 serial_struct_to_DCB()
2088 
2089    accept:
2090    perform:
2091    return:
2092    exceptions:
2093    win32api:     None
2094    comments:
2095 ----------------------------------------------------------*/
serial_struct_to_DCB(struct serial_struct * sstruct,DCB * dcb)2096 int serial_struct_to_DCB(struct serial_struct *sstruct, DCB *dcb)
2097 {
2098     /* 5 Baud rate fix
2099     sstruct.baud_base
2100     sstruct.custom_divisor = ( sstruct.baud_base/cspeed );
2101     */
2102     return (0);
2103 }
2104 
2105 /*----------------------------------------------------------
2106 termios_to_DCB()
2107 
2108    accept:
2109    perform:
2110    return:
2111    exceptions:
2112    win32api:     None
2113    comments:
2114 ----------------------------------------------------------*/
termios_to_DCB(struct termios * s_termios,DCB * dcb)2115 static int termios_to_DCB(struct termios *s_termios, DCB *dcb)
2116 {
2117     ENTER("termios_to_DCB");
2118 
2119     if (!(s_termios->c_cflag & CBAUDEX))
2120     {
2121         s_termios->c_ispeed = s_termios->c_ospeed = s_termios->c_cflag & CBAUD;
2122     }
2123 
2124     dcb->BaudRate        = B_to_CBR(s_termios->c_ispeed);
2125     dcb->ByteSize = termios_to_bytesize(s_termios->c_cflag);
2126 
2127     if (s_termios->c_cflag & PARENB)
2128     {
2129         if (s_termios->c_cflag & PARODD
2130                 && s_termios->c_cflag & CMSPAR)
2131         {
2132             dcb->Parity = MARKPARITY;
2133         }
2134         else if (s_termios->c_cflag & PARODD)
2135         {
2136             dcb->Parity = ODDPARITY;
2137         }
2138         else if (s_termios->c_cflag & CMSPAR)
2139         {
2140             dcb->Parity = SPACEPARITY;
2141         }
2142         else
2143         {
2144             dcb->Parity = EVENPARITY;
2145         }
2146     }
2147     else
2148     {
2149         dcb->Parity = NOPARITY;
2150     }
2151 
2152     if (s_termios->c_cflag & CSTOPB) { dcb->StopBits = TWOSTOPBITS; }
2153     else { dcb->StopBits = ONESTOPBIT; }
2154 
2155     if (s_termios->c_cflag & HARDWARE_FLOW_CONTROL)
2156     {
2157         dcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
2158         dcb->fOutxCtsFlow = TRUE;
2159     }
2160     else
2161     {
2162         dcb->fRtsControl = RTS_CONTROL_DISABLE;
2163         dcb->fOutxCtsFlow = FALSE;
2164     }
2165 
2166     LEAVE("termios_to_DCB");
2167     return 0;
2168 }
2169 
2170 /*----------------------------------------------------------
2171 DCB_to_serial_struct()
2172 
2173    accept:
2174    perform:
2175    return:
2176    exceptions:
2177    win32api:     None
2178    comments:
2179 ----------------------------------------------------------*/
DCB_to_serial_struct(DCB * dcb,struct serial_struct * sstruct)2180 int DCB_to_serial_struct(DCB *dcb, struct serial_struct *sstruct)
2181 {
2182     return (0);
2183 }
2184 /*----------------------------------------------------------
2185 DCB_to_termios()
2186 
2187    accept:
2188    perform:
2189    return:
2190    exceptions:
2191    win32api:     None
2192    comments:
2193 ----------------------------------------------------------*/
DCB_to_termios(DCB * dcb,struct termios * s_termios)2194 static void DCB_to_termios(DCB *dcb, struct termios *s_termios)
2195 {
2196     ENTER("DCB_to_termios");
2197     s_termios->c_ispeed = CBR_to_B(dcb->BaudRate);
2198     s_termios->c_ospeed = s_termios->c_ispeed;
2199     s_termios->c_cflag |= s_termios->c_ispeed & CBAUD;
2200     LEAVE("DCB_to_termios");
2201 }
2202 
2203 /*----------------------------------------------------------
2204 show_DCB()
2205 
2206    accept:
2207    perform:
2208    return:
2209    exceptions:
2210    win32api:     None
2211    comments:
2212 ----------------------------------------------------------*/
show_DCB(DCB myDCB)2213 static void show_DCB(DCB myDCB)
2214 {
2215 
2216 #ifdef DEBUG_HOSED
2217     char message[80];
2218 
2219     sprintf(message, "DCBlength: %ld\n", myDCB.DCBlength);
2220     report(message);
2221     sprintf("BaudRate: %ld\n", myDCB.BaudRate);
2222     report(message);
2223 
2224     if (myDCB.fBinary)
2225     {
2226         report("fBinary\n");
2227     }
2228 
2229     if (myDCB.fParity)
2230     {
2231         report("fParity: ");
2232 
2233         if (myDCB.fErrorChar)
2234         {
2235             sprintf(message, "fErrorChar: %#x\n", myDCB.ErrorChar);
2236             report(message);
2237         }
2238         else
2239         {
2240             report("fErrorChar == false\n");
2241         }
2242     }
2243 
2244     if (myDCB.fOutxCtsFlow)
2245     {
2246         report("fOutxCtsFlow\n");
2247     }
2248 
2249     if (myDCB.fOutxDsrFlow)
2250     {
2251         report("fOutxDsrFlow\n");
2252     }
2253 
2254     if (myDCB.fDtrControl & DTR_CONTROL_HANDSHAKE);
2255 
2256     report("DTR_CONTROL_HANDSHAKE\n");
2257 
2258     if (myDCB.fDtrControl & DTR_CONTROL_ENABLE);
2259 
2260     report("DTR_CONTROL_ENABLE\n");
2261 
2262     if (myDCB.fDtrControl & DTR_CONTROL_DISABLE);
2263 
2264     report("DTR_CONTROL_DISABLE\n");
2265 
2266     if (myDCB.fDsrSensitivity)
2267     {
2268         report("fDsrSensitivity\n");
2269     }
2270 
2271     if (myDCB.fTXContinueOnXoff)
2272     {
2273         report("fTXContinueOnXoff\n");
2274     }
2275 
2276     if (myDCB.fOutX)
2277     {
2278         report("fOutX\n");
2279     }
2280 
2281     if (myDCB.fInX)
2282     {
2283         report("fInX\n");
2284     }
2285 
2286     if (myDCB.fNull)
2287     {
2288         report("fNull\n");
2289     }
2290 
2291     if (myDCB.fRtsControl & RTS_CONTROL_TOGGLE)
2292     {
2293         report("RTS_CONTROL_TOGGLE\n");
2294     }
2295 
2296     if (myDCB.fRtsControl == 0)
2297     {
2298         report("RTS_CONTROL_HANDSHAKE ( fRtsControl==0 )\n");
2299     }
2300 
2301     if (myDCB.fRtsControl & RTS_CONTROL_HANDSHAKE)
2302     {
2303         report("RTS_CONTROL_HANDSHAKE\n");
2304     }
2305 
2306     if (myDCB.fRtsControl & RTS_CONTROL_ENABLE)
2307     {
2308         report("RTS_CONTROL_ENABLE\n");
2309     }
2310 
2311     if (myDCB.fRtsControl & RTS_CONTROL_DISABLE)
2312     {
2313         report("RTS_CONTROL_DISABLE\n");
2314     }
2315 
2316     if (myDCB.fAbortOnError)
2317     {
2318         report("fAbortOnError\n");
2319     }
2320 
2321     sprintf(message, "XonLim: %d\n", myDCB.XonLim);
2322     report(message);
2323     sprintf(message, "XoffLim: %d\n", myDCB.XoffLim);
2324     report(message);
2325     sprintf(message, "ByteSize: %d\n", myDCB.ByteSize);
2326     report(message);
2327 
2328     switch (myDCB.Parity)
2329     {
2330     case EVENPARITY:
2331         report("EVENPARITY");
2332         break;
2333 
2334     case MARKPARITY:
2335         report("MARKPARITY");
2336         break;
2337 
2338     case NOPARITY:
2339         report("NOPARITY");
2340         break;
2341 
2342     case ODDPARITY:
2343         report("ODDPARITY");
2344         break;
2345 
2346     default:
2347         sprintf(message,
2348                 "unknown Parity (%#x ):", myDCB.Parity);
2349         report(message);
2350         break;
2351     }
2352 
2353     report("\n");
2354 
2355     switch (myDCB.StopBits)
2356     {
2357     case ONESTOPBIT:
2358         report("ONESTOPBIT");
2359         break;
2360 
2361     case ONE5STOPBITS:
2362         report("ONE5STOPBITS");
2363         break;
2364 
2365     case TWOSTOPBITS:
2366         report("TWOSTOPBITS");
2367         break;
2368 
2369     default:
2370         report("unknown StopBits (%#x ):", myDCB.StopBits);
2371         break;
2372     }
2373 
2374     report("\n");
2375     sprintf(message,  "XonChar: %#x\n", myDCB.XonChar);
2376     report(message);
2377     sprintf(message, "XoffChar: %#x\n", myDCB.XoffChar);
2378     report(message);
2379     sprintf(message, "EofChar: %#x\n", myDCB.EofChar);
2380     report(message);
2381     sprintf(message, "EvtChar: %#x\n", myDCB.EvtChar);
2382     report(message);
2383     report("\n");
2384 #endif /* DEBUG_HOSED */
2385 }
2386 
2387 /*----------------------------------------------------------
2388 tcgetattr()
2389 
2390    accept:
2391    perform:
2392    return:
2393    exceptions:
2394    win32api:    GetCommState(), GetCommTimeouts()
2395    comments:
2396 ----------------------------------------------------------*/
2397 
tcgetattr(int fd,struct termios * s_termios)2398 int tcgetattr(int fd, struct termios *s_termios)
2399 {
2400     DCB myDCB;
2401     COMMTIMEOUTS timeouts;
2402     struct termios_list *index;
2403     char message[80];
2404 
2405     ENTER("tcgetattr");
2406 
2407     if (fd <= 0)
2408     {
2409         return 0;
2410     }
2411 
2412     index = find_port(fd);
2413 
2414     if (!index)
2415     {
2416         LEAVE("tcgetattr");
2417         return -1;
2418     }
2419 
2420     if (!GetCommState(index->hComm, &myDCB))
2421     {
2422         sprintf(message, "GetCommState failed\n");
2423         report(message);
2424         return -1;
2425     }
2426 
2427     memcpy(s_termios, index->ttyset, sizeof(struct termios));
2428 
2429     show_DCB(myDCB);
2430 
2431     /***** input mode flags (c_iflag ) ****/
2432     /* parity check enable */
2433     if (myDCB.fParity)
2434     {
2435         s_termios->c_iflag |= INPCK;
2436         s_termios->c_iflag &= ~IGNPAR;
2437     }
2438     else
2439     {
2440         s_termios->c_iflag &= ~INPCK;
2441         s_termios->c_iflag |= IGNPAR;
2442     }
2443 
2444     /* FIXME: IGNBRK: ignore break */
2445     /* FIXME: BRKINT: interrupt on break */
2446 
2447     if (myDCB.fOutX)
2448     {
2449         s_termios->c_iflag |= IXON;
2450     }
2451     else
2452     {
2453         /* IXON: output start/stop control */
2454         s_termios->c_iflag &= ~IXON;
2455     }
2456 
2457     if (myDCB.fInX)
2458     {
2459         s_termios->c_iflag |= IXOFF;
2460     }
2461     else
2462     {
2463         /* IXOFF: input start/stop control */
2464         s_termios->c_iflag &= ~IXOFF;
2465     }
2466 
2467     if (myDCB.fTXContinueOnXoff)
2468     {
2469         s_termios->c_iflag |= IXANY;
2470     }
2471     else
2472     {
2473         /* IXANY: any char restarts output */
2474         s_termios->c_iflag &= ~IXANY;
2475     }
2476 
2477     /* FIXME: IMAXBEL: if input buffer full, send bell */
2478 
2479     /***** control mode flags (c_cflag ) *****/
2480     /* FIXME: CLOCAL: DONT send SIGHUP on modem disconnect */
2481     /* FIXME: HUPCL: generate modem disconnect when all has closed or
2482         exited */
2483     /* CSTOPB two stop bits ( otherwise one) */
2484     if (myDCB.StopBits == TWOSTOPBITS)
2485     {
2486         s_termios->c_cflag |= CSTOPB;
2487     }
2488 
2489     if (myDCB.StopBits == ONESTOPBIT)
2490     {
2491         s_termios->c_cflag &= ~CSTOPB;
2492     }
2493 
2494     /* PARENB enable parity bit */
2495     s_termios->c_cflag &= ~(PARENB | PARODD | CMSPAR);
2496     myDCB.fParity = 1;
2497 
2498 #if 0 // redundant
2499 
2500     if (myDCB.fParity)
2501     {
2502 #endif
2503         report("tcgetattr getting parity\n");
2504         s_termios->c_cflag |= PARENB;
2505 
2506         if (myDCB.Parity == MARKPARITY)
2507         {
2508             s_termios->c_cflag |= (PARODD | CMSPAR);
2509         }
2510         else if (myDCB.Parity == SPACEPARITY)
2511         {
2512             s_termios->c_cflag |= CMSPAR;
2513         }
2514         else if (myDCB.Parity == ODDPARITY)
2515         {
2516             report("ODDPARITY\n");
2517             s_termios->c_cflag |= PARODD;
2518         }
2519         else if (myDCB.Parity == EVENPARITY)
2520         {
2521             report("EVENPARITY\n");
2522             s_termios->c_cflag &= ~PARODD;
2523         }
2524         else if (myDCB.Parity == NOPARITY)
2525         {
2526             s_termios->c_cflag &= ~(PARODD | CMSPAR | PARENB);
2527         }
2528 
2529 #if 0 // see redundant above
2530     }
2531     else
2532     {
2533         s_termios->c_cflag &= ~PARENB;
2534     }
2535 
2536 #endif
2537 
2538     /* CSIZE */
2539     s_termios->c_cflag |= bytesize_to_termios(myDCB.ByteSize);
2540 
2541     /* HARDWARE_FLOW_CONTROL: hardware flow control */
2542     if ((myDCB.fOutxCtsFlow == TRUE) ||
2543             (myDCB.fRtsControl == RTS_CONTROL_HANDSHAKE))
2544     {
2545         s_termios->c_cflag |= HARDWARE_FLOW_CONTROL;
2546     }
2547     else
2548     {
2549         s_termios->c_cflag &= ~HARDWARE_FLOW_CONTROL;
2550     }
2551 
2552     /* MDMBUF: carrier based flow control of output */
2553     /* CIGNORE: tcsetattr will ignore control modes & baudrate */
2554 
2555     /***** NOT SUPPORTED: local mode flags (c_lflag) *****/
2556     /* ICANON: canonical (not raw) mode */
2557     /* ECHO: echo back to terminal */
2558     /* ECHOE: echo erase */
2559     /* ECHOPRT: hardcopy echo erase */
2560     /* ECHOK: show KILL char */
2561     /* ECHOKE: BSD ECHOK */
2562     /* ECHONL: ICANON only: echo newline even with no ECHO */
2563     /* ECHOCTL: if ECHO, then control-A are printed as '^A' */
2564     /* ISIG: recognize INTR, QUIT & SUSP */
2565     /* IEXTEN: implementation defined */
2566     /* NOFLSH: dont clear i/o queues on INTR, QUIT or SUSP */
2567     /* TOSTOP: background process generate SIGTTOU */
2568     /* ALTWERASE: alt-w erase distance */
2569     /* FLUSHO: user DISCARD char */
2570     /* NOKERNINFO: disable STATUS char */
2571     /* PENDIN: input line needsd reprinting, set by REPRINT char */
2572     /***** END - NOT SUPPORTED *****/
2573 
2574     /***** control characters (c_cc[NCCS] ) *****/
2575 
2576     if (!GetCommTimeouts(index->hComm, &timeouts))
2577     {
2578         YACK();
2579         report("GetCommTimeouts\n");
2580         return -1;
2581     }
2582 
2583     s_termios->c_cc[VTIME] = timeouts.ReadTotalTimeoutConstant / 100;
2584     /*
2585         handled in SerialImp.c?
2586         s_termios->c_cc[VMIN] = ?
2587     */
2588 
2589     s_termios->c_cc[VSTART] = myDCB.XonChar;
2590     s_termios->c_cc[VSTOP] = myDCB.XoffChar;
2591     s_termios->c_cc[VEOF] = myDCB.EofChar;
2592 
2593 #ifdef DEBUG_VERBOSE
2594     sprintf(message,
2595             "tcgetattr: VTIME:%d, VMIN:%d\n", s_termios->c_cc[VTIME],
2596             s_termios->c_cc[VMIN]);
2597     report(message);
2598 #endif /* DEBUG_VERBOSE */
2599 
2600     /***** line discipline ( c_line ) ( == c_cc[33] ) *****/
2601 
2602     DCB_to_termios(&myDCB, s_termios);   /* baudrate */
2603     LEAVE("tcgetattr");
2604     return 0;
2605 }
2606 
2607 /*
2608     `TCSANOW'
2609         Make the change immediately.
2610 
2611     `TCSADRAIN'
2612         Make the change after waiting until all queued output has
2613         been written.  You should usually use this option when
2614         changing parameters that affect output.
2615 
2616     `TCSAFLUSH'
2617         This is like `TCSADRAIN', but also discards any queued input.
2618 
2619     `TCSASOFT'
2620         This is a flag bit that you can add to any of the above
2621         alternatives.  Its meaning is to inhibit alteration of the
2622         state of the terminal hardware.  It is a BSD extension; it is
2623         only supported on BSD systems and the GNU system.
2624 
2625         Using `TCSASOFT' is exactly the same as setting the `CIGNORE'
2626         bit in the `c_cflag' member of the structure TERMIOS-P points
2627         to.  *Note Control Modes::, for a description of `CIGNORE'.
2628 */
2629 
2630 /*----------------------------------------------------------
2631 tcsetattr()
2632 
2633    accept:
2634    perform:
2635    return:
2636    exceptions:
2637    win32api:     GetCommState(), GetCommTimeouts(), SetCommState(),
2638                  SetCommTimeouts()
2639    comments:
2640 ----------------------------------------------------------*/
tcsetattr(int fd,int when,struct termios * s_termios)2641 int tcsetattr(int fd, int when, struct termios *s_termios)
2642 {
2643     int vtime;
2644     DCB dcb;
2645     COMMTIMEOUTS timeouts;
2646     struct termios_list *index;
2647 
2648     ENTER("tcsetattr");
2649 
2650     if (fd <= 0)
2651     {
2652         return 0;
2653     }
2654 
2655     index = find_port(fd);
2656 
2657     if (!index)
2658     {
2659         LEAVE("tcsetattr");
2660         return -1;
2661     }
2662 
2663     fflush(stdout);
2664 
2665     if (s_termios->c_lflag & ICANON)
2666     {
2667         report("tcsetattr: no canonical mode support\n");
2668         /* and all other c_lflags too */
2669         return -1;
2670     }
2671 
2672     if (!GetCommState(index->hComm, &dcb))
2673     {
2674         YACK();
2675         report("tcsetattr:GetCommState\n");
2676         return -1;
2677     }
2678 
2679     if (!GetCommTimeouts(index->hComm, &timeouts))
2680     {
2681         YACK();
2682         report("tcsetattr:GetCommTimeouts\n");
2683         return -1;
2684     }
2685 
2686     /*** control flags, c_cflag **/
2687     if (!(s_termios->c_cflag & CIGNORE))
2688     {
2689         dcb.fParity = 1;
2690 
2691         /* CIGNORE: ignore control modes and baudrate */
2692         /* baudrate */
2693         if (termios_to_DCB(s_termios, &dcb) < 0) { return -1; }
2694     }
2695     else
2696     {
2697     }
2698 
2699     /*** input flags, c_iflag **/
2700     /*  This is wrong.  It disables Parity  FIXME
2701         if( ( s_termios->c_iflag & INPCK ) && !( s_termios->c_iflag & IGNPAR ) )
2702         {
2703             dcb.fParity = TRUE;
2704         } else
2705         {
2706             dcb.fParity = FALSE;
2707         }
2708     */
2709     /* not in win95?
2710        Some years later...
2711        eww..  FIXME This is used for changing the Parity
2712        error character
2713 
2714        I think this code is hosed.  See VEOF below
2715 
2716        Trent
2717     */
2718 
2719     if (s_termios->c_iflag & ISTRIP) { dcb.fBinary = FALSE; }
2720     /* ISTRIP: strip to seven bits */
2721     else { dcb.fBinary = TRUE; }
2722 
2723     /* FIXME: IGNBRK: ignore break */
2724     /* FIXME: BRKINT: interrupt on break */
2725     if (s_termios->c_iflag & IXON)
2726     {
2727         dcb.fOutX = TRUE;
2728     }
2729     else
2730     {
2731         dcb.fOutX = FALSE;
2732     }
2733 
2734     if (s_termios->c_iflag & IXOFF)
2735     {
2736         dcb.fInX = TRUE;
2737     }
2738     else
2739     {
2740         dcb.fInX = FALSE;
2741     }
2742 
2743     dcb.fTXContinueOnXoff = (s_termios->c_iflag & IXANY) ? TRUE : FALSE;
2744     /* FIXME: IMAXBEL: if input buffer full, send bell */
2745 
2746     /* no DTR control in termios? */
2747     dcb.fDtrControl     = DTR_CONTROL_DISABLE;
2748     /* no DSR control in termios? */
2749     dcb.fOutxDsrFlow    = FALSE;
2750     /* DONT ignore rx bytes when DSR is OFF */
2751     dcb.fDsrSensitivity = FALSE;
2752     dcb.XonChar         = s_termios->c_cc[VSTART];
2753     dcb.XoffChar        = s_termios->c_cc[VSTOP];
2754     dcb.XonLim          = 0;    /* ? */
2755     dcb.XoffLim         = 0;    /* ? */
2756     dcb.EofChar         = s_termios->c_cc[VEOF];
2757 
2758     if (dcb.EofChar != '\0')
2759     {
2760         dcb.fBinary = FALSE;
2761     }
2762     else
2763     {
2764         dcb.fBinary = TRUE;
2765     }
2766 
2767     if (EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | (EV_RLSD & EV_RXFLAG))
2768     {
2769         dcb.EvtChar = '\n';
2770     }
2771     else
2772     {
2773         dcb.EvtChar = '\0';
2774     }
2775 
2776     if (!SetCommState(index->hComm, &dcb))
2777     {
2778         report("SetCommState error\n");
2779         YACK();
2780         return -1;
2781     }
2782 
2783 #ifdef DEBUG_VERBOSE
2784     {
2785         char message[32];
2786         sprintf(message, "VTIME:%d, VMIN:%d\n", s_termios->c_cc[VTIME],
2787                 s_termios->c_cc[VMIN]);
2788         report(message);
2789     }
2790 #endif /* DEBUG_VERBOSE */
2791     vtime = s_termios->c_cc[VTIME] * 100;
2792     timeouts.ReadTotalTimeoutConstant = vtime;
2793     timeouts.ReadIntervalTimeout = 0;
2794     timeouts.ReadTotalTimeoutMultiplier = 0;
2795 
2796     timeouts.WriteTotalTimeoutConstant = vtime;
2797     timeouts.WriteTotalTimeoutMultiplier = 0;
2798 
2799     /* max between bytes */
2800     if (s_termios->c_cc[VMIN] > 0 && vtime > 0)
2801     {
2802         /* read blocks forever on VMIN chars */
2803     }
2804     else if (s_termios->c_cc[VMIN] == 0 && vtime == 0)
2805     {
2806         /* read returns immediately */
2807         timeouts.ReadIntervalTimeout = MAXDWORD;
2808         timeouts.ReadTotalTimeoutConstant = 0;
2809         timeouts.ReadTotalTimeoutMultiplier = 0;
2810     }
2811 
2812 #ifdef DEBUG_VERBOSE
2813     {
2814         char message[64];
2815         sprintf(message, "ReadIntervalTimeout=%ld\n",
2816                 timeouts.ReadIntervalTimeout);
2817         report(message);
2818         sprintf(message, "c_cc[VTIME] = %d, c_cc[VMIN] = %d\n",
2819                 s_termios->c_cc[VTIME], s_termios->c_cc[VMIN]);
2820         report(message);
2821         sprintf(message, "ReadTotalTimeoutConstant: %ld\n",
2822                 timeouts.ReadTotalTimeoutConstant);
2823         report(message);
2824         sprintf(message, "ReadIntervalTimeout : %ld\n",
2825                 timeouts.ReadIntervalTimeout);
2826         report(message);
2827         sprintf(message, "ReadTotalTimeoutMultiplier: %ld\n",
2828                 timeouts.ReadTotalTimeoutMultiplier);
2829         report(message);
2830     }
2831 #endif /* DEBUG_VERBOSE */
2832 
2833     if (!SetCommTimeouts(index->hComm, &timeouts))
2834     {
2835         YACK();
2836         report("SetCommTimeouts\n");
2837         return -1;
2838     }
2839 
2840     memcpy(index->ttyset, s_termios, sizeof(struct termios));
2841     LEAVE("tcsetattr");
2842     return 0;
2843 }
2844 
2845 /*----------------------------------------------------------
2846 tcsendbreak()
2847 
2848    accept:
2849    perform:
2850    return:
2851    exceptions:
2852    win32api:     None
2853    comments:
2854         break for duration*0.25 seconds or
2855         0.25 seconds if duration = 0.
2856 ----------------------------------------------------------*/
2857 
tcsendbreak(int fd,int duration)2858 int tcsendbreak(int fd, int duration)
2859 {
2860     struct termios_list *index;
2861     COMSTAT Stat;
2862 
2863     ENTER("tcsendbreak");
2864 
2865     index = find_port(fd);
2866 
2867     if (!index)
2868     {
2869         LEAVE("tcdrain");
2870         return -1;
2871     }
2872 
2873     if (duration <= 0) { duration = 1; }
2874 
2875     if (!SetCommBreak(index->hComm))
2876     {
2877         ClearErrors(index, &Stat);
2878     }
2879 
2880     /* 0.25 seconds == 250000 usec */
2881     hl_usleep(duration * 250000);
2882 
2883     if (!ClearCommBreak(index->hComm))
2884     {
2885         ClearErrors(index, &Stat);
2886     }
2887 
2888     LEAVE("tcsendbreak");
2889     return 1;
2890 }
2891 
2892 /*----------------------------------------------------------
2893 tcdrain()
2894 
2895    accept:       file descriptor
2896    perform:      wait for output to be written.
2897    return:       0 on success, -1 otherwise
2898    exceptions:   None
2899    win32api:     FlushFileBuffers
2900    comments:
2901 ----------------------------------------------------------*/
2902 
tcdrain(int fd)2903 int tcdrain(int fd)
2904 {
2905     struct termios_list *index;
2906     char message[80];
2907     int old_flag;
2908 
2909     ENTER("tcdrain");
2910     index = find_port(fd);
2911 
2912     if (!index)
2913     {
2914         LEAVE("tcdrain");
2915         return -1;
2916     }
2917 
2918     old_flag = index->event_flag;
2919 
2920     /*
2921         index->event_flag &= ~EV_TXEMPTY;
2922         SetCommMask( index->hComm, index->event_flag );
2923         index->tx_happened = 1;
2924     */
2925     if (!FlushFileBuffers(index->hComm))
2926     {
2927         /* FIXME  Need to figure out what the various errors are in
2928                   windows.  YACK() should report them and we can
2929               handle them as we find them
2930 
2931 
2932               Something funky is happening on NT.  GetLastError =
2933               0.
2934         */
2935         sprintf(message,  "FlushFileBuffers() %i\n",
2936                 (int) GetLastError());
2937         report(message);
2938 
2939         if (GetLastError() == 0)
2940         {
2941             set_errno(0);
2942             return (0);
2943         }
2944 
2945         set_errno(EAGAIN);
2946         YACK();
2947         LEAVE("tcdrain");
2948         return -1;
2949     }
2950 
2951     /*
2952         sprintf( message,  "FlushFileBuffers() %i\n",
2953             (int) GetLastError() );
2954         report( message );
2955     */
2956     LEAVE("tcdrain success");
2957     index->event_flag |= EV_TXEMPTY;
2958     SetCommMask(index->hComm, index->event_flag);
2959     index->event_flag = old_flag;
2960     /*
2961         index->tx_happened = 1;
2962     */
2963     return 0;
2964 }
2965 
2966 /*----------------------------------------------------------
2967 tcflush()
2968 
2969    accept:       file descriptor, queue_selector
2970    perform:      discard data not transmitted or read
2971          TCIFLUSH:  flush data not read
2972          TCOFLUSH:  flush data not transmitted
2973          TCIOFLUSH: flush both
2974    return:       0 on success, -1 on error
2975    exceptions:   none
2976    win32api:     PurgeComm
2977    comments:
2978 ----------------------------------------------------------*/
2979 
tcflush(int fd,int queue_selector)2980 int tcflush(int fd, int queue_selector)
2981 {
2982     struct termios_list *index;
2983     int old_flag;
2984 
2985     ENTER("tcflush");
2986 
2987     index = find_port(fd);
2988 
2989     if (!index)
2990     {
2991         LEAVE("tclflush");
2992         return (-1);
2993     }
2994 
2995     old_flag = index->event_flag;
2996     /*
2997         index->event_flag &= ~EV_TXEMPTY;
2998         SetCommMask( index->hComm, index->event_flag );
2999         index->tx_happened = 1;
3000     */
3001 
3002     index->tx_happened = 1;
3003 
3004     switch (queue_selector)
3005     {
3006     case TCIFLUSH:
3007         if (!PurgeComm(index->hComm, PURGE_RXABORT | PURGE_RXCLEAR))
3008         {
3009             goto fail;
3010         }
3011 
3012         break;
3013 
3014     case TCOFLUSH:
3015         if (!PurgeComm(index->hComm, PURGE_TXABORT | PURGE_TXCLEAR))
3016         {
3017             goto fail;
3018         }
3019 
3020         break;
3021 
3022     case TCIOFLUSH:
3023         if (!PurgeComm(index->hComm, PURGE_TXABORT | PURGE_TXCLEAR))
3024         {
3025             goto fail;
3026         }
3027 
3028         if (!PurgeComm(index->hComm, PURGE_RXABORT | PURGE_RXCLEAR))
3029         {
3030             goto fail;
3031         }
3032 
3033         break;
3034 
3035     default:
3036         /*
3037                     set_errno( ENOTSUP );
3038         */
3039         report("tcflush: Unknown queue_selector\n");
3040         LEAVE("tcflush");
3041         return -1;
3042     }
3043 
3044     index->event_flag |= EV_TXEMPTY;
3045     SetCommMask(index->hComm, index->event_flag);
3046     index->event_flag = old_flag;
3047     index->tx_happened = 1;
3048     LEAVE("tcflush");
3049     return (0);
3050 
3051     /* FIXME  Need to figure out what the various errors are in
3052               windows.  YACK() should report them and we can
3053           handle them as we find them
3054     */
3055 
3056 fail:
3057     LEAVE("tcflush");
3058     set_errno(EAGAIN);
3059     YACK();
3060     return -1;
3061 
3062 }
3063 
3064 /*----------------------------------------------------------
3065 tcflow()
3066 
3067    accept:
3068    perform:
3069    return:
3070    exceptions:
3071    win32api:     None
3072    comments:   FIXME
3073 ----------------------------------------------------------*/
3074 
tcflow(int fd,int action)3075 int tcflow(int fd, int action)
3076 {
3077     ENTER("tcflow");
3078 
3079     switch (action)
3080     {
3081     /* Suspend transmission of output */
3082     case TCOOFF: break;
3083 
3084     /* Restart transmission of output */
3085     case TCOON: break;
3086 
3087     /* Transmit a STOP character */
3088     case TCIOFF: break;
3089 
3090     /* Transmit a START character */
3091     case TCION: break;
3092 
3093     default: return -1;
3094     }
3095 
3096     LEAVE("tcflow");
3097     return 1;
3098 }
3099 /*----------------------------------------------------------
3100 fstat()
3101 
3102    accept:
3103    perform:
3104    return:
3105    exceptions:
3106    win32api:
3107    comments:  this is just to keep the eventLoop happy.
3108 ----------------------------------------------------------*/
3109 
3110 #if 0
3111 int fstat(int fd, ...)
3112 {
3113     return (0);
3114 }
3115 #endif
3116 
3117 /*----------------------------------------------------------
3118 ioctl()
3119 
3120    accept:
3121    perform:
3122    return:
3123    exceptions:
3124    win32api:     GetCommError(), GetCommModemStatus, EscapeCommFunction()
3125    comments:  FIXME
3126     the DCB struct is:
3127 
3128     typedef struct _DCB
3129     {
3130         unsigned long DCBlength, BaudRate, fBinary:1, fParity:1;
3131         unsigned long fOutxCtsFlow:1, fOutxDsrFlow:1, fDtrControl:2;
3132         unsigned long fDsrSensitivity:1, fTXContinueOnXoff:1;
3133         unsigned long fOutX:1, fInX:1, fErrorChar:1, fNull:1;
3134         unsigned long fRtsControl:2, fAbortOnError:1, fDummy2:17;
3135         WORD wReserved, XonLim, XoffLim;
3136         BYTE ByteSize, Parity, StopBits;
3137         char XonChar, XoffChar, ErrorChar, EofChar, EvtChar;
3138         WORD wReserved1;
3139     } DCB;
3140 
3141 ----------------------------------------------------------*/
3142 
win32_serial_ioctl(int fd,int request,...)3143 int win32_serial_ioctl(int fd, int request, ...)
3144 {
3145     unsigned long dwStatus = 0;
3146     va_list ap;
3147     int *arg, ret, old_flag;
3148     char message[80];
3149 
3150 #ifdef TIOCGSERIAL
3151     DCB *dcb;
3152     struct serial_struct *sstruct;
3153 #endif /* TIOCGSERIAL */
3154     COMSTAT Stat;
3155 
3156     struct termios_list *index;
3157 #ifdef TIOCGICOUNT
3158     struct serial_icounter_struct *sistruct;
3159 #endif  /* TIOCGICOUNT */
3160 
3161     ENTER("ioctl");
3162 
3163     if (fd <= 0)
3164     {
3165         return 0;
3166     }
3167 
3168     index = find_port(fd);
3169 
3170     if (!index)
3171     {
3172         LEAVE("ioctl");
3173         return -1;
3174     }
3175 
3176     va_start(ap, request);
3177 
3178     ret = ClearErrors(index, &Stat);
3179 
3180     if (ret == 0)
3181     {
3182         set_errno(EBADFD);
3183         YACK();
3184         report("ClearError Failed! ernno EBADFD");
3185         arg = va_arg(ap, int *);
3186         va_end(ap);
3187         return -1;
3188     }
3189 
3190     switch (request)
3191     {
3192     case TCSBRK:
3193         arg = va_arg(ap, int *);
3194         va_end(ap);
3195         return -ENOIOCTLCMD;
3196 
3197     case TCSBRKP:
3198         arg = va_arg(ap, int *);
3199         va_end(ap);
3200         return -ENOIOCTLCMD;
3201 
3202     case TIOCGSOFTCAR:
3203         arg = va_arg(ap, int *);
3204         va_end(ap);
3205         return -ENOIOCTLCMD;
3206 
3207     case TIOCSSOFTCAR:
3208         arg = va_arg(ap, int *);
3209         va_end(ap);
3210         return -ENOIOCTLCMD;
3211 
3212     case TIOCCBRK:
3213     case TIOCSBRK:
3214         arg = va_arg(ap, int *);
3215 
3216         if (EscapeCommFunction(index->hComm,
3217                                (request == TIOCSBRK) ? SETBREAK :
3218                                CLRBREAK))
3219         {
3220             report("EscapeCommFunction: True\n");
3221         }
3222         else
3223         {
3224             report("EscapeCommFunction: False\n");
3225         }
3226 
3227         break;
3228 
3229     case TIOCMGET:
3230         arg = va_arg(ap, int *);
3231 
3232         /* DORITOS */
3233         if (!GetCommModemStatus(index->hComm, &dwStatus))
3234         {
3235             report_error("GetCommMOdemStatus failed!\n");
3236         }
3237 
3238         if (dwStatus & MS_RLSD_ON) { *arg |= TIOCM_CAR; }
3239         else { *arg &= ~TIOCM_CAR; }
3240 
3241         if (dwStatus & MS_RING_ON) { *arg |= TIOCM_RNG; }
3242         else { *arg &= ~TIOCM_RNG; }
3243 
3244         if (dwStatus & MS_DSR_ON) { *arg |= TIOCM_DSR; }
3245         else { *arg &= ~TIOCM_DSR; }
3246 
3247         if (dwStatus & MS_CTS_ON) { *arg |= TIOCM_CTS; }
3248         else { *arg &= ~TIOCM_CTS; }
3249 
3250         /*  I'm not seeing a way to read the MSR directly
3251             we store the state using TIOCM_*
3252 
3253             Trent
3254         */
3255         if (index->MSR & TIOCM_DTR)
3256         {
3257             *arg |= TIOCM_DTR;
3258         }
3259         else { *arg &= ~TIOCM_DTR; }
3260 
3261         if (index->MSR & TIOCM_RTS)
3262         {
3263             *arg |= TIOCM_RTS;
3264         }
3265         else { *arg &= ~TIOCM_RTS; }
3266 
3267         /*
3268 
3269                     TIOCM_LE
3270                     TIOCM_ST
3271                     TIOCM_SR
3272         */
3273         va_end(ap);
3274         return (0);
3275 
3276     case TIOCMBIS:
3277         arg = va_arg(ap, int *);
3278 
3279         if (*arg & TIOCM_DTR)
3280         {
3281             index->MSR |= TIOCM_DTR;
3282 
3283             if (EscapeCommFunction(index->hComm, SETDTR))
3284             {
3285                 report("EscapeCommFunction: True\n");
3286             }
3287             else
3288             {
3289                 report("EscapeCommFunction: False\n");
3290             }
3291         }
3292 
3293         if (*arg & TIOCM_RTS)
3294         {
3295             index->MSR |= TIOCM_RTS;
3296 
3297             if (EscapeCommFunction(index->hComm, SETRTS))
3298             {
3299                 report("EscapeCommFunction: True\n");
3300             }
3301             else
3302             {
3303                 report("EscapeCommFunction: False\n");
3304             }
3305         }
3306 
3307         break;
3308 
3309     case TIOCMBIC:
3310         arg = va_arg(ap, int *);
3311 
3312         if (*arg & TIOCM_DTR)
3313         {
3314             index->MSR &= ~TIOCM_DTR;
3315 
3316             if (EscapeCommFunction(index->hComm, CLRDTR))
3317             {
3318                 report("EscapeCommFunction: True\n");
3319             }
3320             else
3321             {
3322                 report("EscapeCommFunction: False\n");
3323             }
3324         }
3325 
3326         if (*arg & TIOCM_RTS)
3327         {
3328             index->MSR &= ~TIOCM_RTS;
3329 
3330             if (EscapeCommFunction(index->hComm, CLRRTS))
3331             {
3332                 report("EscapeCommFunction: True\n");
3333             }
3334             else
3335             {
3336                 report("EscapeCommFunction: False\n");
3337             }
3338         }
3339 
3340         break;
3341 
3342     case TIOCMSET:
3343         arg = va_arg(ap, int *);
3344 
3345         if ((*arg & TIOCM_DTR) == (index->MSR & TIOCM_DTR))
3346         {
3347             report("DTR is unchanged\n");
3348         }
3349 
3350         sprintf(message, "DTR %i %i\n", *arg & TIOCM_DTR, index->MSR & TIOCM_DTR);
3351         report(message);
3352 
3353         if (*arg & TIOCM_DTR)
3354         {
3355             index->MSR |= TIOCM_DTR;
3356         }
3357         else
3358         {
3359             index->MSR &= ~TIOCM_DTR;
3360         }
3361 
3362         if (EscapeCommFunction(index->hComm,
3363                                (*arg & TIOCM_DTR) ? SETDTR :
3364                                CLRDTR))
3365         {
3366             report("EscapeCommFunction: True\n");
3367         }
3368         else
3369         {
3370             report("EscapeCommFunction: False\n");
3371         }
3372 
3373         if ((*arg & TIOCM_RTS) == (index->MSR & TIOCM_RTS))
3374         {
3375             report("RTS is unchanged\n");
3376         }
3377 
3378         sprintf(message, "RTS %i %i\n", *arg & TIOCM_RTS, index->MSR & TIOCM_RTS);
3379         report(message);
3380 
3381         if (*arg & TIOCM_RTS)
3382         {
3383             index->MSR |= TIOCM_RTS;
3384         }
3385         else
3386         {
3387             index->MSR &= ~TIOCM_RTS;
3388         }
3389 
3390         if (EscapeCommFunction(index->hComm,
3391                                (*arg & TIOCM_RTS) ? SETRTS : CLRRTS))
3392         {
3393             report("EscapeCommFunction: True\n");
3394         }
3395         else
3396         {
3397             report("EscapeCommFunction: False\n");
3398         }
3399 
3400         break;
3401 
3402 #ifdef TIOCGSERIAL
3403 
3404     case TIOCGSERIAL:
3405         report("TIOCGSERIAL\n");
3406 
3407         dcb = malloc(sizeof(DCB));
3408 
3409         if (!dcb)
3410         {
3411             va_end(ap);
3412             return -1;
3413         }
3414 
3415         memset(dcb, 0, sizeof(DCB));
3416         GetCommState(index->hComm, dcb);
3417 
3418         sstruct = va_arg(ap, struct serial_struct *);
3419 
3420         if (DCB_to_serial_struct(dcb, sstruct) < 0)
3421         {
3422             va_end(ap);
3423             return -1;
3424         }
3425 
3426         index->sstruct = sstruct;
3427 
3428         report("TIOCGSERIAL\n");
3429         free(dcb);
3430         break;
3431 
3432 #endif /* TIOCGSERIAL */
3433 #ifdef TIOCSSERIAL
3434 
3435     case TIOCSSERIAL:
3436         report("TIOCSSERIAL\n");
3437 
3438         dcb = malloc(sizeof(DCB));
3439 
3440         if (!dcb)
3441         {
3442             va_end(ap);
3443             return -1;
3444         }
3445 
3446         memset(dcb, 0, sizeof(DCB));
3447         GetCommState(index->hComm, dcb);
3448 
3449         index->sstruct = va_arg(ap, struct serial_struct *);
3450 
3451         if (serial_struct_to_DCB(index->sstruct, dcb) < 0)
3452         {
3453             va_end(ap);
3454             return -1;
3455         }
3456 
3457         report("TIOCSSERIAL\n");
3458         free(dcb);
3459         break;
3460 
3461 #endif /* TIOCSSERIAL */
3462 
3463     case TIOCSERCONFIG:
3464     case TIOCSERGETLSR:
3465         arg = va_arg(ap, int *);
3466         /*
3467         do {
3468             wait = WaitForSingleObject( index->sol.hEvent, 5000 );
3469         } while ( wait == WAIT_TIMEOUT );
3470         */
3471         ret = ClearErrors(index, &Stat);
3472 
3473         if (ret == 0)
3474         {
3475             /* FIXME ? */
3476             set_errno(EBADFD);
3477             YACK();
3478             report("TIOCSERGETLSR EBADFD");
3479             va_end(ap);
3480             return -1;
3481         }
3482 
3483         if ((int) Stat.cbOutQue == 0)
3484         {
3485             /* output is empty */
3486             if (index->tx_happened == 1)
3487             {
3488                 old_flag = index->event_flag;
3489                 index->event_flag &= ~EV_TXEMPTY;
3490                 SetCommMask(index->hComm,
3491                             index->event_flag);
3492                 index->event_flag = old_flag;
3493                 *arg = 1;
3494                 index->tx_happened = 0;
3495                 report("ioctl: output empty\n");
3496             }
3497             else
3498             {
3499                 *arg = 0;
3500             }
3501 
3502             ret = 0;
3503         }
3504         else
3505         {
3506             /* still data out there */
3507             *arg = 0;
3508             ret = 0;
3509         }
3510 
3511         va_end(ap);
3512         return (0);
3513         break;
3514 
3515     case TIOCSERGSTRUCT:
3516     case TIOCSERGETMULTI:
3517     case TIOCSERSETMULTI:
3518         va_end(ap);
3519         return -ENOIOCTLCMD;
3520 
3521     case TIOCMIWAIT:
3522         arg = va_arg(ap, int *);
3523         va_end(ap);
3524         return -ENOIOCTLCMD;
3525         /*
3526             On linux this fills a struct with all the line info
3527             (data available, bytes sent, ...
3528         */
3529 #ifdef TIOCGICOUNT
3530 
3531     case TIOCGICOUNT:
3532         sistruct = va_arg(ap, struct  serial_icounter_struct *);
3533         ret = ClearErrors(index, &Stat);
3534 
3535         if (ret == 0)
3536         {
3537             /* FIXME ? */
3538             report("TIOCGICOUNT failed\n");
3539             set_errno(EBADFD);
3540             va_end(ap);
3541             return -1;
3542         }
3543 
3544         sistruct->frame = index->sis->frame;
3545         sistruct->overrun = index->sis->overrun;
3546         sistruct->parity = index->sis->parity;
3547         sistruct->brk = index->sis->brk;
3548 
3549         va_end(ap);
3550         return 0;
3551         /* abolete ioctls */
3552 #endif /* TIOCGICOUNT */
3553 
3554     case TIOCSERGWILD:
3555     case TIOCSERSWILD:
3556         report("TIOCSER[GS]WILD absolete\n");
3557         va_end(ap);
3558         return 0;
3559 
3560     /*  number of bytes available for reading */
3561     case FIONREAD:
3562         arg = va_arg(ap, int *);
3563         ret = ClearErrors(index, &Stat);
3564 
3565         if (ret == 0)
3566         {
3567             /* FIXME ? */
3568             report("FIONREAD failed\n");
3569             set_errno(EBADFD);
3570             va_end(ap);
3571             return -1;
3572         }
3573 
3574         *arg = (int) Stat.cbInQue;
3575 #ifdef DEBUG_VERBOSE
3576         sprintf(message, "FIONREAD:  %i bytes available\n",
3577                 (int) Stat.cbInQue);
3578         report(message);
3579 
3580         if (*arg)
3581         {
3582             sprintf(message, "FIONREAD: %i\n", *arg);
3583             report(message);
3584         }
3585 
3586 #endif /* DEBUG_VERBOSE */
3587         ret = 0;
3588         break;
3589 
3590     /* pending bytes to be sent */
3591     case TIOCOUTQ:
3592         arg = va_arg(ap, int *);
3593         va_end(ap);
3594         return -ENOIOCTLCMD;
3595 
3596     default:
3597         sprintf(message,
3598                 "FIXME:  ioctl: unknown request: %#x\n",
3599                 request);
3600         report(message);
3601         va_end(ap);
3602         return -ENOIOCTLCMD;
3603     }
3604 
3605     va_end(ap);
3606     LEAVE("ioctl");
3607     return 0;
3608 }
3609 
3610 /*----------------------------------------------------------
3611 fcntl()
3612 
3613    accept:
3614    perform:
3615    return:
3616    exceptions:
3617    win32api:    None
3618    comments:    FIXME
3619 ----------------------------------------------------------*/
3620 
win32_serial_fcntl(int fd,int command,...)3621 int win32_serial_fcntl(int fd, int command, ...)
3622 {
3623     int arg, ret = 0;
3624     va_list ap;
3625     struct termios_list *index;
3626     char message[80];
3627 
3628     ENTER("fcntl");
3629 
3630     if (fd <= 0)
3631     {
3632         return 0;
3633     }
3634 
3635     index = find_port(fd);
3636 
3637     if (!index)
3638     {
3639         LEAVE("fcntl");
3640         return -1;
3641     }
3642 
3643     va_start(ap, command);
3644 
3645     arg = va_arg(ap, int);
3646 
3647     switch (command)
3648     {
3649     case F_SETOWN:  /* set ownership of fd */
3650         break;
3651 
3652     case F_SETFL:   /* set operating flags */
3653 #ifdef DEBUG
3654         sprintf(message, "F_SETFL fd=%d flags=%d\n", fd, arg);
3655         report(message);
3656 #endif
3657         index->open_flags = arg;
3658         break;
3659 
3660     case F_GETFL:   /* get operating flags */
3661         ret = index->open_flags;
3662         break;
3663 
3664     default:
3665         sprintf(message, "unknown fcntl command %#x\n", command);
3666         report(message);
3667         break;
3668     }
3669 
3670     va_end(ap);
3671     LEAVE("fcntl");
3672     return ret;
3673 }
3674 
3675 #if 0
3676 /*----------------------------------------------------------
3677 termios_interrupt_event_loop()
3678 
3679    accept:
3680    perform:
3681    return:  let Serial_select break out so the thread can die
3682    exceptions:
3683    win32api:
3684    comments:
3685 ----------------------------------------------------------*/
3686 static void termios_interrupt_event_loop(int fd, int flag)
3687 {
3688     struct termios_list *index = find_port(fd);
3689 
3690     if (!index)
3691     {
3692         LEAVE("termios_interrupt_event_loop");
3693         return;
3694     }
3695 
3696     /*
3697         index->event_flag = 0;
3698          TRENT SetCommMask( index->hComm, index->event_flag );
3699         hl_usleep(2000);
3700         tcdrain( index->fd );
3701         SetEvent( index->sol.hEvent );
3702     */
3703     index->interrupt = flag;
3704     return;
3705 }
3706 #endif
3707 
3708 /*----------------------------------------------------------
3709 Serial_select()
3710 
3711    accept:
3712    perform:
3713    return:      number of fd's changed on success or -1 on error.
3714    exceptions:
3715    win32api:    SetCommMask(), GetCommEvent(), WaitSingleObject()
3716    comments:
3717 ----------------------------------------------------------*/
3718 #ifndef __LCC__
win32_serial_select(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout)3719 int  win32_serial_select(int  n,  fd_set  *readfds,  fd_set  *writefds,
3720                          fd_set *exceptfds, struct timeval *timeout)
3721 {
3722 
3723     unsigned long dwCommEvent, wait = WAIT_TIMEOUT;
3724     int fd = n - 1;
3725     struct termios_list *index;
3726     char message[80];
3727     COMSTAT Stat;
3728     int ret;
3729 
3730     ENTER("serial_select");
3731 
3732     if (fd <= 0)
3733     {
3734         /*  Baby did a bad baad thing */
3735         goto fail;
3736     }
3737 
3738     index = find_port(fd);
3739 
3740     if (!index)
3741     {
3742         goto fail;
3743     }
3744 
3745 #define DATA_AVAILABLE     1
3746 
3747     //nativeSetEventFlag( fd, SerialPortEvent.DATA_AVAILABLE, enable );
3748     if (readfds)
3749     {
3750         int eventflags[12];
3751         memset(eventflags, 0, sizeof(eventflags));
3752 
3753         eventflags[DATA_AVAILABLE] = 1;
3754         termios_setflags(fd, eventflags);
3755     }
3756 
3757     if (!index->event_flag)
3758     {
3759         /* still setting up the port? hold off for a Sec so
3760            things can fire up
3761 
3762            this does happen.  loops ~twice on a 350 Mzh with
3763            hl_usleep(1000000)
3764         */
3765         /* hl_usleep(10000); */
3766         LEAVE("serial_uselect");
3767         return (0);
3768     }
3769 
3770     ResetEvent(index->wol.hEvent);
3771     ResetEvent(index->sol.hEvent);
3772     ResetEvent(index->rol.hEvent);
3773     ret = ClearErrors(index, &Stat);
3774 #if 1
3775 
3776     if (ret == 0)
3777     {
3778         goto fail;
3779     }
3780 
3781     /* look only after read */
3782     if (readfds && !writefds && !exceptfds)
3783     {
3784         int timeout_usec = timeout ? timeout->tv_sec * 1000000 + timeout->tv_usec :
3785                            INT_MAX;
3786 
3787         while (timeout_usec > 0)
3788         {
3789             sprintf(message, "wait for data in read buffer%d\n", (int)Stat.cbInQue);
3790             report(message);
3791 
3792             if (Stat.cbInQue != 0)
3793             {
3794                 goto end;
3795             }
3796 
3797             hl_usleep(10000);
3798             /* FIXME: not very accurate wrt process time */
3799             timeout_usec -= 10000;
3800 
3801             report("sleep...\n");
3802 
3803             ret = ClearErrors(index, &Stat);
3804 
3805             if (ret == 0)
3806             {
3807                 goto fail;
3808             }
3809         }
3810 
3811         goto timeout;
3812     }
3813 
3814 #endif
3815 
3816     while (wait == WAIT_TIMEOUT && index->sol.hEvent)
3817     {
3818         if (index->interrupt == 1)
3819         {
3820             goto fail;
3821         }
3822 
3823         SetCommMask(index->hComm, index->event_flag);
3824         ClearErrors(index, &Stat);
3825 
3826         if (!WaitCommEvent(index->hComm, &dwCommEvent,
3827                            &index->rol))
3828         {
3829             /* WaitCommEvent failed probably overlapped though */
3830             if (GetLastError() != ERROR_IO_PENDING)
3831             {
3832                 ClearErrors(index, &Stat);
3833                 goto fail;
3834             }
3835 
3836             /* thought so... */
3837         }
3838 
3839         /*  could use the select timeout here but it should not
3840             be needed
3841         */
3842         ClearErrors(index, &Stat);
3843         wait = WaitForSingleObject(index->rol.hEvent, 100);
3844 
3845         switch (wait)
3846         {
3847         case WAIT_OBJECT_0:
3848             goto end;
3849 
3850         case WAIT_TIMEOUT:
3851             goto timeout;
3852 
3853         case WAIT_ABANDONED:
3854         default:
3855             goto fail;
3856 
3857         }
3858     }
3859 
3860 end:
3861     /*  You may want to chop this out for lower latency */
3862     /* hl_usleep(1000); */
3863     LEAVE("serial_select");
3864     return (1);
3865 timeout:
3866     LEAVE("serial_select");
3867     return (0);
3868 fail:
3869     YACK();
3870     sprintf(message, "< select called error %i\n", n);
3871     report(message);
3872     errno = EBADFD;
3873     LEAVE("serial_select");
3874     return (-1);
3875 }
3876 #ifdef asdf
win32_serial_select(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout)3877 int  win32_serial_select(int  n,  fd_set  *readfds,  fd_set  *writefds,
3878                          fd_set *exceptfds, struct timeval *timeout)
3879 {
3880 
3881     unsigned long nBytes, dwCommEvent, wait = WAIT_TIMEOUT;
3882     int fd = n - 1;
3883     struct termios_list *index;
3884     char message[80];
3885 
3886     ENTER("serial_select");
3887 
3888     if (fd <= 0)
3889     {
3890         /* hl_usleep(1000); */
3891         return 1;
3892     }
3893 
3894     index = find_port(fd);
3895 
3896     if (!index)
3897     {
3898         LEAVE("serial_select");
3899         return -1;
3900     }
3901 
3902     if (index->interrupt == 1)
3903     {
3904         goto end;
3905     }
3906 
3907     while (!index->event_flag)
3908     {
3909         /* hl_usleep(1000); */
3910         return -1;
3911     }
3912 
3913     while (wait == WAIT_TIMEOUT && index->sol.hEvent)
3914     {
3915         if (index->interrupt == 1)
3916         {
3917             goto end;
3918         }
3919 
3920         if (!index->sol.hEvent)
3921         {
3922             return 1;
3923         }
3924 
3925         if (!WaitCommEvent(index->hComm, &dwCommEvent,
3926                            &index->sol))
3927         {
3928             /* WaitCommEvent failed */
3929             if (index->interrupt == 1)
3930             {
3931                 goto end;
3932             }
3933 
3934             if (GetLastError() != ERROR_IO_PENDING)
3935             {
3936                 sprintf(message, "WaitCommEvent filename = %s\n", index->filename);
3937                 report(message);
3938                 return (1);
3939                 /*
3940                                 goto fail;
3941                 */
3942             }
3943 
3944             return (1);
3945         }
3946 
3947         if (index->interrupt == 1)
3948         {
3949             goto end;
3950         }
3951 
3952         wait = WaitForSingleObject(index->sol.hEvent, 1000);
3953 
3954         switch (wait)
3955         {
3956         case WAIT_OBJECT_0:
3957             if (index->interrupt == 1)
3958             {
3959                 goto end;
3960             }
3961 
3962             if (!index->sol.hEvent) { return (1); }
3963 
3964             if (!GetOverlappedResult(index->hComm,
3965                                      &index->sol, &nBytes, TRUE))
3966             {
3967                 goto end;
3968             }
3969             else if (index->tx_happened == 1)
3970             {
3971                 goto end;
3972             }
3973             else
3974             {
3975                 goto end;
3976             }
3977 
3978             break;
3979 
3980         case WAIT_TIMEOUT:
3981         default:
3982             return (1); /* WaitFor error */
3983 
3984         }
3985     }
3986 
3987 end:
3988     /*
3989         hl_usleep(1000);
3990     */
3991     LEAVE("serial_select");
3992     return (1);
3993 #ifdef asdf
3994     /* FIXME this needs to be cleaned up... */
3995 fail:
3996     sprintf(message, "< select called error %i\n", n);
3997     YACK();
3998     report(message);
3999     set_errno(EBADFD);
4000     LEAVE("serial_select");
4001     return (1);
4002 #endif /* asdf */
4003 
4004 }
4005 #endif /* asdf */
4006 #endif /* __LCC__ */
4007 
4008 #if 0
4009 /*----------------------------------------------------------
4010 termiosSetParityError()
4011 
4012    accept:      fd The device opened
4013    perform:     Get the Parity Error Char
4014    return:      the Parity Error Char
4015    exceptions:  none
4016    win32api:    GetCommState()
4017    comments:    No idea how to do this in Unix  (handle in read?)
4018 ----------------------------------------------------------*/
4019 
4020 static int termiosGetParityErrorChar(int fd)
4021 {
4022     struct termios_list *index;
4023     DCB dcb;
4024 
4025     ENTER("termiosGetParityErrorChar");
4026     index = find_port(fd);
4027 
4028     if (!index)
4029     {
4030         LEAVE("termiosGetParityErrorChar");
4031         return (-1);
4032     }
4033 
4034     GetCommState(index->hComm, &dcb);
4035     LEAVE("termiosGetParityErrorChar");
4036     return (dcb.ErrorChar);
4037 }
4038 
4039 /*----------------------------------------------------------
4040 termiosSetParityError()
4041 
4042    accept:      fd The device opened, value the new Parity Error Char
4043    perform:     Set the Parity Error Char
4044    return:      void
4045    exceptions:  none
4046    win32api:    GetCommState(), SetCommState()
4047    comments:    No idea how to do this in Unix  (handle in read?)
4048 ----------------------------------------------------------*/
4049 
4050 static void termiosSetParityError(int fd, char value)
4051 {
4052     DCB dcb;
4053     struct termios_list *index;
4054 
4055     ENTER("termiosSetParityErrorChar");
4056     index = find_port(fd);
4057 
4058     if (!index)
4059     {
4060         LEAVE("termiosSetParityError");
4061         return;
4062     }
4063 
4064     GetCommState(index->hComm, &dcb);
4065     dcb.ErrorChar = value;
4066     SetCommState(index->hComm, &dcb);
4067     LEAVE("termiosSetParityErrorChar");
4068 }
4069 #endif
4070 
4071 /*----------------------- END OF LIBRARY -----------------*/
4072 
4073 #endif  /* WIN32 */
4074