ARPDAS_QNX6 1.0
serusb.c
Go to the documentation of this file.
00001 #include <errno.h>
00002 #include <stdio.h>
00003 #include <stddef.h>
00004 #include <stdlib.h>
00005 #include <string.h>
00006 #include <unistd.h>
00007 #include <sys/iofunc.h>
00008 #include <sys/dispatch.h>
00009 #include <fcntl.h>
00010 #include <ctype.h>
00011 #include "serusb.h"
00012 #include "nl_assert.h"
00013 
00014 static char sb_ibuf[SB_SERUSB_MAX_REQUEST];
00015 static int sb_ibuf_idx = 0;
00016 static sbd_request_t sbdrq[SUBBUSD_MAX_REQUESTS];
00017 static sbd_request_t *cur_req;
00018 static unsigned int sbdrq_head = 0, sbdrq_tail = 0;
00019 static int sb_fd;
00020 static struct sigevent ionotify_event;
00021 static timer_t timeout_timer;
00022 static struct itimerspec timeout_enable, timeout_disable;
00023 static int n_timeouts = 0;
00024 
00025 static int n_writes = 0;
00026 static int n_reads = 0;
00027 static int n_part_reads = 0;
00028 static int n_compound_reads = 0;
00029 
00030 static void dequeue_request( signed short status, int n_args,
00031   unsigned short arg0, unsigned short arg1, char *s );
00032 
00033 static void set_timeout( int enable ) {
00034   if ( timer_settime( timeout_timer, 0,
00035           enable ? &timeout_enable : &timeout_disable,
00036           NULL ) == -1 ) {
00037     nl_error( 4, "Error setting timer: %s",
00038       strerror(errno) );
00039   }
00040 }
00041 
00042 // Transmits a request if the currently queued
00043 // request has not been transmitted.
00044 static void process_request(void) {
00045   int cmdlen, n;
00046   int no_response = 0;
00047   sbd_request_t *sbr;
00048   while ( sbdrq_head != sbdrq_tail && cur_req == NULL ) {
00049     nl_assert( sbdrq_head < SUBBUSD_MAX_REQUESTS );
00050     sbr = &sbdrq[sbdrq_head];
00051     nl_assert( sbr->status == SBDR_STATUS_QUEUED );
00052     switch (sbr->type) {
00053       case SBDR_TYPE_INTERNAL:
00054         switch (sbr->request[0]) {
00055           case '\n': // NOP
00056           case 'V':  // Board Revision
00057             break;
00058           default:
00059             nl_error( 4, "Invalid internal request" );
00060         }
00061         break;
00062       case SBDR_TYPE_CLIENT:
00063         switch (sbr->request[0]) {
00064           case 'T':
00065             no_response = 1; break;
00066           case 'A':
00067           case 'R':
00068           case 'M':
00069           case 'W':
00070           case 'V':
00071           case 'S':
00072           case 'C':
00073           case 'B':
00074           case 'i':
00075           case 'u':
00076           case 'D':
00077           case 'F':
00078           case 'f':
00079             break;
00080           default:
00081             nl_error( 4, "Invalid client request: '%c'", sbr->request[0] );
00082         }
00083         break;
00084       default:
00085         nl_error(4, "Invalid request type" );
00086     }
00087     cmdlen = strlen( sbr->request );
00088     nl_error(-2, "Request: '%*.*s'", cmdlen-1, cmdlen-1, sbr->request );
00089     n = write(sb_fd, sbr->request, cmdlen);
00090     ++n_writes;
00091     nl_assert( n == cmdlen );
00092     sbr->status = SBDR_STATUS_SENT;
00093     cur_req = sbr;
00094     if ( no_response )
00095       dequeue_request( SBS_OK, 0, 0, 0, "" );
00096     else set_timeout(1);
00097   }
00098 }
00099 
00100 /**
00101  * This is where we serialize the request.
00102  */
00103 static void enqueue_sbreq( int type, int rcvid, char *req,
00104         unsigned short n_reads ) {
00105   sbd_request_t *sbr = &sbdrq[sbdrq_tail];
00106   int i;
00107   int new_tail = sbdrq_tail+1;
00108   int old_tail;
00109   if ( new_tail >= SUBBUSD_MAX_REQUESTS ) new_tail = 0;
00110   if ( new_tail == sbdrq_head )
00111     nl_error( 4, "Request queue overflow" );
00112   for ( i = 0; i < SB_SERUSB_MAX_REQUEST; ) {
00113     if ( req[i] == '\n' ) {
00114       ++i;
00115       break;
00116     } else if ( req[i] == '\0' ) {
00117       break;
00118     } else ++i;
00119   }
00120   if ( i >= SB_SERUSB_MAX_REQUEST )
00121     nl_error( 4, "Request exceeds %d characters", SB_SERUSB_MAX_REQUEST-1 );
00122   sbr->type = type;
00123   sbr->rcvid = rcvid;
00124   strncpy(sbr->request, req, i);
00125   sbr->request[i] = '\0';
00126   nl_error( -2, "Enqueued: '%*.*s'", i-1, i-1, sbr->request );
00127   sbr->status = SBDR_STATUS_QUEUED;
00128   sbr->n_reads = n_reads;
00129   old_tail = sbdrq_tail;
00130   sbdrq_tail = new_tail;
00131   /* If the queue was empty, process this first request */
00132   if ( sbdrq_head == old_tail ) process_request();
00133 }
00134 
00135 static int sb_data_arm(void) {
00136   int cond;
00137   cond = ionotify( sb_fd, _NOTIFY_ACTION_POLLARM,
00138     _NOTIFY_COND_INPUT, &ionotify_event );
00139   if ( cond == -1 )
00140     nl_error( 3, "Error from ionotify: %s", strerror(errno));
00141   return cond;
00142 }
00143 
00144 /**
00145  Parses the input string for a hexadecimal integer.
00146  @return zero on failure.
00147  */
00148 static int read_hex( char **sp, unsigned short *arg ) {
00149   char *s = *sp;
00150   unsigned short val = 0;
00151   if ( ! isxdigit(*s) )
00152     return 0;
00153   while ( isxdigit(*s) ) {
00154     val *= 16;
00155     if ( isdigit(*s) )
00156       val += *s - '0';
00157     else
00158       val += tolower(*s) - 'a' + 10;
00159     ++s;
00160   }
00161   *arg = val;
00162   *sp = s;
00163   return 1;
00164 }
00165 
00166 /**
00167  * Sends the response to the client (if any) and
00168  * removes it from the queue. Initiates
00169  * processing of the next command if one is waiting.
00170  * Current assumption:
00171  *    n_args maps 1:1 onto SBRT_ codes
00172  *    n_args == 3 is only for 'V' request/response
00173  *    n_args == 4 is only for 'M' request/response
00174  * We need to parse the 'M' response here rather than in process_response()
00175  * because we need direct access to the reply structure.
00176  */
00177 static void dequeue_request( signed short status, int n_args,
00178   unsigned short arg0, unsigned short arg1, char *s ) {
00179   int rv, rsize = 0;
00180   subbusd_rep_t rep;
00181 
00182   nl_assert( cur_req != NULL);
00183   set_timeout(0);
00184   rep.hdr.status = status;
00185   switch (n_args) {
00186     case 0:
00187       rep.hdr.ret_type = SBRT_NONE;
00188       rsize = sizeof(subbusd_rep_hdr_t);
00189       break;
00190     case 1:
00191       rep.hdr.ret_type = SBRT_US;
00192       rep.data.value = arg0;
00193       rsize = sizeof(subbusd_rep_hdr_t)+sizeof(unsigned short);
00194       break;
00195     case 3:
00196       nl_assert( cur_req->request[0] == 'V' );
00197       switch ( cur_req->type ) {
00198         case SBDR_TYPE_INTERNAL:
00199           nl_error( 0, "Features: %d:%03X Version: %s",
00200             arg0, arg1, s);
00201           break;
00202         case SBDR_TYPE_CLIENT:
00203           rep.hdr.ret_type = SBRT_CAP;
00204           rep.data.capabilities.subfunc = arg0;
00205           rep.data.capabilities.features = arg1;
00206           strncpy(rep.data.capabilities.name, s, SUBBUS_NAME_MAX );
00207           rsize = sizeof(subbusd_rep_hdr_t) + sizeof(subbusd_cap_t);
00208           break;
00209         default: 
00210           break; // picked up and reported below
00211       }
00212       break;
00213     case 4:
00214       // 'M' response and request (tested before calling)
00215       rep.hdr.ret_type = SBRT_MREAD;
00216       nl_assert(cur_req->request[0] == 'M' && cur_req->n_reads != 0);
00217       // Look at req n_reads, then parse responses. Don't parse more
00218       // than n_reads values. If we encounter 'm', switch status to
00219       // SBS_NOACK. If we encounter 'E', switch status to
00220       // SBS_RESP_ERROR, report the error code, and return with no
00221       // data. If we get the wrong number of responses, report
00222       // SBS_RESP_SYNTAX, complain and return with no data
00223       { int n_reads = cur_req->n_reads;
00224         int i = 0;
00225         char *p = s;
00226         unsigned short errval;
00227 
00228         nl_assert( n_reads > 0 && n_reads <= 50 );
00229         while ( i < n_reads && rsize == 0 ) {
00230           switch ( *p ) {
00231             case 'm':
00232               rep.hdr.status = SBS_NOACK; // No acknowledge on at least one read
00233               // fall through
00234             case 'M':
00235               ++p;
00236               if ( ! read_hex( &p, &rep.data.mread.rvals[i++] ) ) {
00237                 nl_error(2,"DACS response syntax error: '%s'",
00238                   ascii_escape(s));
00239                 rep.hdr.status = SBS_RESP_SYNTAX; // DACS reply syntax error
00240                 rsize = sizeof(subbusd_rep_hdr_t);
00241                 rep.hdr.ret_type = SBRT_NONE;
00242                 break;
00243               }
00244               continue;
00245             case 'E':
00246               ++p;
00247               if ( ! read_hex( &p, &errval ) ) {
00248                 nl_error(2,"Invalid error in mread response: '%s'",
00249                   ascii_escape(s));
00250                 rep.hdr.status = SBS_RESP_SYNTAX;
00251               } else {
00252                 nl_error(2, "DACS reported error %d on mread", errval );
00253                 rep.hdr.status = SBS_RESP_ERROR;
00254               }
00255               rsize = sizeof(subbusd_rep_hdr_t);
00256               rep.hdr.ret_type = SBRT_NONE;
00257               break;
00258             default:
00259               break;
00260           }
00261           break;
00262         }
00263         if ( rsize == 0 ) {
00264           if ( i != n_reads || *p != '\0' ) {
00265             // Wrong number of read values returned
00266             nl_error(2, "Expected %d, read %d: '%s'",
00267               n_reads, i, ascii_escape(s));
00268             rep.hdr.status = SBS_RESP_SYNTAX;
00269             rsize = sizeof(subbusd_rep_hdr_t);
00270             rep.hdr.ret_type = SBRT_NONE;
00271           } else {
00272             rep.data.mread.n_reads = n_reads;
00273             rsize = sizeof(subbusd_rep_hdr_t) +
00274                     (n_reads+1) * sizeof(unsigned short);
00275           }
00276         }
00277       }
00278       break;
00279     case 2:
00280       nl_error( 4, "Invalid n_args in dequeue_request" );
00281   }
00282   switch( cur_req->type ) {
00283     case SBDR_TYPE_INTERNAL:
00284       rv = 0;
00285       break;
00286     case SBDR_TYPE_CLIENT:
00287       rv = MsgReply( cur_req->rcvid, rsize, &rep, rsize );
00288       break;
00289     default:
00290       nl_error( 4, "Invalid command type in dequeue_request" );
00291   }
00292   { int n = strlen(cur_req->request) - 1;
00293     nl_error( -2, "Dequeued: '%*.*s'", n, n, cur_req->request ); 
00294   }
00295   cur_req = NULL;
00296   if ( ++sbdrq_head >= SUBBUSD_MAX_REQUESTS )
00297     sbdrq_head = 0;
00298   if (rv == -1)
00299     nl_error(2, "Error from MsgReply: %s",
00300       strerror(errno) );
00301   process_request(); // if one is pending...
00302 }
00303 
00304 static void process_interrupt( unsigned int nb ) {
00305   card_def *cd;
00306   unsigned short addr;
00307   unsigned int bn;
00308   char sreq[8];
00309   
00310   for ( cd = carddefs; cd != NULL && cd->bitno != nb; cd = cd->next ) {}
00311   if ( cd != NULL ) {
00312     int rv = MsgDeliverEvent( cd->owner, &cd->event );
00313     if ( rv == -1 ) {
00314       switch (errno) {
00315         case EBADF:
00316         case ESRCH:
00317           nl_error( 1,
00318             "Process attached to '%s' interrupt not found",
00319             cd->cardID );
00320           rv = expint_detach( cd->owner, cd->cardID, &addr, &bn );
00321           nl_assert( rv == EOK );
00322           nl_assert( nb == bn );
00323           snprintf( sreq, 8, "u%X\n", addr );
00324           enqueue_sbreq( SBDR_TYPE_INTERNAL, 0, sreq, 0 );
00325           break;
00326         default:
00327           nl_error( 4, "Unexpected error %d from MsgDeliverEvent: %s",
00328               errno, strerror(errno));
00329       }
00330     }
00331   } else {
00332     nl_error( 1, "Unexpected interrupt #%d", nb );
00333     // We don't know the address, so can't disable it.
00334     // Probably a late hit.
00335   }
00336 }
00337 
00338 
00339 #define RESP_OK 0
00340 #define RESP_UNREC 1 /* Unrecognized code */
00341 #define RESP_UNEXP 2 /* Unexpected code */
00342 #define RESP_INV 3 /* Invalid response syntax */
00343 #define RESP_INTR 4 /* Interrupt code */
00344 #define RESP_ERR 5 /* Error from serusb */
00345 
00346 /** process_response() reviews the response in
00347    the buffer to determine if it is a suitable
00348    response to the current request. If so, it
00349    is returned to the requester.
00350    process_response() is not responsible for
00351    advancing to the next request, but it is
00352    responsible for dequeuing the current
00353    request if it has been completed.
00354 
00355    The string in resp is guaranteed to have had
00356    a newline at the end, which was replaced with
00357    a NUL, so we are guaranteed to have a NUL-
00358    terminated string.
00359  */
00360 static void process_response( char *buf ) {
00361   int status = RESP_OK;
00362   unsigned short arg0, arg1;
00363   signed short sbs_ok_status = SBS_OK;
00364   int n_args = 0;
00365   char *s = buf;
00366   char resp_code = *s++;
00367   char exp_req = '\0';
00368   int exp_args = 0;
00369   if ( resp_code == 'M' || resp_code == 'm' )  {
00370     if ( cur_req != NULL && cur_req->request[0] == 'M' ) {
00371       // We have to push the parsing into dequeue_request() because we need
00372       // direct access to the reply structure.
00373       dequeue_request(SBS_OK, 4, 0, 0, buf);
00374       return;
00375     } else {
00376       status = RESP_UNEXP;
00377     }
00378   } else {
00379     if ( resp_code != '\0' ) {
00380       // We can process args in the general case
00381       if (read_hex( &s, &arg0 )) {
00382         ++n_args;
00383         if (*s == ':') {
00384           ++s;
00385           if ( read_hex( &s, &arg1 ) ) {
00386             ++n_args;
00387             if ( *s == ':' ) {
00388               ++s; // points to name
00389               ++n_args;
00390             } else {
00391               status = RESP_INV;
00392             }
00393           } else status = RESP_INV;
00394         } else if ( *s != '\0' ) {
00395           status = RESP_INV;
00396         }
00397       } else if ( *s != '\0' ) {
00398         status = RESP_INV;
00399       }
00400     }
00401     // Check response for self-consistency
00402     // Check that response is appropriate for request
00403     switch (resp_code) {
00404       case 'R':
00405         exp_req = 'R';
00406         exp_args = 1;
00407         sbs_ok_status = SBS_ACK;
00408         break;
00409       case 'r':
00410         exp_req = 'R';
00411         exp_args = 1;
00412         sbs_ok_status = SBS_NOACK;
00413         break;
00414       case 'W':
00415         exp_req = 'W';
00416         exp_args = 0;
00417         sbs_ok_status = SBS_ACK;
00418         break;
00419       case 'w':
00420         exp_req = 'W';
00421         exp_args = 0;
00422         sbs_ok_status = SBS_NOACK;
00423         break;
00424       case 'V':
00425         exp_req = 'V';
00426         exp_args = 3;
00427         break;
00428       case 'I':
00429         status = RESP_INTR;
00430         exp_req = '\0';
00431         exp_args = 1;
00432         break;
00433       case 'A':
00434       case 'B':
00435       case 'S':
00436       case 'C':
00437       case 'F':
00438         exp_req = resp_code;
00439         exp_args = 0;
00440         break;
00441       case '0':
00442         exp_req = '\n';
00443         exp_args = 0;
00444         break;
00445       case 'D':
00446       case 'f':
00447       case 'i':
00448       case 'u':
00449         exp_req = resp_code;
00450         exp_args = 1;
00451         break;
00452       case 'E':
00453         status = RESP_ERR;
00454         exp_req = '\0';
00455         exp_args = 1;
00456         break;
00457       default:
00458         status = RESP_UNREC;
00459         break;
00460     }
00461     switch (status) {
00462       case RESP_OK:
00463         if ( cur_req == NULL || cur_req->request[0] != exp_req) {
00464           status = RESP_UNEXP;
00465           break;
00466         } // fall through
00467       case RESP_INTR:
00468       case RESP_ERR:
00469         if (n_args != exp_args)
00470           status = RESP_INV;
00471         break;
00472     }
00473   }
00474   switch (status) {
00475     case RESP_OK:
00476       dequeue_request(sbs_ok_status, n_args, arg0, arg1, s);
00477       break;
00478     case RESP_INTR:
00479       process_interrupt(arg0);
00480       break;
00481     case RESP_UNREC:
00482       nl_error( 2, "Unrecognized response: '%s'", ascii_escape(buf) );
00483       break;
00484     case RESP_UNEXP:
00485       nl_error( 2, "Unexpected response: '%s'", ascii_escape(buf) );
00486       break;
00487     case RESP_INV:
00488       nl_error( 2, "Invalid response: '%s'", ascii_escape(buf) );
00489       break;
00490     case RESP_ERR:
00491       nl_error( 2, "Error code %s from DACS", ascii_escape(buf) );
00492       break;
00493     default:
00494       nl_error( 4, "Invalid status: %d", status );
00495   }
00496   switch (status) {
00497     case RESP_OK:
00498     case RESP_INTR: break;
00499     default:
00500       if ( cur_req )
00501         nl_error( 2, "Current request was: '%s'",
00502             ascii_escape(cur_req->request) );
00503       else
00504         nl_error( 2, "No current request" );
00505   }
00506   // we won't dequeue on error: wait for timeout to handle that
00507   // that's because we don't know the invalid response was
00508   // to the current request. It could be noise, or an invalid
00509   // interrupt response for something.
00510 }
00511 
00512 /* sb_read_usb() reads data from the serusb device and
00513    decides what to do with it. If it satisfies the current
00514    request, we reply to the caller.
00515  */
00516 static void sb_read_usb(void) {
00517   do {
00518     int nb, nbr;
00519 
00520     nbr = SB_SERUSB_MAX_REQUEST - sb_ibuf_idx;
00521     nl_assert(nbr > 0 && nbr <= SB_SERUSB_MAX_REQUEST);
00522     nb = read(sb_fd, &sb_ibuf[sb_ibuf_idx], nbr);
00523     if ( nb < 0 ) {
00524       if (errno == EAGAIN) nb = 0;
00525       else
00526         nl_error( 3, "Error on read: %s", strerror(errno));
00527     }
00528     if ( nb > 0 ) ++n_reads;
00529     nl_assert(nb >= 0 && nb <= nbr);
00530     // Check to see if we have a complete response
00531     while ( nb > 0 ) {
00532       if ( sb_ibuf[sb_ibuf_idx] == '\n' ) {
00533         sb_ibuf[sb_ibuf_idx] = '\0';
00534         process_response(sb_ibuf);
00535         if (--nb > 0) {
00536           memmove( sb_ibuf, &sb_ibuf[sb_ibuf_idx+1], nb );
00537           sb_ibuf_idx = 0;
00538           ++n_compound_reads;
00539           // do not issue any pending request
00540           // in order to preserve causality
00541         } else {
00542           sb_ibuf_idx = 0;
00543         }
00544       } else {
00545         ++sb_ibuf_idx;
00546         --nb;
00547       }
00548     }
00549     if ( sb_ibuf_idx > 0 ) ++n_part_reads;
00550   } while ( sb_data_arm() & _NOTIFY_COND_INPUT );
00551 }
00552 
00553 /* sb_data_ready() is a thin wrapper for sb_read_usb()
00554    which is invoked from dispatch via pulse_attach().
00555  */
00556 static int sb_data_ready( message_context_t * ctp, int code,
00557         unsigned flags, void * handle ) {
00558   sb_read_usb();
00559   return 0;
00560 }
00561 
00562 static int sb_timeout( message_context_t * ctp, int code,
00563         unsigned flags, void * handle ) {
00564   if ( ++n_timeouts > 1 ) {
00565     n_timeouts = 0;
00566     if ( cur_req != NULL ) {
00567       nl_error( 1, "%sUSB request '%c' timed out",
00568         (cur_req->type == SBDR_TYPE_INTERNAL) ? "Internal " : "",
00569         cur_req->request[0] );
00570       dequeue_request( -ETIMEDOUT, 0, 0, 0, "" );
00571     }
00572   }
00573   return 0;
00574 }
00575 
00576 static void init_serusb(dispatch_t *dpp, int ionotify_pulse,
00577                           int timeout_pulse) {
00578   struct sigevent timeout_event;
00579   sb_fd = open("/dev/serusb2", O_RDWR | O_NONBLOCK);
00580   if (sb_fd == -1)
00581     nl_error(3,"Error opening USB subbus: %s", strerror(errno));
00582   /* flush anything in the input buffer */
00583   { int n;
00584     char tbuf[256];
00585     do {
00586       n = read(sb_fd, tbuf, 256);
00587       if ( n == -1) {
00588         if (errno == EAGAIN) break;
00589         else nl_error( 3, "Error trying to clear ibuf: %s",
00590           strerror(errno));
00591       }
00592     } while (n < 256);
00593   }
00594   ionotify_event.sigev_notify = SIGEV_PULSE;
00595   ionotify_event.sigev_code = ionotify_pulse;
00596   ionotify_event.sigev_priority = getprio(0);
00597   ionotify_event.sigev_value.sival_int = 0;
00598   ionotify_event.sigev_coid =
00599     message_connect(dpp, MSG_FLAG_SIDE_CHANNEL);
00600   if ( ionotify_event.sigev_coid == -1 )
00601     nl_error(3, "Could not connect to our channel: %s",
00602       strerror(errno));
00603   timeout_event.sigev_notify = SIGEV_PULSE;
00604   timeout_event.sigev_code = timeout_pulse;
00605   timeout_event.sigev_priority = getprio(0);
00606   timeout_event.sigev_value.sival_int = 0;
00607   timeout_event.sigev_coid = ionotify_event.sigev_coid;
00608   if ( timer_create( CLOCK_REALTIME, &timeout_event,
00609           &timeout_timer ) == -1 )
00610     nl_error(3, "Could not create timer: %s",
00611       strerror(errno));
00612   timeout_enable.it_value.tv_sec = 0;
00613   timeout_enable.it_value.tv_nsec = 100000000L; // 100 msecs
00614   timeout_enable.it_interval.tv_sec = 0;
00615   timeout_enable.it_interval.tv_nsec = 100000000L;
00616 
00617   // timeout_enable.it_value.tv_sec = 1; // 1 sec for debugging
00618   // timeout_enable.it_value.tv_nsec = 0;
00619   // timeout_enable.it_interval.tv_sec = 1;
00620   // timeout_enable.it_interval.tv_nsec = 0;
00621 
00622   timeout_disable.it_value.tv_sec = 0;
00623   timeout_disable.it_value.tv_nsec = 0;
00624   timeout_disable.it_interval.tv_sec = 0;
00625   timeout_disable.it_interval.tv_nsec = 0;
00626 
00627   /* now arm for input */
00628   sb_read_usb();
00629 }
00630 
00631 static void ErrorReply( int rcvid, int rv ) {
00632   subbusd_rep_hdr_t rep;
00633   nl_assert( rv > 0 );
00634   rep.status = -rv;
00635   rep.ret_type = SBRT_NONE;
00636   rv = MsgReply( rcvid, sizeof(rep), &rep, sizeof(rep) );
00637 }
00638 
00639 /**
00640  This is where we serialize the request
00641  The basic sanity of the incoming message has been
00642  checked by subbus_io_msg before it gets here,
00643  so we can at least assume that the message was
00644  big enough to include the specified message type,
00645  and that the message type is defined.
00646  */
00647 void incoming_sbreq( int rcvid, subbusd_req_t *req ) {
00648   char sreq[SB_SERUSB_MAX_REQUEST];
00649   subbusd_rep_t rep;
00650   int rv, rsize;
00651   
00652   switch ( req->sbhdr.command ) {
00653     case SBC_READCACHE:
00654       rep.hdr.status =
00655         (sb_cache_read(req->data.d1.data, &rep.data.value) < 0) ?
00656         SBS_NOACK : SBS_ACK;
00657       rep.hdr.ret_type = SBRT_US;
00658       rsize =
00659         sizeof(subbusd_rep_hdr_t) + sizeof(unsigned short);    
00660       rv = MsgReply( rcvid, rsize, &rep, rsize );
00661       return;
00662     case SBC_READACK:
00663       snprintf( sreq, SB_SERUSB_MAX_REQUEST, "R%04X\n",
00664         req->data.d1.data );
00665       break;
00666     case SBC_MREAD:
00667       enqueue_sbreq(SBDR_TYPE_CLIENT, rcvid, req->data.d4.multread_cmd,
00668                     req->data.d4.n_reads);
00669       return;
00670     case SBC_WRITECACHE:
00671       rv = sb_cache_write(req->data.d0.address, req->data.d0.data);
00672       if (rv != 1) {
00673         rep.hdr.ret_type = SBRT_NONE;
00674         rep.hdr.status = (rv == 0) ? SBS_ACK : SBS_NOACK;
00675         rsize = sizeof(subbusd_rep_hdr_t);
00676         rv = MsgReply( rcvid, rsize, &rep, rsize );
00677         return;
00678       }
00679       /* else fall through */
00680     case SBC_WRITEACK:
00681       snprintf( sreq, SB_SERUSB_MAX_REQUEST, "W%04X:%04X\n",
00682         req->data.d0.address, req->data.d0.data );
00683       break;
00684     case SBC_SETCMDENBL:
00685       snprintf( sreq, SB_SERUSB_MAX_REQUEST, "C%c\n",
00686         req->data.d1.data ? '1' : '0');
00687       break;
00688     case SBC_SETCMDSTRB:
00689       snprintf( sreq, SB_SERUSB_MAX_REQUEST, "S%c\n",
00690         req->data.d1.data ? '1' : '0');
00691       break;
00692     case SBC_SETFAIL:
00693       snprintf( sreq, SB_SERUSB_MAX_REQUEST, "F%04X\n",
00694         req->data.d1.data );
00695       break;
00696     case SBC_READSW:
00697       strcpy( sreq, "D\n" ); break;
00698     case SBC_READFAIL:
00699       strcpy( sreq, "f\n" ); break;
00700     case SBC_GETCAPS:
00701       strcpy( sreq, "V\n" ); break;
00702     case SBC_TICK:
00703       strcpy( sreq, "T\n" ); break;
00704     case SBC_DISARM:
00705       strcpy( sreq, "A\n" ); break;
00706     case SBC_INTATT:
00707       rv = int_attach(rcvid, req, sreq);
00708       if (rv != EOK) {
00709         ErrorReply(rcvid, rv);
00710         return; // i.e. don't enqueue
00711       }
00712       break;
00713     case SBC_INTDET:
00714       rv = int_detach(rcvid, req, sreq);
00715       if (rv != EOK) {
00716         ErrorReply(rcvid, rv);
00717         return; // i.e. don't enqueue
00718       }
00719       break;
00720     case SBC_QUIT:
00721       rep.hdr.ret_type = SBRT_NONE;
00722       rep.hdr.status = SBS_OK;
00723       rsize = sizeof(subbusd_rep_hdr_t);
00724       rv = MsgReply( rcvid, rsize, &rep, rsize );
00725       return;
00726     default:
00727       nl_error(4, "Undefined command in incoming_sbreq!" );
00728   }
00729   enqueue_sbreq( SBDR_TYPE_CLIENT, rcvid, sreq, 0 );
00730 }
00731 
00732 void init_subbus(dispatch_t *dpp ) {
00733   /* Setup ionotify pulse handler */
00734   int ionotify_pulse =
00735     pulse_attach(dpp, MSG_FLAG_ALLOC_PULSE, 0, sb_data_ready, NULL);
00736   int timer_pulse =
00737     pulse_attach(dpp, MSG_FLAG_ALLOC_PULSE, 0, sb_timeout, NULL);
00738   init_serusb(dpp, ionotify_pulse, timer_pulse);
00739 
00740   /* Setup timer pulse handler */
00741   // pulse_attach();
00742 
00743   /* Enqueue initialization requests */
00744   enqueue_sbreq( SBDR_TYPE_INTERNAL, 0, "\n", 0 );
00745   enqueue_sbreq( SBDR_TYPE_INTERNAL, 0, "V\n", 0 );
00746 }
00747 
00748 void shutdown_subbus(void) {
00749   nl_error( 0, "%d writes, %d reads, %d partial reads, %d compound reads",
00750     n_writes, n_reads, n_part_reads, n_compound_reads );
00751 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines