1/* IBM has disclaimed copyright on this module. */ 2 3/***************************************************************/ 4/* */ 5/* Function: hftctl */ 6/* */ 7/* Syntax: */ 8/* #include <sys/ioctl.h> */ 9/* #include <sys/hft.h> */ 10/* */ 11/* int hftctl(fildes, request, arg ) */ 12/* int fildes, request; */ 13/* char *arg; */ 14/* */ 15/* Description: */ 16/* */ 17/* Does the following: */ 18/* 1. determines if fildes is pty */ 19/* does normal ioctl it is not */ 20/* 2. places fildes into raw mode */ 21/* 3. converts ioctl arguments to datastream */ 22/* 4. waits for 2 secs for acknowledgement before */ 23/* timing out. */ 24/* 5. places response in callers buffer ( just like */ 25/* ioctl. */ 26/* 6. returns fildes to its original mode */ 27/* */ 28/* User of this program should review steps 1,4, and 3. */ 29/* hftctl makes no check on the request type. It must be */ 30/* a HFT ioctl that is supported remotely. */ 31/* This program will use the SIGALRM and alarm(2). Any */ 32/* Previous alarms are lost. */ 33/* */ 34/* Users of this program are free to modify it any way */ 35/* they want. */ 36/* */ 37/* Return Value: */ 38/* */ 39/* If ioctl fails, a value of -1 is returned and errno */ 40/* is set to indicate the error. */ 41/* */ 42/***************************************************************/ 43 44#include <config.h> 45#include <sys/signal.h> 46#include <errno.h> 47#include <stdio.h> 48#include <fcntl.h> 49#include <setjmp.h> 50#include <sys/ioctl.h> 51#include <sys/devinfo.h> 52#include <termios.h> 53#include <termio.h> 54#include <sys/hft.h> 55#include <sys/uio.h> 56#include <sys/tty.h> 57/* #include <sys/pty.h> */ 58 59#define REMOTE 0x01 60 61#undef ioctl 62static char SCCSid[] = "com/gnuemacs/src,3.1,9021-90/05/03-5/3/90"; 63 64/*************** LOCAL DEFINES **********************************/ 65 66#define QDEV ((HFQPDEVCH<<8)|HFQPDEVCL) 67#define QLOC ((HFQLOCCH<<8)|HFQLOCCL) 68#define QPS ((HFQPRESCH<<8)|HFQPRESCL) 69 70#ifndef TCGETS 71#define TCGETS TCGETA 72#endif 73#ifndef TCSETS 74#define TCSETS TCSETA 75#endif 76 77/*************** EXTERNAL / GLOBAL DATA AREA ********************/ 78 79static int hfqry(); 80static int hfskbd(); 81 char *xmalloc(); 82 83extern int errno; 84static jmp_buf hftenv; 85static int is_ack_vtd; 86static SIGTYPE (*sav_alrm) (); 87static struct hfctlreq req = 88 { 0x1b,'[','x',0,0,0,21,HFCTLREQCH,HFCTLREQCL}; 89static struct hfctlack ACK = 90 { 0x1b,'[','x',0,0,0,21,HFCTLACKCH,HFCTLACKCL}; 91 92 /* FUNC signal(); */ 93 94/*************** LOCAL MACROS ***********************************/ 95 96#define HFTYPE(p) ((p->hf_typehi<<8)|(p->hf_typelo)) 97 98#define BYTE4(p) ((p)[0]<<24 | (p)[1]<<16 | (p)[2]<<8 | (p)[3]) 99 100 /* read a buffer */ 101#define RD_BUF(f,p,l) \ 102 while ((l)) \ 103 if ((j = emacs_read (f, p, l)) < 0) \ 104 if (errno != EINTR) return (-1); \ 105 else continue; \ 106 else { (l) -= j; (p) += j; } 107 108/*************** function prototypes ***************************/ 109#ifdef PROTOTYPES 110static GT_ACK (int fd, int req, char *buf); 111static WR_REQ (int fd, int request, int cmdlen, char *cmd, int resplen); 112static void hft_alrm(int sig); 113#else 114static GT_ACK (); 115static WR_REQ (); 116static void hft_alrm (); 117#endif 118 119/*************** HFTCTL FUNCTION *******************************/ 120 121hftctl (fd, request, arg) 122 int fd; 123 int request; 124 union { 125 struct hfintro *intro; 126 struct hfquery *query; 127 char *c; 128 } arg; 129{ 130 131 int i; 132 int fd_flag; /* fcntl flags */ 133 register union { 134 struct hfintro *cmd; /* p.cmd - intro des. */ 135 struct hfqphdevc *ph; /* p.ph - physical dev.*/ 136 char *c; /* p.c - char ptr */ 137 } p; /* general pointer */ 138 int pty_new; /* pty modes */ 139 int pty_old; 140 int retcode; 141 struct termios term_new; /* terminal attributes */ 142 struct termios term_old; 143 struct devinfo devInfo; /* defined in sys/devinfo.h */ 144 145 146 if (ioctl (fd, IOCINFO, &devInfo) == -1) return(-1); 147 148 if (devInfo.devtype != DD_PSEU) /* is it a pty? */ 149 return (ioctl(fd, request, arg)); /* no, do IOCTL */ 150 151 /******* START PTY **************/ 152 /** Pty found, possible HFT */ 153 /** set new file des as raw */ 154 /** as you can. */ 155 /********************************/ 156 157 /* Get current state of file */ 158 /* descriptor & save */ 159 if ((fd_flag = fcntl (fd, F_GETFL, 0)) == -1) return (-1); 160 if (ioctl (fd, TCGETS, &term_old) == -1) return (-1); 161 /* set terminal attr to raw */ 162 /* and to delay on read */ 163 pty_new = pty_old | REMOTE; 164 memcpy (&term_new, &term_old, sizeof (term_new)); 165 term_new.c_iflag = 0; 166 term_new.c_oflag = 0; 167 term_new.c_lflag = 0; 168 /* term_new.c_line = 0; */ 169 for (i = 1; i <= 5; i++) 170 term_new.c_cc[i] = 0; 171 term_new.c_cc[0] = -1; 172 ioctl (fd, TCSETS, &term_new); 173 if (fcntl (fd, F_SETFL, fd_flag & ~O_NDELAY) == -1) 174 return(-1); 175 /* call spacific function */ 176 if (request == HFSKBD) 177 retcode = hfskbd (fd, request, arg.c); 178 else /* assume HFQUERY */ 179 retcode = hfqry (fd, request, arg.c); 180 181 fcntl (fd, F_SETFL, fd_flag); /* reset terminal to original */ 182 ioctl (fd, TCSETS, &term_old); 183 184 185 return (retcode); /* return error */ 186} 187 188/*************** HFSKBD FUNCTION ******************************/ 189static int 190hfskbd (fd, request, arg) 191 int fd; 192 int request; 193 struct hfbuf *arg; 194{ 195 WR_REQ(fd, request, arg->hf_buflen, arg->hf_bufp,0); 196 return (GT_ACK(fd, request, arg->hf_bufp)); 197} 198 199/*************** HFQUERY FUNCTION ******************************/ 200static int 201hfqry (fd, request, arg) 202 int fd; 203 int request; 204 struct hfquery *arg; 205{ 206 WR_REQ(fd, request, arg->hf_cmdlen, arg->hf_cmd, arg->hf_resplen); 207 return (GT_ACK(fd, request, arg->hf_resp)); 208} 209 210 211/*************** GT_ACK FUNCTION ******************************/ 212static int 213GT_ACK (fd, req, buf) 214 int fd; 215 int req; 216 char *buf; 217{ 218 struct hfctlack ack; 219 int i = sizeof (ack); 220 int j = 0; 221 union { 222 char *c; 223 struct hfctlack *ack; 224 } p; 225 226 is_ack_vtd = 0; /* flag no ACT VTD yet */ 227 228 if (setjmp (hftenv)) /* set environment in case */ 229 { /* of time out */ 230 errno = ENODEV; /* if time out, set errno */ 231 return (-1); /* flag error */ 232 } 233 234 alarm(3); /* time out in 3 secs */ 235 sav_alrm = signal (SIGALRM, hft_alrm); /* prepare to catch time out */ 236 237 p.ack = &ack; 238 while (! is_ack_vtd) /* do until valid ACK VTD */ 239 { 240 RD_BUF(fd, p.c, i); /* read until a ACK VTD is fill*/ 241 242 if (! memcmp (&ack, &ACK, sizeof (HFINTROSZ)) /* the ACK intro & */ 243 && (ack.hf_request == req)) /* is it the response we want ?*/ 244 { /* yes, ACK VTD found */ 245 is_ack_vtd = 1; /* quickly, flag it */ 246 break; /* get the %$%#@ out of here */ 247 } 248 249 p.ack = &ack; /* no, then skip 1st */ 250 ++p.c; /* char and start over */ 251 i = sizeof (ack) - 1; /* one less ESC to cry over */ 252 253 while ((*p.c != 0x1b) && i) /* scan for next ESC */ 254 { ++p.c; --i; } /* if any */ 255 256 (i ? memcpy (&ack, p.c, i) : 0); /* if any left over, then move */ 257 p.ack = &ack; /* ESC to front of ack struct */ 258 p.c += i; /* skip over whats been read */ 259 i = sizeof (ack) - i; /* set whats left to be read */ 260 } /***** TRY AGAIN */ 261 262 alarm(0); /* ACK VTD received, reset alrm*/ 263 signal (SIGALRM, sav_alrm); /* reset signal */ 264 265 if (i = ack.hf_arg_len) /* any data following ? */ 266 { /* yes, */ 267 RD_BUF(fd,buf,i); /* read until it is received */ 268 } 269 270 if (errno = ack.hf_retcode) /* set errno based on returned */ 271 return (-1); /* code, if 0, then no error */ 272 else 273 return (0); /* if set, then error returned */ 274} 275 276/*************** HFT_ALRM FUNCTION ******************************/ 277static void 278hft_alrm (sig) /* Function hft_alrm - handle */ 279 int sig; /* alarm signal */ 280{ 281 signal (SIGALRM, sav_alrm); /* reset to previous */ 282 283 if (is_ack_vtd) /* has ack vtd arrived ? */ 284 return; /* yes, then continue */ 285 else /* no, then return with error */ 286 longjmp (hftenv, -1); 287 288} 289 290/*********************************************************************/ 291/*** ***/ 292/*** NOTE: Both the HFCTLREQ and the arg structure should be ***/ 293/*** sent in one io write operation. If terminal ***/ 294/*** emulators are in NODELAY mode then multiple writes ***/ 295/*** may cause bogus information to be read by the emulator ***/ 296/*** depending on the timing. ***/ 297/*** ***/ 298/*********************************************************************/ 299 300static int 301WR_REQ (fd, request, cmdlen, cmd, resplen) 302 int fd; 303 int request; 304 int cmdlen; 305 char *cmd; 306 int resplen; 307{ 308 struct { 309 char *c; 310 struct hfctlreq *req; 311 } p; 312 int size; 313 314 req.hf_request = request; 315 req.hf_arg_len = cmdlen; 316 req.hf_rsp_len = resplen; 317 318 if (cmdlen) /* if arg structure to pass */ 319 { 320 size = sizeof (struct hfctlreq) + cmdlen; 321 if ((p.c = xmalloc(size)) == NULL) /* malloc one area */ 322 return (-1); 323 324 memcpy (p.c, &req, sizeof (req)); /* copy CTL REQ struct */ 325 memcpy (p.c + sizeof (req), cmd, cmdlen); /* copy arg struct */ 326 } 327 else 328 { 329 p.req = &req; /* otherwise use only CTL REQ */ 330 size = sizeof (req); 331 } 332 333 /* write request to terminal */ 334 if (emacs_write (fd, p.c, size) == -1) return (-1); 335 if (p.req != &req) /* free if allocated */ 336 xfree (p.c); 337 return (0); 338 339} 340 341/* arch-tag: cfd4f3bd-fd49-44e6-9f69-c8abdf367650 342 (do not change this comment) */ 343