view src/hftctl.c @ 300:4ee2046fcb72

Initial revision
author Jim Blandy <jimb@redhat.com>
date Wed, 26 Jun 1991 20:21:21 +0000
parents 0d3a6b3b64a4
children 8c615e453683
line wrap: on
line source

/* IBM has disclaimed copyright on this module.  */

/***************************************************************/
/*                                                             */
/* Function: hftctl                                            */
/*                                                             */
/* Syntax:                                                     */
/*    #include <sys/ioctl.h>                                   */
/*    #include <sys/hft.h>                                     */
/*                                                             */
/*    int hftctl(fildes, request, arg )                        */
/*    int fildes, request ;                                    */
/*    char *arg ;                                              */
/*                                                             */
/* Description:                                                */
/*                                                             */
/*    Does the following:                                      */
/*      1. determines if fildes is pty                         */
/*         does normal ioctl it is not                         */
/*      2. places fildes into raw mode                         */
/*      3. converts ioctl arguments to datastream              */
/*      4. waits for 2 secs for acknowledgement before         */
/*         timimg out.                                         */
/*      5. places response in callers buffer ( just like       */
/*         ioctl.                                              */
/*      6. returns fildes to its original mode                 */
/*                                                             */
/*    User of this program should review steps 1,4, and 3.     */
/*    hftctl makes no check on the request type. It must be    */
/*    a HFT ioctl that is supported remotely.                  */
/*    This program will use the SIGALRM and alarm(2).  Any     */
/*    Previous alarms are lost.                                */
/*                                                             */
/*    Users of this program are free to modify it any way      */
/*    they want.                                               */
/*                                                             */
/* Return Value:                                               */
/*                                                             */
/*    If ioctl fails, a value of -1 is returned and errno      */
/*    is set to indicate the error.                            */
/*                                                             */
/***************************************************************/


#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <setjmp.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sys/devinfo.h>
#include <termio.h>
#include <sys/hft.h>
#include <termios.h>
#include <sys/tty.h>
/* #include <sys/pty.h> */
#define REMOTE 0x01

#undef ioctl
static char     SCCSid[] = "com/gnuemacs/src,3.1,9021-90/05/03-5/3/90" ;

/*************** LOCAL DEFINES **********************************/

typedef int     (*FUNC)() ;     /* pointer to a function        */

#define QDEV   ((HFQPDEVCH<<8)|HFQPDEVCL)
#define QLOC   ((HFQLOCCH<<8)|HFQLOCCL)
#define QPS    ((HFQPRESCH<<8)|HFQPRESCL)

/*************** EXTERNAL / GLOBAL DATA AREA ********************/

       int              hfqry() ;
       int              hfskbd() ;
       char            *malloc() ;

extern int              errno ;
static jmp_buf          hftenv ;
static int              is_ack_vtd ;
static FUNC             sav_alrm ;
static struct hfctlreq  req =
			{ 0x1b,'[','x',0,0,0,21,HFCTLREQCH,HFCTLREQCL};
static struct hfctlack  ACK =
			{ 0x1b,'[','x',0,0,0,21,HFCTLACKCH,HFCTLACKCL};

       /* FUNC             signal() ; */

/*************** LOCAL MACROS ***********************************/

#define HFTYPE(p)   ((p->hf_typehi<<8)|(p->hf_typelo))

#define BYTE4(p)    ( (p)[0]<<24 | (p)[1]<<16 | (p)[2]<<8 | (p)[3] )

					/* read a buffer        */
#define RD_BUF(f,p,l) \
        while ( (l) ) \
          if ( ( j = read((f),(p),(l)) ) < 0 ) \
             if ( errno != EINTR ) return (-1) ; \
             else continue ; \
          else { (l)-=j ; (p)+=j ; }

/*************** HFTCTL FUNCTION *******************************/

hftctl( fd, request, arg )
        int     fd ;
        int     request ;
        union {
        struct hfintro *intro ;
        struct hfquery *query ;
        char           *c ;
        }       arg ;
{

        int             i ;
        int             fd_flag ;       /* fcntl flags          */
register union {
 struct hfintro         *cmd ;          /* p.cmd - intro des.   */
 struct hfqphdevc       *ph ;           /* p.ph  - physical dev.*/
        char            *c ;            /* p.c   - char ptr     */
        }               p ;             /* general pointer      */
        int             pty_new ;       /* pty modes            */
        int             pty_old ;
        int             retcode ;
        struct termios   term_new ;      /* terminal attributes  */
        struct termios   term_old ;
	struct devinfo	devInfo ;	/* defined in sys/devinfo.h */


if ( ioctl( fd, IOCINFO, &devInfo ) == -1 ) return(-1) ;

if ( devInfo.devtype != DD_PSEU )	/* is it a pty? */
   return (ioctl(fd, request, arg) ) ;	/* no, do IOCTL */

                                /******* START PTY **************/
                                /**  Pty found, possible HFT    */
                                /** set new file des as raw     */
                                /** as you can.                 */
                                /********************************/

                                /* Get current state of file    */
                                /* descriptor & save            */
if ( ( fd_flag = fcntl( fd, F_GETFL, 0 ) ) == -1 ) return (-1) ;
if ( ioctl( fd, TCGETS, &term_old ) == -1 ) return (-1) ;
                                /* set terminal attr to raw     */
                                /* and to delay on read         */
pty_new = pty_old | REMOTE ;
memcpy( &term_new, &term_old, sizeof( term_new ) ) ;
term_new.c_iflag = 0 ;
term_new.c_oflag = 0 ;
term_new.c_lflag = 0 ;
/* term_new.c_line  = 0 ; */
for ( i = 1 ; i <= 5 ; i++ )
term_new.c_cc[i] = 0 ;
term_new.c_cc[0] = -1 ;
ioctl( fd, TCSETS, &term_new ) ;
if ( fcntl( fd, F_SETFL, fd_flag & ~O_NDELAY ) == -1 )
   return(-1) ;
                                /* call spacific function       */
if ( request == HFSKBD )
   retcode = hfskbd( fd, request, arg.c) ;
else /* assume HFQUERY */
   retcode = hfqry( fd, request, arg.c) ;

fcntl( fd, F_SETFL, fd_flag ) ; /* reset terminal to original   */
ioctl( fd, TCSETS, &term_old ) ;


return( retcode ) ;             /* return error                 */
}

/*************** HFSKBD  FUNCTION ******************************/
static hfskbd(fd, request, arg )
        int     fd ;
        int     request ;
        struct hfbuf *arg ;
{
WR_REQ(fd, request, arg->hf_buflen, arg->hf_bufp,0) ;
return( GT_ACK(fd, request, arg->hf_bufp) ) ;
}

/*************** HFQUERY FUNCTION ******************************/
static hfqry(fd, request, arg )
        int     fd ;
        int     request ;
        struct hfquery *arg ;
{
WR_REQ(fd, request, arg->hf_cmdlen, arg->hf_cmd, arg->hf_resplen ) ;
return( GT_ACK(fd, request, arg->hf_resp ) ) ;
}


/*************** GT_ACK FUNCTION ******************************/
static GT_ACK(fd, req, buf )
        int     fd ;
        int     req ;
        char   *buf ;
{

        struct hfctlack ack ;
        int             i = sizeof( ack ) ;
        int             j = 0 ;
        union {
        char            *c ;
        struct hfctlack *ack ;
        }               p ;

        int             hft_alrm() ;

is_ack_vtd = 0 ;                        /* flag no ACT VTD yet         */

if ( setjmp( hftenv ) )                 /* set environment in case     */
   {                                    /* of time out                 */
   errno=ENODEV ;                       /* if time out, set errno      */
   return( -1 ) ;                       /* flag error                  */
   }

alarm(3) ;                              /* time out in 3 secs          */
sav_alrm = signal( SIGALRM, hft_alrm ) ;/* prepare to catch time out   */

p.ack = &ack ;
while ( ! is_ack_vtd )                  /* do until valid ACK VTD      */
  {
  RD_BUF(fd, p.c, i ) ;                 /* read until a ACK VTD is fill*/

  if ( ! memcmp( &ack, &ACK, sizeof( HFINTROSZ ) ) /* the ACK intro &  */
       && ( ack.hf_request == req ) )   /* is it the response we want ?*/
     {                                  /* yes, ACK VTD found          */
     is_ack_vtd = 1 ;                   /* quickly, flag it            */
     break ;                            /* get the %$%#@ out of here   */
     }

  p.ack = &ack ;                        /* no, then skip 1st           */
  ++p.c ;                               /* char and start over         */
  i = sizeof( ack ) - 1 ;               /* one less ESC to cry over    */

  while( ( *p.c != 0x1b ) && i )        /* scan for next ESC           */
     { ++p.c ; --i ; }                  /* if any                      */

  ( i ? memcpy( &ack, p.c, i ) : 0 ) ;  /* if any left over, then move */
  p.ack = &ack ;                        /* ESC to front of ack struct  */
  p.c += i ;                            /* skip over whats been read   */
  i = sizeof( ack ) - i ;               /* set whats left to be read   */
  }                                     /***** TRY AGAIN               */

alarm(0) ;                              /* ACK VTD received, reset alrm*/
signal( SIGALRM, sav_alrm ) ;           /* reset signal                */

if ( i = ack.hf_arg_len )               /* any data following ?        */
   {                                    /* yes,                        */
   RD_BUF(fd,buf,i) ;                   /* read until it is received   */
   }

if ( errno = ack.hf_retcode )           /* set errno based on returned */
   return (-1) ;                         /* code, if 0, then no error   */
else
   return (0) ;                        /* if set, then error returned */
}

/*************** HFT_ALRM FUNCTION ******************************/
static hft_alrm(sig)                    /* Function hft_alrm - handle  */
        int             sig ;           /* alarm signal               */
{
signal( SIGALRM, sav_alrm ) ;           /* reset to previous          */

if ( is_ack_vtd )                       /* has ack vtd arrived ?      */
   return(0) ;                          /* yes, then continue         */
else                                    /* no, then return with error */
   longjmp( hftenv, -1 ) ;

}

/*********************************************************************/
/***                                                               ***/
/***  NOTE: Both the HFCTLREQ and the arg structure should be      ***/
/***        sent in one io write operation.  If terminal           ***/
/***        emulators are in NODELAY mode then multiple writes     ***/
/***        may cause bogus information to be read by the emulator ***/
/***        depending on the timing.                               ***/
/***                                                               ***/
/*********************************************************************/

static WR_REQ(fd, request, cmdlen, cmd, resplen )
	int             fd ;
	int             request ;
	int             cmdlen ;
	char           *cmd ;
	int             resplen ;
{
	struct {
	char            *c ;
	struct hfctlreq *req ;
	}              p ;
	int            size ;

	req.hf_request = request ;
	req.hf_arg_len = cmdlen ;
	req.hf_rsp_len = resplen ;

if ( cmdlen )                           /* if arg structure to pass    */
   {
   size = sizeof( struct hfctlreq ) + cmdlen ;
   if ( ( p.c = malloc(size) ) == NULL ) /* malloc one area            */
      return( -1 ) ;

   memcpy( p.c, &req, sizeof( req ) ) ; /* copy CTL REQ struct         */
   memcpy( p.c + sizeof( req ), cmd, cmdlen ) ; /* copy arg struct     */
   }
else
   {
   p.req = &req ;                       /* otherwise use only CTL REQ  */
   size = sizeof( req ) ;
   }

					/* write request to terminal   */
if ( write(fd,p.c,size) == -1 ) return (-1) ;
if ( p.req != &req )                    /* free if allocated           */
   free( p.c ) ;
return (0) ;

}