Main Page   Packages   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Search  

C:/temp/src/j2k/QNX4/driver/par/main.c

Go to the documentation of this file.
00001 
00002 #include <sys/types.h>
00003 #include <sys/_devdrvr.h>
00004 #include <sys/sched.h>
00005 #include <sys/utsname.h>
00006 #include <sys/osinfo.h>
00007 #include <sys/psinfo.h>
00008 #include <sys/kernel.h>
00009 #include <sys/proxy.h>
00010 #include <i86.h>
00011 #include <conio.h>
00012 #include <errno.h>
00013 #include <string.h>
00014 #include <stdlib.h>
00015 #include <unistd.h>
00016 #include <signal.h>
00017 
00018 #include "par.h"
00019 
00020 /*
00021    declare the calls 'dev' will make into driver.
00022 */
00023 int far  Kick  (struct output_buffer far *obuf);
00024 int far  Stty  (struct termios far *tios); 
00025 int far  Ctrl (union ioctl_entry far *ioc); 
00026 
00027 #pragma aux (_dev_call) Kick;
00028 #pragma aux (_dev_call) Stty;
00029 #pragma aux (_dev_call) Ctrl;
00030 
00031 union _printer_msg {
00032    msg_t    type;
00033    msg_t    status;
00034    char     filer[100];
00035    } msg;
00036 
00037 int idle = 1;
00038 volatile int   dangerous = 0;
00039 
00040 unsigned port = 0;
00041 int biosport = 1;
00042 int osize = 1000;
00043 
00044 /* 10 msec nap time */
00045 #define  NAP_TIME 10
00046 #define  NAPS_PER_SEC   (1000/NAP_TIME)
00047 #define  nap() (delay(NAP_TIME))
00048 
00049 unsigned ioport = 0;
00050 unsigned cpu_speed;
00051 long     usec_wait = 1000; /* 1 msec default */
00052 long     io_retry;
00053 
00054 int   check_open = 0;
00055 
00056 int   rtimeout = -1;
00057 struct driver_ctrl drv_ctrl;
00058 struct device_ctrl ctrl;
00059 
00060 char *prefix = "par";
00061 
00062 #define peekch(obuf) (*(obuf)->tail)
00063 #define  abort_output(obuf)   ((obuf)->discard = (obuf)->size)
00064 
00065 int dev_handle;
00066 
00067 void terminate( int signal )
00068    {
00069    if(signal) {
00070       /*
00071        * Shutdown by signal
00072        */
00073       dev_drvr_shutdown( dev_handle );
00074       /*
00075        * We should give back any GDT's, etc. that
00076        * the system doesn't release for us
00077        */
00078       }
00079    exit(0);
00080    }
00081 
00082 main(argc, argv)
00083 int argc; char *argv[];
00084    {
00085    unsigned c;
00086     struct _osinfo osinfo;
00087    int i;
00088    int priority = 9;
00089    struct termios far *tios;
00090 
00091    /*
00092     * Allow only SIGTERM, which we catch and cause
00093     * graceful termination, all others are ignored
00094     */
00095    for( i = _SIGMIN; i <= _SIGMAX; ++i)
00096       if( i != SIGTERM)
00097          signal( i, SIG_IGN );
00098 
00099    signal( SIGTERM, &terminate );
00100 
00101    /*
00102     * Scan arguments
00103     */
00104    while ((c=getopt(argc,argv,"cO:N:p:b:w:s:P:")) != -1) {
00105       switch (c) {
00106       case  'c':
00107          check_open = 1;
00108          break;
00109       case  'O':
00110          osize = strtol(optarg,NULL,0);
00111          break;
00112       case  'N':
00113          prefix = optarg;
00114          break;
00115       case  'p':
00116          ioport = strtol(optarg,NULL,16);
00117          break;
00118       case  'b':
00119          biosport = strtol(optarg,NULL,16);
00120          break;
00121       case  's':
00122          if ((rtimeout = strtol(optarg,NULL,10) * NAPS_PER_SEC) == 0) {
00123             rtimeout = 1;  /* sleep at least once... */
00124             }
00125          break;
00126       case  'w':
00127          usec_wait = strtol(optarg,NULL,0);
00128          break;
00129       case  'P':
00130          priority = strtol(optarg,NULL,0);
00131          break;
00132          }
00133       }
00134 
00135    setscheduler(0, SCHED_FAIR, priority);
00136 
00137    if(ioport == 0) {
00138       ioport = next_printer(biosport);
00139       if(ioport == 0)
00140          exit(0); /* Terminate quietly if no parallel ports */
00141       }
00142 
00143    qnx_osinfo((nid_t) 0, &osinfo);
00144    cpu_speed = osinfo.cpu_speed;
00145    io_retry = (cpu_speed / 100) *  usec_wait;
00146    /*
00147     * Register ourselves with the DEVICE Manager
00148     */
00149 
00150    if((dev_handle = dev_drvr_register("parallel", prefix, 1,
00151                &Kick, &Stty, &Ctrl, &drv_ctrl, 0)) == -1) {
00152       exit(ENFILE);
00153       }
00154 
00155    /*
00156     * Allocate the resources for this device
00157     */
00158 
00159    ctrl.isize = 0;
00160    ctrl.osize = osize;
00161    ctrl.csize = 0;
00162 
00163    if(dev_drvr_mount(dev_handle, drv_ctrl.base_tty, 1, &ctrl)) {
00164       dev_drvr_shutdown( dev_handle );
00165       exit(ENOMEM);
00166       }
00167    
00168    /*
00169     * Initialize 'stty' settings to consistent values
00170     */
00171    ctrl.obuf->mode |= OUTPUT_XNL;
00172 
00173    tios = ctrl.termios;
00174    tios->c_cflag = (CS8);
00175    tios->c_oflag = (OPOST);
00176    tios->c_iflag = 0;
00177    tios->c_lflag = 0;
00178    tios->c_ispeed = 0L;
00179    tios->c_ospeed = 9600L;
00180 
00181    /*
00182     * OUTPUT DRIVER
00183     */
00184 
00185    init_printer(ioport);
00186 
00187    idle = 0;
00188 
00189    port = qnx_proxy_attach(0, 0, 0, -1);
00190 
00191    /*
00192     * Let DEV call us now
00193     */
00194    if(dev_drvr_arm(ctrl.tty)) {
00195       dev_drvr_shutdown( dev_handle );
00196       exit(ENODEV);
00197       }
00198 
00199    /*
00200     * Close off stdin,stdout,stderr since this process
00201     * is usually started in sysinit as a background process,
00202     * by the shell, which typically sets stdin to /dev/null
00203     * (on the machine we booted from), which ties up resources
00204     */
00205    close(0);
00206    close(1);
00207    close(2);
00208 
00209    qnx_pflags( _PPF_SERVER, _PPF_SERVER, 0, 0 );
00210 
00211    
00212    for(;;) {
00213    
00214 #define GAURD(X)  ((dangerous=1),(X),(dangerous=0))
00215 
00216       GAURD(idle = (ctrl.obuf->size == 0));
00217       if (idle) {
00218          /*
00219           * If nothing to print (at this time)
00220           * then set flag and wait for DEV to Kick us
00221           */
00222          wait_msg(port);
00223          continue;      
00224          }
00225       if (flush_buffer(ctrl.obuf)) {
00226          continue;
00227          }
00228       /*
00229        * Get the next character to print
00230        * from the output buffer
00231        */
00232       if ((c=peekch(ctrl.obuf)) == '\n' && (ctrl.obuf->mode & OUTPUT_XNL)) {
00233          if (outch('\r',ctrl.obuf) == -1) {  /* failed on a write */
00234             abort_output(ctrl.obuf);
00235             continue;
00236             }
00237          }
00238       if (outch(c,ctrl.obuf) == -1) {
00239          abort_output(ctrl.obuf);
00240          continue;
00241          }
00242       /*
00243       * If we broke out because of a request to flush
00244       * output, then start the loop over without printing
00245       * this character
00246       */
00247       advance(ctrl.obuf);
00248       }
00249    }
00250 
00251 short prtready(port,strict)
00252    {
00253    short c;
00254 
00255    c = inp(port+REG_STAT);
00256    return strict ?
00257          (c&STATUS_MASK) == STATUS_OK :
00258          (c&NOTBUSY) == NOTBUSY;
00259    }
00260 
00261 
00262 outch(int ch, const struct output_buffer far *obuf)
00263    {
00264    int   tick;
00265    long  x;
00266 
00267    /*
00268     * Wait (possible forever) for BUSY to go off
00269     */
00270    for (tick=rtimeout,x=io_retry;  !prtready(ioport,0);) {
00271       if (obuf->discard)
00272          return -1;
00273       if (x--)
00274          continue;
00275       x = io_retry;
00276       nap();
00277       if (tick != -1) {
00278          if (--tick == 0) {
00279             return -1;
00280             }
00281          }
00282       }
00283    /*
00284     * Write the character
00285     */
00286    outp(ioport, ch);
00287 
00288    /*
00289     * Pulse the strobe line
00290     */
00291    udelay(2);
00292 
00293    outp(ioport + REG_CNTL, 0x0D );
00294    udelay(1); /* Wait a bit (scaled on CPU speed) */
00295    outp(ioport + REG_CNTL, 0x0C );
00296    udelay(2);
00297    return 0;
00298    }  
00299 
00300 /*
00301  * Kick is called by DEV everytime something "new" happens
00302  * to the output buffer
00303  *
00304  * It will set 'obuf' to be the output buffer
00305  * It will also set ds to be the data segment of the driver being called
00306  *
00307  * Since this routine is "called" by DEV, it will ALWAYS run at higher
00308  * priority than the driver task, so cannot be interrupted.
00309  */
00310 
00311 int far Kick (struct output_buffer far *obuf)   {
00312    if(obuf->size > 0) {
00313       if(idle || dangerous) {
00314          idle = 0;
00315          Trigger(port);
00316          }
00317       return(1);
00318       }
00319    return(0);
00320    }
00321 
00322 /*
00323  * Stty is called by DEV to indicate a significant change in the
00324  * termios control structure (baud rate, modem control)
00325  *
00326  * It will set 'tios' to be a far pointer to the termios entry
00327  * It will also set ds to be the data segment of the driver being called
00328  *
00329  * Since this routine is "called" by DEV, it will ALWAYS run at higher
00330  * priority than the driver task, so cannot be interrupted.
00331  */
00332 
00333 
00334 int far Stty (struct termios far *tios)
00335    {
00336    unsigned cflags;
00337 
00338    /*
00339     * Use 'tios' to keep the compiler happy
00340     */
00341    cflags = tios->c_cflag;
00342 
00343    return(0);
00344    }
00345 
00346 /*
00347  * Ctrl is called by DEV to indicate a high level
00348  * control function
00349  *
00350  * It will set 'ioc' to be an ioctl control block
00351  * It will also set ds to be the data segment of the driver being called
00352  *
00353  * Since this routine is "called" by DEV, it will ALWAYS run at higher
00354  * priority than the driver task, so cannot be interrupted.
00355  */
00356 
00357 int far Ctrl (union ioctl_entry far *ioc)
00358    {
00359    int type;
00360 
00361    type = ioc->type;
00362    ioc->status = IOCTL_ERROR;
00363    switch (type) {
00364    case  IOCTL_OPEN:
00365       ioc->status = (check_open && !prtready(ioport,1)) ? IOCTL_NONE_FREE
00366                : IOCTL_OK;
00367       return(0);
00368    case  IOCTL_CLOSE:
00369       ioc->status = IOCTL_OK;
00370       return(0);
00371    case  IOCTL_CTL:  
00372       {
00373          unsigned unit = ioc->user.unit;
00374          unsigned char bits, mask, oldbits;
00375 
00376          if(unit > 1  ||  unit <= 0) {
00377             ioc->status = IOCTL_BAD_UNIT;
00378             return(0);
00379             }
00380          
00381          mask = ioc->user.data[4];
00382          bits = ioc->user.data[0];
00383          _disable();
00384          oldbits = inp( ioport + REG_STAT );
00385          outp( ioport + REG_STAT, (oldbits & ~mask) | (bits & mask));
00386          _enable();
00387          ioc->user_return.data[0] = oldbits;
00388 
00389          mask = ioc->user.data[5];
00390          bits = ioc->user.data[1];
00391          _disable();
00392          oldbits = inp( ioport + REG_CNTL );
00393          outp( ioport + REG_CNTL, (oldbits & ~mask) | (bits & mask));
00394          _enable();
00395          ioc->user_return.data[1] = oldbits;
00396 
00397          ioc->user_return.data[2] = 0;
00398          ioc->user_return.data[3] = 0;
00399          ioc->user_return.nbytes = 4;
00400          ioc->user_return.status = IOCTL_OK;
00401          return(0);
00402          }
00403       }
00404    return(-1);
00405    }
00406 
00407 next_printer(unsigned n) {
00408    unsigned far *port;
00409 
00410    port = MK_FP(0x0040, (2*(n-1))+0x0008);
00411    n = *port;
00412    return(n);
00413    }
00414 
00415 
00416 init_printer(port)
00417 unsigned port;
00418    {
00419    outp(port + REG_CNTL, 0x0C );
00420    return(0);
00421    }
00422 
00423 
00424 /*
00425  * Attempt to busy-wait for a number of microseconds
00426  */
00427 
00428 udelay(usec)
00429 unsigned usec;
00430    {
00431    unsigned i, u;
00432 
00433    for(i = 0; i < usec; ++i) {
00434       for(u = 0; u < cpu_speed; u+= 100)
00435          ;
00436       }
00437    return(0);
00438    }
00439 
00440 wait_msg(pid_t port)
00441    {
00442    pid_t pid;
00443    int nbytes;
00444    extern int sys_msg(void *);
00445 
00446    while(1) {
00447       /*
00448        * Consume all messages from processes
00449        */
00450       if ((pid = Receive(0, &msg, sizeof(msg))) == port)
00451          break;
00452       /*
00453        * Otherwise, respond to message and wait for proxy
00454        */
00455       nbytes = 1;
00456       if(msg.type == 0)
00457          nbytes = sys_msg(&msg);
00458       else
00459          msg.status = ENOSYS;
00460       if(nbytes)
00461          Reply(pid, &msg, nbytes);
00462       }
00463    }
00464 
00465 flush_buffer(struct output_buffer far *obuf)
00466    {
00467    int   i;
00468    int   n;
00469 
00470    _disable();
00471    if((n=obuf->discard) == 0) {
00472       _enable();
00473       return 0;
00474       }
00475    /*
00476     * Discard some (or all) data instead of displaying it
00477     */
00478    obuf->discard = 0;
00479    obuf->size -= n;
00480    _enable();
00481       
00482    i = &obuf->buffer[obuf->length] - obuf->tail;
00483    if(i > n)
00484       obuf->tail += n;
00485    else
00486       obuf->tail = &obuf->buffer[n-i];
00487 
00488    low_water(obuf);
00489    return 1;
00490    }
00491 
00492 advance(struct output_buffer far *obuf)
00493    {
00494    /*
00495     * Advance tail pointer after character has been printed
00496     */
00497    ++obuf->tail;
00498    if(obuf->tail >= &obuf->buffer[obuf->length])
00499       obuf->tail = &obuf->buffer[0];
00500 
00501    /*
00502     * Decrement the queue size
00503     */
00504    _disable();
00505    --obuf->size;
00506 
00507    /*
00508     * If size of buffer drops below notification threshold,
00509     * inform DEV of the new information
00510     */
00511    low_water(obuf);
00512    return obuf->size != 0;
00513    } 
00514    
00515 low_water(struct output_buffer far *obuf)
00516    {
00517    /*
00518     * Inform DEV if the output buffer is now
00519     * below the notification threshold
00520     */
00521    _disable();
00522    if(obuf->size < obuf->bcount) {
00523       obuf->bcount = 0;
00524       obuf->action |= ACT_OUTPUT_READY;
00525       _enable();
00526       Trigger(drv_ctrl.hw_pid);
00527       }
00528    else
00529       _enable();
00530    return 1;
00531    }

Generated on Sun Oct 14 18:46:41 2001 for Standard J2K Library by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001