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

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

Go to the documentation of this file.
00001 /*
00002  * Sample QNX4 Device Driver
00003  *
00004  * The purpose of this file is to provide a working QNX4
00005  * device driver which can be used as the basis for developing
00006  * "real" drivers. It is assumed that a "real" driver would be
00007  * interfacing to some "real" hardware somewhere, rather than
00008  * using stdin/stdout.
00009  *
00010  * One point worth mentioning is that "most" hardware drivers
00011  * will provide input into the Device subsystem directly from
00012  * the input interrupt handler (see Dev.ser source for an
00013  * example of this). This sample driver shows how to input
00014  * data at "process time".
00015  *
00016  * On the other hand, it is NOT uncommon for a "real" driver to
00017  * output data at process time as is the case in this example.
00018  * (for example Dev.con, Dev.win, Dev.par all output data at
00019  * process time).
00020  */
00021 
00022 #include <sys/types.h>
00023 #include <sys/sched.h>
00024 #include <sys/kernel.h>
00025 #include <sys/proxy.h>
00026 #include <sys/psinfo.h>
00027 #include <stdlib.h>
00028 #include <unistd.h>
00029 #include <errno.h>
00030 #include <signal.h>
00031 
00032 #include <sys/_devdrvr.h>
00033 
00034 extern int far Kick ( struct output_buffer far * obuf );
00035 extern int far Stty ( struct termios       far * tios ); 
00036 extern int far Ctrl ( union  ioctl_entry   far * ioc  ); 
00037 
00038 extern int sys_msg( void * );
00039 
00040 union _private_msg {
00041   msg_t  type;
00042   msg_t  status;
00043   char   filer[100];
00044 } msg;
00045 
00046 int idle = 1;
00047 int more = 0;
00048 
00049 pid_t out_proxy;
00050 pid_t in_proxy;
00051 pid_t proxy;
00052 
00053 unsigned isize = 2048;
00054 unsigned osize = 2048;
00055 unsigned csize = 256;
00056 
00057 #define MAX_DEVICES 1
00058 
00059 struct driver_ctrl drv_ctrl;
00060 struct device_ctrl ctrl[MAX_DEVICES];
00061 
00062 int dev_handle;
00063 int num_devices = 1;
00064 
00065 unsigned driver_options = 0;  /* found in <sys/_devdrvr.h> */
00066 
00067 char* prefix = "Board";
00068 
00069 int main(int argc, char* argv[] ) {
00070   unsigned c;
00071   int i;
00072   pid_t pid;
00073   int t;
00074   int nbytes;
00075 
00076   extern void terminate();
00077 
00078   setscheduler(0, SCHED_FIFO, 15);
00079 
00080   /*
00081    * Allow only SIGTERM, which we catch and cause
00082    * graceful termination, all others are ignored
00083    */
00084    for( i = _SIGMIN; i <= _SIGMAX; ++i)
00085      if ( i != SIGTERM)
00086        signal( i, SIG_IGN );
00087 
00088    signal( SIGTERM, &terminate );
00089 
00090    /*
00091     * Scan arguments
00092     */
00093    while(  ( c=getopt(argc,argv,"C:I:O:N:n:") ) != -1  ) {
00094      switch (c) {
00095        case 'C':
00096          csize = strtol(optarg,NULL,0);
00097          break;
00098        case 'I':
00099          isize = strtol(optarg,NULL,0);
00100          break;
00101 
00102        case 'O':
00103          osize = strtol(optarg,NULL,0);
00104          break;
00105 
00106        case 'N':
00107          prefix = optarg;
00108          break;
00109 
00110        case 'n':
00111          num_devices = strtol(optarg,NULL,0);
00112          if (num_devices > MAX_DEVICES)
00113            num_devices = MAX_DEVICES;
00114            break;
00115 
00116      }
00117    }
00118 
00119    /*
00120     * Register ourselves with the DEVICE Manager
00121     */
00122 
00123    if ( ( dev_handle = dev_drvr_register( "custom", prefix, num_devices,
00124           &Kick, &Stty, &Ctrl, &drv_ctrl, driver_options )
00125         ) == -1 ) {
00126         exit ( ENFILE );
00127       }
00128 
00129    /*
00130     * Allocate the resources for this device
00131     */
00132 
00133     for( i = 0; i < num_devices; i++ ) {
00134       ctrl[i].isize = isize;
00135       ctrl[i].osize = osize;
00136       ctrl[i].csize = csize;
00137     }
00138 
00139     if (  dev_drvr_mount( dev_handle,  drv_ctrl.base_tty,
00140                          num_devices, &ctrl[0] )  )
00141     {
00142       dev_drvr_shutdown( dev_handle );
00143       exit(ENOMEM);
00144     }
00145 
00146    out_proxy = qnx_proxy_attach(0, 0, 0, -1);
00147     in_proxy  = qnx_proxy_attach(0, 0, 0, -1);
00148 
00149 #ifndef DEBUGMODE
00150    /*
00151     * Close off stdin,stdout,stderr since this process
00152     * is usually started in sysinit as a background process,
00153     * by the shell, which typically sets stdin to /dev/null
00154     * (on the machine we booted from), which ties up resources
00155     */
00156    close(0);
00157    close(1);
00158    close(2);
00159 #endif
00160 
00161    /*
00162     * Tell Proc that we will respond to "sin ver" messages
00163     */
00164    qnx_pflags( _PPF_SERVER, _PPF_SERVER, 0, 0 );
00165 
00166    /*
00167     * Initialize termios and queue parameters
00168     * to whatever defaults make sense for this class of device
00169     */
00170    
00171     for( i = 0; i < num_devices; i++ )
00172     {
00173       /* struct input_buffer far *ibuf; */
00174         struct output_buffer far * obuf;
00175         struct termios       far * tios;
00176 
00177       obuf = ctrl[i].obuf;
00178       obuf->mode |= OUTPUT_XNL;
00179 
00180       tios = ctrl[i].termios;
00181 
00182       tios->c_ispeed = tios->c_ospeed = 9600;
00183 
00184       tios->c_cflag = (CREAD);
00185       tios->c_oflag = (OPOST);
00186       tios->c_iflag = (ICRNL|IXON|BRKINT);
00187       tios->c_lflag = (ICANON|ISIG|ECHO|ECHOE|ECHOK|IEXTEN);
00188 
00189       tios->c_cc[VEOF]  = 0x04;
00190       tios->c_cc[VEOL]  = 0x00;
00191       tios->c_cc[VERASE]   = 0x7F;
00192       tios->c_cc[VINTR] = 0x03;
00193       tios->c_cc[VKILL] = 0x18;
00194       tios->c_cc[VQUIT] = 0x00;
00195       tios->c_cc[VSUSP] = 0x00;
00196       tios->c_cc[VSTART]   = 0x11;
00197       tios->c_cc[VSTOP] = 0x13;
00198 
00199       tios->c_cc[VMIN]  = 0x01;
00200       tios->c_cc[VTIME] = 0x00;
00201     }
00202 
00203    /*
00204     * Initialize hardware
00205     */
00206 
00207    init_driver();
00208 
00209 
00210    /*
00211     * Let DEV call us now
00212     */
00213     for(i = 0; i < num_devices; i++) {
00214       if ( dev_drvr_arm(ctrl[i].tty) )
00215       {
00216         dev_drvr_shutdown( dev_handle );
00217         exit(ENODEV);
00218       }
00219     }
00220 
00221 
00222    /*
00223     * Main loop
00224     */
00225    
00226    for(;;) {
00227    
00228       pid = Receive( 0, &msg, sizeof(msg) );
00229 
00230         if ( pid == out_proxy )
00231         {
00232           idle = 1;
00233 
00234          /*
00235           * Output data now available
00236           */
00237 
00238           flush_output();
00239           continue;
00240         }
00241 
00242         if ( pid == in_proxy )
00243         {
00244 
00245          /*
00246           * Input data is available
00247           * NOTE: that this would "normally" be taken care of
00248           *       by an interrupt handler
00249           */
00250 
00251           input_ready();
00252           continue;
00253         }
00254 
00255       /*
00256        * Otherwise, process a message from a process
00257        */
00258 
00259       t = msg.type;
00260       msg.status = ENOSYS;
00261       nbytes = sizeof(msg.status);
00262 
00263       switch(t) {
00264 
00265       case 0:
00266          nbytes = sys_msg(&msg);
00267          break;
00268 
00269       default:
00270          break;
00271         }
00272 
00273         if (nbytes) {
00274          Reply(pid, &msg, nbytes);
00275         }
00276 
00277         continue;
00278 
00279     } // End of for(;;)
00280 }
00281 
00282 
00283 void terminate( int signal ) {
00284   if (signal) {
00285    /*
00286     * Shutdown by signal
00287     */
00288 
00289     dev_drvr_shutdown( dev_handle );
00290 
00291     /*
00292      * We should give back any GDT's, etc. that
00293      * the system doesn't release for us
00294      */
00295 
00296      exit_driver();
00297   }
00298 
00299   exit(0);
00300 }
00301 
00302 /*
00303  * Process all input data in all devices
00304  * Only return when all input is exhausted.
00305  * Rely on a subsequent Interrupt (which triggers 'in_proxy') to wake us up.
00306  */
00307 
00308 int input_ready() {
00309   pid_t proxy;
00310   int i;
00311   int n;
00312   char buf[100];
00313 
00314   proxy = 0;
00315 
00316   /*
00317    * Scan all devices looking for available data
00318    */
00319 
00320   for( i = 0; i < num_devices; ++i ) {
00321     while( (n = get_data(i, &buf[0], sizeof(buf))) > 0 ) {
00322       if(drv_ctrl.ttim_offset != 0)
00323       {
00324         /*
00325          * Use multiple character input routine if supported by Dev
00326          */
00327 
00328          pid_t (far *ttimcall) (int tty, int len, char far *data, unsigned ds);
00329          ttimcall = MK_FP( FP_SEG(drv_ctrl.tti), drv_ctrl.ttim_offset );
00330          proxy |= (*ttimcall) (ctrl[i].tty, n, &buf[0], drv_ctrl.tti_ds);
00331        } else {
00332         /*
00333          * Must inject character at a time for older Dev's
00334          */
00335 
00336          int j;
00337          for(j = 0; j < n; ++j)
00338            proxy |= (*drv_ctrl.tti) (buf[j], ctrl[i].tty, drv_ctrl.tti_ds);
00339        }
00340     }
00341   }
00342 
00343   /*
00344    * "wake up" Dev if ANYTHING of interest happened
00345    */
00346    if(proxy)
00347      Trigger(proxy);
00348 
00349    return(0);
00350 }
00351 
00352 /*
00353  * This function will print forever, only returning
00354  * when all output buffers are drained
00355  * Rely on a subsequent Kick() call to wake us up again
00356  *
00357  * NOTE: that the memory semaphores 'idle' and 'more' are updated
00358  *       by the far-call stubs (ie: Kick) to make this work efficiently
00359  */
00360 
00361 flush_output() {
00362   struct output_buffer far *obuf;
00363   char far * tail;
00364   char far * end;
00365   char far * begin;
00366   int i;
00367   int n;
00368   int size;
00369   int nothing;
00370   int unit;
00371   int expand_newlines;
00372 
00373   for(;;) {
00374       /*
00375        * Scan every output queue, looking for something to do
00376        */
00377       nothing = 0;
00378       more = 0;
00379       for(unit = 0; unit < num_devices; ++unit) {
00380 
00381          obuf = ctrl[unit].obuf;
00382 
00383          /*
00384           * Process flow control output functions first
00385           */
00386 
00387          if(obuf->mode & OUTPUT_HFLOW_OFF) {
00388             obuf->mode &= ~OUTPUT_HFLOW_OFF;
00389             drop_hw(unit);
00390             }
00391    
00392          if(obuf->mode & OUTPUT_HFLOW_ON) {
00393             obuf->mode &= ~OUTPUT_HFLOW_ON;
00394             raise_hw(unit);
00395             }
00396 
00397          if(obuf->mode & OUTPUT_XOFF) {
00398             obuf->mode &= ~OUTPUT_XOFF;
00399             /*
00400              * Disable input by sending XOFF
00401                 */
00402             put_data(unit, (char far *) "\023", 1, 0);
00403             }
00404    
00405          if(obuf->mode & OUTPUT_XON) {
00406             obuf->mode &= ~OUTPUT_XON;
00407             /*
00408              * Re-enable input by sending XON
00409              */
00410             put_data(unit, (char far *) "\021", 1, 0);
00411             }
00412    
00413          /*
00414           * Skip if no data characters available
00415           */
00416 
00417          _disable();
00418          if(obuf->size == 0  ||
00419                (obuf->mode & (OUTPUT_STOPPED|OUTPUT_STOPPED_HW)) != 0) {
00420             _enable();
00421             ++nothing;
00422             continue;
00423             }
00424          _enable();
00425    
00426          if(obuf->discard) {
00427             /*
00428              * Discard some (or all) data instead of displaying it
00429              */
00430             n = obuf->discard;
00431             _disable();
00432             obuf->discard -= n;
00433             obuf->size -= n;
00434             _enable();
00435             i = &obuf->buffer[obuf->length] - obuf->tail;
00436             if(i > n)
00437                obuf->tail += n;
00438             else
00439                obuf->tail = &obuf->buffer[n-i];
00440             }
00441 
00442          /*
00443           * Extract the data from the buffer
00444           */
00445 
00446          tail = obuf->tail;
00447          end = &obuf->buffer[obuf->length];
00448          begin = &obuf->buffer[0];
00449          size = obuf->size;
00450 
00451          expand_newlines = obuf->mode & OUTPUT_XNL;
00452 
00453          /*
00454           * Calculate number of chars before wrap-around point
00455           */
00456          i = end - tail;
00457          if(i >= size) { /* No wrap around */
00458             n = put_data(unit, tail, size, expand_newlines);
00459             }
00460          else {
00461             n = put_data(unit, tail, i, expand_newlines);
00462             n += put_data(unit, begin, size - i, expand_newlines);
00463             }
00464 
00465          /*
00466           * Update the Queue pointers, now that the
00467           * 'n' bytes of data has been extracted
00468           */
00469 
00470          _disable();
00471 
00472          if(i > n) /* No wrap around */
00473             obuf->tail = tail + n;
00474          else
00475             obuf->tail = begin + (n-i);
00476          obuf->size -= n;
00477          /*
00478           * Compensate for any flushed data which
00479           * was in the process of being transmitted
00480           */
00481          if(obuf->discard > n)
00482             obuf->discard -= n;
00483          else
00484             obuf->discard = 0;
00485 
00486          _enable();
00487    
00488          /*
00489           * If size of buffer drops below notification threshold,
00490           * inform DEV of the new information
00491           */
00492          _disable();
00493          if(obuf->size < obuf->bcount) {
00494             obuf->bcount = 0;
00495             obuf->action |= ACT_OUTPUT_READY;
00496             _enable();
00497             Trigger(drv_ctrl.hw_pid);
00498             }
00499          else
00500             _enable();
00501          }
00502    
00503       /*
00504        */
00505       _disable();
00506       if(nothing >= num_devices  &&  more == 0) {
00507          idle = 1;
00508          _enable();
00509          return;
00510          }
00511       else
00512          _enable();
00513       }
00514    }
00515 
00516 
00517 
00518 /*******************************************************************
00519 
00520  Hardware specific functions
00521 
00522  [add "useful" stuff here]
00523 
00524  ******************************************************************/
00525 
00526 
00527 int init_driver()
00528    {
00529 #ifdef DEBUGMODE
00530    old_mode = dev_mode( 0, 0, _DEV_MODES);
00531    dev_arm( 0, in_proxy, _DEV_EVENT_RXRDY );
00532 #else
00533    /* Your stuff here */
00534 #endif
00535    return(0);
00536    }
00537 
00538 
00539 
00540 int exit_driver()
00541    {
00542 #ifdef DEBUGMODE
00543    dev_mode( 0, old_mode, _DEV_MODES);
00544 #else
00545    /* Your stuff here */
00546 #endif
00547    return(0);
00548    }
00549 
00550 
00551 
00552 get_data(int unit, char *buf, int nbytes)
00553    {
00554    /*
00555     * Get (at most) 'nbytes' of data from 'unit' (into 'buf').
00556     * Return #bytes read.
00557     */
00558    int n = 0;
00559 
00560    unit = unit; /* keep compiler happy */
00561 
00562 #ifdef DEBUGMODE
00563    n = dev_read(0, buf, nbytes, 0, 0, 0, 0, 0);
00564    dev_arm( 0, in_proxy, _DEV_EVENT_RXRDY );
00565 #else
00566    /* Your stuff here */
00567 #endif
00568 
00569    return(n);
00570    }
00571 
00572 
00573 
00574 put_data(int unit, char far *buf, int nbytes, int expand_newlines)
00575    {
00576    /*
00577     * Output 'nbytes' of data (in 'buf') to 'unit'.
00578     * Return #bytes written (before expansion).
00579     */
00580 #ifdef DEBUGMODE
00581    int i;
00582    char c;
00583 
00584    unit = unit; /* keep compiler happy */
00585 
00586    for(i = 0; i < nbytes; ++i) {
00587       c = *buf++;
00588       if(expand_newlines  &&  c == '\n')
00589          write(1, "\r", 1);
00590       write(1, &c, 1);
00591       }
00592 #else
00593    /* Your stuff here */
00594 #endif
00595    return(nbytes);
00596    }
00597 
00598 
00599 
00600 void drop_hw(int unit) {
00601    /*
00602     * Disable input by dropping Hardware handshaking
00603     */
00604    unit = unit; /* keep compiler happy */
00605 #ifndef DEBUGMODE
00606    /* Your stuff here */
00607 #endif
00608    }
00609 
00610 
00611 
00612 void raise_hw(int unit) {
00613    /*
00614     * Re-enable input by raising Hardware handshaking
00615     */
00616    unit = unit; /* keep compiler happy */
00617 #ifndef DEBUGMODE
00618    /* Your stuff here */
00619 #endif
00620    }
00621 
00622 
00623 #if 0
00624 
00625 /************************************************************************
00626  * Sample interrupt handler                                             *
00627  ************************************************************************/
00628 
00629 #include "../_devdrvr.h"
00630 #include <sys/trace.h>
00631 #include <sys/tracecod.h>
00632 
00633 /*
00634  * Stack checking MUST be disabled in irq handlers
00635  */
00636 
00637 #pragma off (check_stack);
00638 
00639 pid_t async_int(int irq) {
00640    extern pid_t (far *tti)(int, int, unsigned); /* from dev_drvr_register */
00641    extern unsigned tti_ds;                 /* from dev_drvr_register */
00642    pid_t status = 0;
00643    unsigned char *data;
00644    int nbytes = 0;
00645    int irq_type = 0;
00646    unsigned short c;
00647    unsigned iobase = 0;
00648 
00649    switch(irq_type) {
00650 
00651    case 0:  /* Good data received */
00652       /*
00653        * receive 'nbytes' of data ponted to by 'data'
00654        */
00655       while(nbytes--) {
00656          c = (unsigned short) *data++;
00657          status |= (*tti) (c, dev->tty, tti_ds);
00658          }
00659       break;
00660 
00661    case 1: /* Bad data - parity error */
00662       status |= (*tti) (*data | RCV_PARITY, dev->tty, tti_ds);
00663       Trace1( (long)_TRACE_DEV_SER_PARITY, _TRACE_TRANSIENT, iobase );
00664       break;
00665 
00666    case 2: /* Bad data - framing error */
00667       status |= (*tti) (*data | RCV_FRAME, dev->tty, tti_ds);
00668       Trace1( (long)_TRACE_DEV_SER_FRAME, _TRACE_TRANSIENT, iobase );
00669       break;
00670 
00671    case 3: /* Bad data - overrun */
00672       status |= (*tti) (*data | RCV_OVERRUN, dev->tty, tti_ds);
00673       Trace1( (long)_TRACE_DEV_SER_OVERRUN, _TRACE_TRANSIENT, iobase );
00674       break;
00675 
00676    case 4: /* Break detected */
00677       status |= (*tti) (*data | RCV_BREAK, dev->tty, tti_ds);
00678       break;
00679 
00680    case 5: /* Raised Carrier */
00681       status |= (*tti) (RCV_CARRIER, dev->tty, tti_ds);
00682       Trace1( _TRACE_DEV_SER_CARRIER, _TRACE_EXPECTED, dev->iobase );
00683       break;
00684 
00685    case 6: /* Lost Carrier */
00686       status |= (*tti) (RCV_HNGUP, dev->tty, tti_ds);
00687       Trace1( _TRACE_DEV_SER_HUP, _TRACE_EXPECTED, dev->iobase );
00688       break;
00689 
00690    case 7: /* Resume Transmission (hardware handshaking) */
00691       status |= (*tti) (RCV_HW_ON, dev->tty, tti_ds);
00692       break;
00693 
00694    case 8: /* Stop Transmission (hardware handshaking) */
00695       status |= (*tti) (RCV_HW_OFF, dev->tty, tti_ds);
00696       break;
00697       }
00698 
00699    return(status);
00700    }
00701 
00702 #pragma on (check_stack);
00703 
00704 #endif

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