1 /*
2  * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3  *
4  * This software may be freely used, copied, modified, and distributed
5  * provided that the above copyright notice is preserved in all copies of the
6  * software.
7  */
8 
9 /* -*-C-*-
10  *
11  * $Revision: 1.3 $
12  *     $Date: 2004/12/27 14:00:54 $
13  *
14  */
15 
16 #ifdef __hpux
17 #  define _POSIX_SOURCE 1
18 #endif
19 
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <ctype.h>
23 
24 #ifdef __hpux
25 #  define _TERMIOS_INCLUDED
26 #  include <sys/termio.h>
27 #  undef _TERMIOS_INCLUDED
28 #else
29 #  include <termios.h>
30 #endif
31 
32 #include <string.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <sys/types.h>
37 #include <sys/time.h>
38 
39 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (bsdi)
40 #undef BSD
41 #include <sys/ioctl.h>
42 #endif
43 
44 #ifdef sun
45 # include <sys/ioccom.h>
46 # ifdef __svr4__
47 #  include <sys/bpp_io.h>
48 # else
49 #  include <sbusdev/bpp_io.h>
50 # endif
51 #endif
52 
53 #ifdef BSD
54 # ifdef sun
55 #  include <sys/ttydev.h>
56 # endif
57 # ifdef __alpha
58 #  include <sys/ioctl.h>
59 # else
60 #  include <sys/filio.h>
61 # endif
62 #endif
63 
64 #ifdef __hpux
65 #  define _INCLUDE_HPUX_SOURCE
66 #  include <sys/ioctl.h>
67 #  undef _INCLUDE_HPUX_SOURCE
68 #endif
69 
70 #include "host.h"
71 #include "unixcomm.h"
72 
73 #define PP_TIMEOUT      1              /* seconds */
74 
75 #ifdef sun
76 #define SERIAL_PREFIX "/dev/tty"
77 #define SERPORT1   "/dev/ttya"
78 #define SERPORT2   "/dev/ttyb"
79 #define PARPORT1   "/dev/bpp0"
80 #define PARPORT2   "/dev/bpp1"
81 #endif
82 
83 #ifdef __hpux
84 #define SERIAL_PREFIX "/dev/tty"
85 #define SERPORT1   "/dev/tty00"
86 #define SERPORT2   "/dev/tty01"
87 #define PARPORT1   "/dev/ptr_parallel"
88 #define PARPORT2   "/dev/ptr_parallel"
89 #endif
90 
91 #ifdef __linux__
92 #define SERIAL_PREFIX "/dev/ttyS"
93 #define SERPORT1   "/dev/ttyS0"
94 #define SERPORT2   "/dev/ttyS1"
95 #define PARPORT1   "/dev/par0"
96 #define PARPORT2   "/dev/par1"
97 #endif
98 
99 #if defined(_WIN32) || defined (__CYGWIN__)
100 #define SERIAL_PREFIX "com"
101 #define SERPORT1   "com1"
102 #define SERPORT2   "com2"
103 #define PARPORT1   "lpt1"
104 #define PARPORT2   "lpt2"
105 #endif
106 
107 #if !defined (SERIAL_PREFIX)
108 #define SERIAL_PREFIX "/dev/cuaa"
109 #define SERPORT1   "/dev/cuaa0"
110 #define SERPORT2   "/dev/cuaa1"
111 #define PARPORT1   "/dev/lpt0"
112 #define PARPORT2   "/dev/lpt1"
113 #endif
114 
115 
116 
117 
118 /*
119  * Parallel port output pins, used for signalling to target
120  */
121 
122 #ifdef sun
123 struct bpp_pins bp;
124 #endif
125 
126 static int serpfd = -1;
127 static int parpfd = -1;
128 
129 extern const char *Unix_MatchValidSerialDevice(const char *name)
130 {
131   int i=0;
132   char *sername=NULL;
133 
134   /* Accept no name as the default serial port */
135   if (name == NULL) {
136     return SERPORT1;
137   }
138 
139   /* Look for the simple cases - 1,2,s,S,/dev/... first, and
140    * afterwards look for S=... clauses, which need parsing properly.
141    */
142 
143   /* Accept /dev/tty* where * is limited */
144   if (strlen(name) == strlen(SERPORT1)
145       && strncmp(name, SERIAL_PREFIX, strlen (SERIAL_PREFIX)) == 0)
146       {
147         return name;
148       }
149 
150   /* Accept "1" or "2" or "S" - S is equivalent to "1" */
151   if (strcmp(name, "1") == 0 ||
152       strcmp(name, "S") == 0 || strcmp(name, "s") == 0) {
153     return SERPORT1;
154   }
155   if (strcmp(name, "2") == 0) return SERPORT2;
156 
157   /* It wasn't one of the simple cases, so now we have to parse it
158    * properly
159    */
160 
161   do {
162     switch (name[i]) {
163       case ',':
164         /* Skip over commas */
165         i++;
166         break;
167 
168       default:
169         return 0;
170         /* Unexpected character => error - not matched */
171 
172       case 0:
173         /* End of string means return whatever we have matched */
174         return sername;
175 
176       case 's':
177       case 'S':
178       case 'h':
179       case 'H': {
180         char ch = tolower(name[i]);
181         int j, continue_from, len;
182 
183         /* If the next character is a comma or a NULL then this is
184          * a request for the default Serial port
185          */
186         if (name[++i] == 0 || name[i] == ',') {
187           if (ch=='s')
188               sername=SERPORT1;
189           break;
190         }
191 
192         /* Next character must be an = */
193         if (name[i] != '=') return 0;
194         /* Search for the end of the port spec. (ends in NULL or ,) */
195         for (j= ++i; name[j] != 0 && name[j] != ','; j++)
196           ; /* Do nothing */
197         /* Notice whether this is the last thing to parse or not
198          * and also calaculate the length of the string
199          */
200         if (name[j] == '0') continue_from = -1;
201         else continue_from = j;
202         len=(j-i);
203 
204         /* And now try to match the serial / parallel port */
205         switch (ch) {
206           case 's': {
207             /* Match serial port */
208             if (len==1) {
209               if (name[i]=='1')
210                   sername=SERPORT1;
211               else if (name[i]=='2')
212                   sername=SERPORT2;
213             } else if (len==strlen(SERPORT1)) {
214               if (strncmp(name+i,SERPORT1,strlen(SERPORT1)) == 0)
215                 sername=SERPORT1;
216               else if (strncmp(name+i,SERPORT2,strlen(SERPORT2)) == 0)
217                 sername=SERPORT2;
218             }
219 
220             break;
221           }
222 
223           case 'h':
224             /* We don't actually deal with the H case here, we just
225              * match it and allow it through.
226              */
227             break;
228         }
229 
230         if (continue_from == -1) return sername;
231         i = continue_from;
232         break;
233       }
234     }
235   } while (1);
236 
237   return 0;
238 }
239 
240 
241 extern int Unix_IsSerialInUse(void)
242 {
243     if (serpfd >= 0)
244         return -1;
245 
246     return 0;
247 }
248 
249 extern int Unix_OpenSerial(const char *name)
250 {
251 #if defined(BSD) || defined(__CYGWIN__)
252     serpfd = open(name, O_RDWR);
253 #else
254     serpfd = open(name, O_RDWR | O_NONBLOCK);
255 #endif
256 
257     if (serpfd < 0) {
258         perror("open");
259         return -1;
260     }
261 #ifdef TIOCEXCL
262     if (ioctl(serpfd, TIOCEXCL) < 0) {
263 	close(serpfd);
264         perror("ioctl: TIOCEXCL");
265         return -1;
266     }
267 #endif
268 
269     return 0;
270 }
271 
272 extern void Unix_CloseSerial(void)
273 {
274     if (serpfd >= 0)
275     {
276         (void)close(serpfd);
277         serpfd = -1;
278     }
279 }
280 
281 extern int Unix_ReadSerial(unsigned char *buf, int n, bool block)
282 {
283     fd_set fdset;
284     struct timeval tv;
285     int err;
286 
287     FD_ZERO(&fdset);
288     FD_SET(serpfd, &fdset);
289 
290     tv.tv_sec = 0;
291     tv.tv_usec = (block ? 10000 : 0);
292 
293     err = select(serpfd + 1, &fdset, NULL, NULL, &tv);
294 
295     if (err < 0 && errno != EINTR)
296     {
297 #ifdef DEBUG
298         perror("select");
299 #endif
300         panic("select failure");
301         return -1;
302     }
303     else if (err > 0 && FD_ISSET(serpfd, &fdset))
304       {
305 	int s;
306 
307 	s = read(serpfd, buf, n);
308 	if (s < 0)
309 	  perror("read:");
310 	return s;
311       }
312     else /* err == 0 || FD_CLR(serpfd, &fdset) */
313     {
314         errno = ERRNO_FOR_BLOCKED_IO;
315         return -1;
316     }
317 }
318 
319 extern int Unix_WriteSerial(unsigned char *buf, int n)
320 {
321     return write(serpfd, buf, n);
322 }
323 
324 extern void Unix_ResetSerial(void)
325 {
326     struct termios terminfo;
327 
328     tcgetattr(serpfd, &terminfo);
329     terminfo.c_lflag &= ~(ICANON | ISIG | ECHO | IEXTEN);
330     terminfo.c_iflag &= ~(IGNCR | INPCK | ISTRIP | ICRNL | BRKINT);
331     terminfo.c_iflag |= (IXON | IXOFF | IGNBRK);
332     terminfo.c_cflag = (terminfo.c_cflag & ~CSIZE) | CS8 | CREAD;
333     terminfo.c_cflag &= ~PARENB;
334     terminfo.c_cc[VMIN] = 1;
335     terminfo.c_cc[VTIME] = 0;
336     terminfo.c_oflag &= ~OPOST;
337     tcsetattr(serpfd, TCSAFLUSH, &terminfo);
338 }
339 
340 extern void Unix_SetSerialBaudRate(int baudrate)
341 {
342     struct termios terminfo;
343 
344     tcgetattr(serpfd, &terminfo);
345     cfsetospeed(&terminfo, baudrate);
346     cfsetispeed(&terminfo, baudrate);
347     tcsetattr(serpfd, TCSAFLUSH, &terminfo);
348 }
349 
350 extern void Unix_ioctlNonBlocking(void)
351 {
352 #if defined(BSD)
353     int nonblockingIO = 1;
354     (void)ioctl(serpfd, FIONBIO, &nonblockingIO);
355 
356     if (parpfd != -1)
357         (void)ioctl(parpfd, FIONBIO, &nonblockingIO);
358 #endif
359 }
360 
361 extern void Unix_IsValidParallelDevice(
362   const char *portstring, char **sername, char **parname)
363 {
364   int i=0;
365   *sername=NULL;
366   *parname=NULL;
367 
368   /* Do not recognise a NULL portstring */
369   if (portstring==NULL) return;
370 
371   do {
372     switch (portstring[i]) {
373       case ',':
374         /* Skip over commas */
375         i++;
376         break;
377 
378       default:
379       case 0:
380         /* End of string or bad characcter means we have finished */
381         return;
382 
383       case 's':
384       case 'S':
385       case 'p':
386       case 'P':
387       case 'h':
388       case 'H': {
389         char ch = tolower(portstring[i]);
390         int j, continue_from, len;
391 
392         /* If the next character is a comma or a NULL then this is
393          * a request for the default Serial or Parallel port
394          */
395         if (portstring[++i] == 0 || portstring[i] == ',') {
396           if (ch=='s') *sername=SERPORT1;
397           else if (ch=='p') *parname=PARPORT1;
398           break;
399         }
400 
401         /* Next character must be an = */
402         if (portstring[i] != '=') return;
403         /* Search for the end of the port spec. (ends in NULL or ,) */
404         for (j= ++i; portstring[j] != 0 && portstring[j] != ','; j++)
405           ; /* Do nothing */
406         /* Notice whether this is the last thing to parse or not
407          * and also calaculate the length of the string
408          */
409         if (portstring[j] == '0') continue_from = -1;
410         else continue_from = j;
411         len=(j-i);
412 
413         /* And now try to match the serial / parallel port */
414         switch (ch) {
415           case 's': {
416             /* Match serial port */
417             if (len==1) {
418               if (portstring[i]=='1') *sername=SERPORT1;
419               else if (portstring[i]=='2') *sername=SERPORT2;
420             } else if (len==strlen(SERPORT1)) {
421               if (strncmp(portstring+i,SERPORT1,strlen(SERPORT1)) == 0)
422                 *sername=SERPORT1;
423               else if (strncmp(portstring+i,SERPORT2,strlen(SERPORT2)) == 0)
424                 *sername=SERPORT2;
425             }
426             break;
427           }
428 
429           case 'p': {
430             /* Match parallel port */
431             if (len==1) {
432               if (portstring[i]=='1') *parname=PARPORT1;
433               else if (portstring[i]=='2') *parname=PARPORT2;
434             } else if (len==strlen(PARPORT1)) {
435               if (strncmp(portstring+i,PARPORT1,strlen(PARPORT1)) == 0)
436                 *parname=PARPORT1;
437               else if (strncmp(portstring+i,PARPORT2,strlen(PARPORT2)) == 0)
438                 *parname=PARPORT2;
439             }
440             break;
441           }
442 
443           case 'h':
444             /* We don't actually deal with the H case here, we just
445              * match it and allow it through.
446              */
447             break;
448         }
449 
450         if (continue_from == -1) return;
451         i = continue_from;
452         break;
453       }
454     }
455   } while (1);
456   return;  /* Will never get here */
457 }
458 
459 extern int Unix_IsParallelInUse(void)
460 {
461     if (parpfd >= 0)
462         return -1;
463 
464     return 0;
465 }
466 
467 extern int Unix_OpenParallel(const char *name)
468 {
469 #if defined(BSD)
470     parpfd = open(name, O_RDWR);
471 #else
472     parpfd = open(name, O_RDWR | O_NONBLOCK);
473 #endif
474 
475     if (parpfd < 0)
476     {
477         char errbuf[256];
478 
479         sprintf(errbuf, "open %s", name);
480         perror(errbuf);
481 
482         return -1;
483     }
484 
485     return 0;
486 }
487 
488 extern void Unix_CloseParallel(void)
489 {
490     if (parpfd >= 0)
491     {
492         (void)close(parpfd);
493         parpfd = -1;
494     }
495 }
496 
497 
498 extern unsigned int Unix_WriteParallel(unsigned char *buf, int n)
499 {
500     int ngone;
501 
502     if ((ngone = write(parpfd, buf, n)) < 0)
503     {
504         /*
505          * we ignore errors (except for debug purposes)
506          */
507 #ifdef DEBUG
508         char errbuf[256];
509 
510         sprintf(errbuf, "send_packet: write");
511         perror(errbuf);
512 #endif
513         ngone = 0;
514     }
515 
516     /* finished */
517     return (unsigned int)ngone;
518 }
519 
520 
521 #ifdef sun
522 extern void Unix_ResetParallel(void)
523 {
524     struct bpp_transfer_parms tp;
525 
526 #ifdef DEBUG
527     printf("serpar_reset\n");
528 #endif
529 
530     /*
531      * we need to set the parallel port up for BUSY handshaking,
532      * and select the timeout
533      */
534     if (ioctl(parpfd, BPPIOC_GETPARMS, &tp) < 0)
535     {
536 #ifdef DEBUG
537         perror("ioctl(BPPIOCGETPARMS)");
538 #endif
539         panic("serpar_reset: cannot get BPP parameters");
540     }
541 
542     tp.write_handshake = BPP_BUSY_HS;
543     tp.write_timeout = PP_TIMEOUT;
544 
545     if (ioctl(parpfd, BPPIOC_SETPARMS, &tp) < 0)
546     {
547 #ifdef DEBUG
548         perror("ioctl(BPPIOC_SETPARMS)");
549 #endif
550         panic("serpar_reset: cannot set BPP parameters");
551     }
552 }
553 
554 #else
555 
556 /* Parallel not supported on HP */
557 
558 extern void Unix_ResetParallel(void)
559 {
560 }
561 
562 #endif
563 
564