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

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