ARPDAS_QNX6 1.0
|
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 }