/* * parse_inp_fnc_t inp_rcc8000 * * grab data from input stream */ static u_long inp_rcc8000( parse_t *parseio, char ch, timestamp_t *tstamp ) { unsigned int rtc; parseprintf(DD_PARSE, ("inp_rcc8000(0x%p, 0x%x, ...)\n", (void*)parseio, ch)); switch (ch) { case '\n': parseprintf(DD_PARSE, ("inp_rcc8000: EOL seen\n")); if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) return parse_end(parseio); else return rtc; default: if (parseio->parse_index == 0) /* take sample at start of message */ { parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ } return parse_addchar(parseio, ch); } }
bool parse_timedout( parse_t *parseio, timestamp_t *tstamp, struct timespec *del ) { struct timespec delta; l_fp delt; delt = tstamp->fp; L_SUB(&delt, &parseio->parse_lastchar.fp); delta = lfp_uintv_to_tspec(delt); if (cmp_tspec(delta, *del) == TIMESPEC_GREATER_THAN) { parseprintf(DD_PARSE, ("parse: timedout: TRUE\n")); return true; } else { parseprintf(DD_PARSE, ("parse: timedout: FALSE\n")); return false; } }
/* * parse_inp_fnc_t mbg_input * * grab data from input stream */ static u_long mbg_input( parse_t *parseio, char ch, timestamp_t *tstamp ) { unsigned int rtc; parseprintf(DD_PARSE, ("mbg_input(0x%p, 0x%x, ...)\n", (void*)parseio, ch)); switch (ch) { case STX: parseprintf(DD_PARSE, ("mbg_input: STX seen\n")); parseio->parse_index = 1; parseio->parse_data[0] = ch; parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ return PARSE_INP_SKIP; case ETX: parseprintf(DD_PARSE, ("mbg_input: ETX seen\n")); if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) return parse_end(parseio); else return rtc; default: return parse_addchar(parseio, ch); } }
/* * parse_inp_fnc_t inp_trimtaip * * grab data from input stream */ static u_long inp_trimtaip( parse_t *parseio, char ch, timestamp_t *tstamp ) { unsigned int rtc; parseprintf(DD_PARSE, ("inp_trimtaip(0x%lx, 0x%x, ...)\n", (long)parseio, ch)); switch (ch) { case '>': parseprintf(DD_PARSE, ("inp_trimptaip: START seen\n")); parseio->parse_index = 1; parseio->parse_data[0] = ch; parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ return PARSE_INP_SKIP; case '<': parseprintf(DD_PARSE, ("inp_trimtaip: END seen\n")); if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) return parse_end(parseio); else return rtc; default: return parse_addchar(parseio, ch); } }
/* * parse_inp_fnc_t inp_hopf6021 * * grab data from input stream */ static u_long inp_hopf6021( parse_t *parseio, char ch, timestamp_t *tstamp ) { unsigned int rtc; parseprintf(DD_PARSE, ("inp_hopf6021(0x%lx, 0x%x, ...)\n", (long)parseio, ch)); switch (ch) { case ETX: parseprintf(DD_PARSE, ("inp_hopf6021: EOL seen\n")); parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) return parse_end(parseio); else return rtc; default: return parse_addchar(parseio, ch); } }
unsigned int parse_restart( parse_t *parseio, char ch ) { unsigned int updated = PARSE_INP_SKIP; /* * re-start packet - timeout - overflow - start symbol */ if (parseio->parse_index) { /* * filled buffer - thus not end character found * do processing now */ parseio->parse_data[parseio->parse_index] = '\0'; memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1)); parseio->parse_ldsize = parseio->parse_index; updated = PARSE_INP_TIME; } parseio->parse_index = 1; parseio->parse_data[0] = ch; parseprintf(DD_PARSE, ("parse: parse_restart: buffer start (updated = %x)\n", updated)); return updated; }
static unsigned long inp_sel240x( parse_t *parseio, unsigned int ch, timestamp_t *tstamp ) { unsigned long rc; parseprintf( DD_PARSE, ("inp_sel240x(0x%lx, 0x%x, ...)\n",(long)parseio, ch)); switch( ch ) { case '\x01': parseio->parse_index = 1; parseio->parse_data[0] = ch; parseio->parse_dtime.parse_stime = *tstamp; rc = PARSE_INP_SKIP; break; case '\n': if( (rc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP ) { rc = parse_end( parseio ); } break; default: rc = parse_addchar( parseio, ch ); } return rc; }
static int setup_stream( queue_t *q, int mode ) { mblk_t *mp; mp = allocb(sizeof(struct stroptions), BPRI_MED); if (mp) { struct stroptions *str = (struct stroptions *)(void *)mp->b_rptr; str->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT; str->so_readopt = (mode == M_PARSE) ? RMSGD : RNORM; str->so_hiwat = (mode == M_PARSE) ? sizeof(parsetime_t) : 256; str->so_lowat = 0; mp->b_datap->db_type = M_SETOPTS; mp->b_wptr += sizeof(struct stroptions); putnext(q, mp); return putctl1(WR(q)->q_next, M_CTL, (mode == M_PARSE) ? MC_SERVICEIMM : MC_SERVICEDEF); } else { parseprintf(DD_OPEN,("parse: setup_stream - FAILED - no MEMORY for allocb\n")); return 0; } }
/*ARGSUSED*/ static int parseclose( queue_t *q, int flags ) { register parsestream_t *parse = (parsestream_t *)(void *)q->q_ptr; register unsigned long s; parseprintf(DD_CLOSE,("parse: CLOSE\n")); s = splhigh(); if (parse->parse_dqueue) close_linemon(parse->parse_dqueue, q); parse->parse_dqueue = (queue_t *)0; (void) splx(s); parse_ioend(&parse->parse_io); kmem_free((caddr_t)parse, sizeof(parsestream_t)); q->q_ptr = (caddr_t)NULL; WR(q)->q_ptr = (caddr_t)NULL; #ifdef VDDRV parsebusy--; #endif return 0; }
/* * unregister our ISR routine - must call under splhigh() */ static void close_zs_linemon( register queue_t *q, register queue_t *my_q ) { register struct zscom *zs; register parsestream_t *parsestream = (parsestream_t *)(void *)my_q->q_ptr; zs = ((struct zsaline *)(void *)q->q_ptr)->za_common; if (!zs) { /* * well - not found on startup - just say no (shouldn't happen though) */ return; } else { register struct savedzsops *szs = (struct savedzsops *)parsestream->parse_data; zsopinit(zs, szs->oldzsops); /* reset to previous handler functions */ kmem_free((caddr_t)szs, sizeof (struct savedzsops)); parseprintf(DD_INSTALL, ("close_zs_linemon: CD monitor deleted\n")); return; } }
static int init_linemon( register queue_t *q ) { register queue_t *dq; dq = WR(q); /* * we ARE doing very bad things down here (basically stealing ISR * hooks) * * so we chase down the STREAMS stack searching for the driver * and if this is a known driver we insert our ISR routine for * status changes in to the ExternalStatus handling hook */ while (dq->q_next) { dq = dq->q_next; /* skip down to driver */ } /* * find appropriate driver dependent routine */ if (dq->q_qinfo && dq->q_qinfo->qi_minfo) { register char *dname = dq->q_qinfo->qi_minfo->mi_idname; parseprintf(DD_INSTALL, ("init_linemon: driver is \"%s\"\n", dname)); #ifdef sun if (dname && !Strcmp(dname, "zs")) { return init_zs_linemon(dq, q); } else #endif { parseprintf(DD_INSTALL, ("init_linemon: driver \"%s\" not suitable for CD monitoring\n", dname)); return 0; } } parseprintf(DD_INSTALL, ("init_linemon: cannot find driver\n")); return 0; }
/*ARGSUSED*/ void parse_iodone( register parse_t *parseio ) { /* * we need to clean up certain flags for the next round */ parseprintf(DD_PARSE, ("parse_iodone: DONE\n")); parseio->parse_dtime.parse_state = 0; /* no problems with ISRs */ }
/*ARGSUSED*/ void parse_ioend( register parse_t *parseio ) { parseprintf(DD_PARSE, ("parse_ioend\n")); if (parseio->parse_pdata) free(parseio->parse_pdata); if (parseio->parse_data) free(parseio->parse_data); }
/* * move unrecognized stuff upward */ static int parsersvc( queue_t *q ) { mblk_t *mp; while ((mp = getq(q))) { if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) { putnext(q, mp); parseprintf(DD_RSVC,("parse: RSVC - putnext\n")); } else { putbq(q, mp); parseprintf(DD_RSVC,("parse: RSVC - flow control wait\n")); break; } } return 0; }
static void close_linemon( register queue_t *q, register queue_t *my_q ) { /* * find appropriate driver dependent routine */ if (q->q_qinfo && q->q_qinfo->qi_minfo) { register char *dname = q->q_qinfo->qi_minfo->mi_idname; #ifdef sun if (dname && !Strcmp(dname, "zs")) { close_zs_linemon(q, my_q); return; } parseprintf(DD_INSTALL, ("close_linemon: cannot find driver close routine for \"%s\"\n", dname)); #endif } parseprintf(DD_INSTALL, ("close_linemon: cannot find driver name\n")); }
/*ARGSUSED*/ int parse_iopps( register parse_t *parseio, register int status, register timestamp_t *ptime ) { register unsigned int updated = CVT_NONE; /* * PPS pulse information will only be delivered to ONE clock format * this is either the last successful conversion module with a ppssync * routine, or a fixed format with a ppssync routine */ parseprintf(DD_PARSE, ("parse_iopps: STATUS %s\n", (status == SYNC_ONE) ? "ONE" : "ZERO")); if (clockformats[parseio->parse_lformat]->syncpps) { updated = (unsigned int) clockformats[parseio->parse_lformat]->syncpps(parseio, status == SYNC_ONE, ptime); parseprintf(DD_PARSE, ("parse_iopps: updated = 0x%x\n", updated)); } return (updated & CVT_MASK) != CVT_NONE; }
unsigned int parse_end( parse_t *parseio ) { /* * message complete processing */ parseio->parse_data[parseio->parse_index] = '\0'; memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1)); parseio->parse_ldsize = parseio->parse_index; parseio->parse_index = 0; parseprintf(DD_PARSE, ("parse: parse_end: buffer end\n")); return PARSE_INP_TIME; }
unsigned long updatetimeinfo( register parse_t *parseio, register unsigned long flags ) { parseio->parse_lstate = parseio->parse_dtime.parse_state | flags | PARSEB_TIMECODE; parseio->parse_dtime.parse_state = parseio->parse_lstate; parseprintf(DD_PARSE, ("updatetimeinfo status=0x%lx, time=%x\n", (long)parseio->parse_dtime.parse_state, parseio->parse_dtime.parse_time.fp.l_ui)); return CVT_OK; /* everything fine and dandy... */ }
/*ARGSUSED*/ bool parse_ioinit( register parse_t *parseio ) { parseprintf(DD_PARSE, ("parse_iostart\n")); parseio->parse_plen = 0; parseio->parse_pdata = (void *)0; parseio->parse_data = 0; parseio->parse_ldata = 0; parseio->parse_dsize = 0; parseio->parse_badformat = 0; parseio->parse_ioflags = PARSE_IO_CS7; /* usual unix default */ parseio->parse_index = 0; parseio->parse_ldsize = 0; return true; }
unsigned int parse_addchar( parse_t *parseio, char ch ) { /* * add to buffer */ if (parseio->parse_index < parseio->parse_dsize) { /* * collect into buffer */ parseprintf(DD_PARSE, ("parse: parse_addchar: buffer[%d] = 0x%x\n", parseio->parse_index, ch)); parseio->parse_data[parseio->parse_index++] = (char)ch; return PARSE_INP_SKIP; } else /* * buffer overflow - attempt to make the best of it */ return parse_restart(parseio, ch); }
static u_long inp_varitext( parse_t *parseio, unsigned int ch, timestamp_t *tstamp ) { struct varitext *t = (struct varitext *)parseio->parse_pdata; int rtc; parseprintf(DD_PARSE, ("inp_varitext(0x%lx, 0x%x, ...)\n", (long)parseio, ch)); if (!t) return PARSE_INP_SKIP; /* local data not allocated - sigh! */ if (ch == 'T') t->tstamp = *tstamp; if ((t->previous_ch == 'T') && (ch == ':')) { parseprintf(DD_PARSE, ("inp_varitext: START seen\n")); parseio->parse_data[0] = 'T'; parseio->parse_index=1; parseio->parse_dtime.parse_stime = t->tstamp; /* Time stamp at packet start */ t->start_found = 1; t->end_found = 0; t->end_count = 0; } if (t->start_found) { if ((rtc = parse_addchar(parseio, ch)) != PARSE_INP_SKIP) { parseprintf(DD_PARSE, ("inp_varitext: ABORTED due to too many characters\n")); memset(t, 0, sizeof(struct varitext)); return rtc; } if (t->end_found) { if (++(t->end_count) == 4) /* Finally found the end of the message */ { parseprintf(DD_PARSE, ("inp_varitext: END seen\n")); memset(t, 0, sizeof(struct varitext)); if ((rtc = parse_addchar(parseio, 0)) == PARSE_INP_SKIP) return parse_end(parseio); else return rtc; } } if ((t->previous_ch == '\r') && (ch == '\n')) { t->end_found = 1; } } t->previous_ch = ch; return PARSE_INP_SKIP; }
/* * convert incoming data */ static int parserput( queue_t *q, mblk_t *mp ) { unsigned char type; switch (type = mp->b_datap->db_type) { default: /* * anything we don't know will be put on queue * the service routine will move it to the next one */ parseprintf(DD_RPUT,("parse: parserput - forward type 0x%x\n", type)); if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) { putnext(q, mp); } else putq(q, mp); break; case M_BREAK: case M_DATA: { register parsestream_t * parse = (parsestream_t *)(void *)q->q_ptr; register mblk_t *nmp; register unsigned long ch; timestamp_t ctime; /* * get time on packet delivery */ uniqtime(&ctime.tv); if (!(parse->parse_status & PARSE_ENABLE)) { parseprintf(DD_RPUT,("parse: parserput - parser disabled - forward type 0x%x\n", type)); if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) { putnext(q, mp); } else putq(q, mp); } else { parseprintf(DD_RPUT,("parse: parserput - M_%s\n", (type == M_DATA) ? "DATA" : "BREAK")); if (type == M_DATA) { /* * parse packet looking for start an end characters */ while (mp != (mblk_t *)NULL) { ch = rdchar(&mp); if (ch != ~0 && parse_ioread(&parse->parse_io, (unsigned int)ch, &ctime)) { /* * up up and away (hopefully ...) * don't press it if resources are tight or nobody wants it */ nmp = (mblk_t *)NULL; if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) { bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); nmp->b_wptr += sizeof(parsetime_t); putnext(parse->parse_queue, nmp); } else if (nmp) freemsg(nmp); parse_iodone(&parse->parse_io); } } } else { if (parse_ioread(&parse->parse_io, (unsigned int)0, &ctime)) { /* * up up and away (hopefully ...) * don't press it if resources are tight or nobody wants it */ nmp = (mblk_t *)NULL; if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) { bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); nmp->b_wptr += sizeof(parsetime_t); putnext(parse->parse_queue, nmp); } else if (nmp) freemsg(nmp); parse_iodone(&parse->parse_io); } freemsg(mp); } break; } } /* * CD PPS support for non direct ISR hack */ case M_HANGUP: case M_UNHANGUP: { register parsestream_t * parse = (parsestream_t *)(void *)q->q_ptr; timestamp_t ctime; register mblk_t *nmp; register int status = cd_invert ^ (type == M_UNHANGUP); uniqtime(&ctime.tv); parseprintf(DD_RPUT,("parse: parserput - M_%sHANGUP\n", (type == M_HANGUP) ? "" : "UN")); if ((parse->parse_status & PARSE_ENABLE) && parse_iopps(&parse->parse_io, (int)(status ? SYNC_ONE : SYNC_ZERO), &ctime)) { nmp = (mblk_t *)NULL; if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) { bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); nmp->b_wptr += sizeof(parsetime_t); putnext(parse->parse_queue, nmp); } else if (nmp) freemsg(nmp); parse_iodone(&parse->parse_io); freemsg(mp); } else if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) { putnext(q, mp); } else putq(q, mp); if (status) { parse->parse_ppsclockev.tv = ctime.tv; ++(parse->parse_ppsclockev.serial); } } } return 0; }
/*ARGSUSED*/ bool parse_setfmt( parsectl_t *dct, parse_t *parse ) { if (dct->parseformat.parse_count <= PARSE_TCMAX) { if (dct->parseformat.parse_count) { register unsigned short i; for (i = 0; i < nformats; i++) { if (!strcmp(dct->parseformat.parse_buffer, clockformats[i]->name)) { if (parse->parse_pdata) free(parse->parse_pdata); parse->parse_pdata = 0; parse->parse_plen = clockformats[i]->plen; if (parse->parse_plen) { parse->parse_pdata = malloc(parse->parse_plen); if (!parse->parse_pdata) { parseprintf(DD_PARSE, ("set format failed: malloc for private data area failed\n")); return false; } memset((char *)parse->parse_pdata, 0, parse->parse_plen); } if (parse->parse_data) free(parse->parse_data); parse->parse_ldata = parse->parse_data = 0; parse->parse_dsize = clockformats[i]->length; if (parse->parse_dsize) { parse->parse_data = (char*)malloc((unsigned)(parse->parse_dsize * 2 + 2)); if (!parse->parse_data) { if (parse->parse_pdata) free(parse->parse_pdata); parse->parse_pdata = 0; parseprintf(DD_PARSE, ("init failed: malloc for data area failed\n")); return false; } } /* * leave room for '\0' */ parse->parse_ldata = parse->parse_data + parse->parse_dsize + 1; parse->parse_lformat = i; return true; } } } } return false; }
static u_long convert_rawdcf( unsigned char *buffer, int size, struct dcfparam *dcfprm, clocktime_t *clock_time ) { unsigned char *s = buffer; const unsigned char *b = dcfprm->onebits; const unsigned char *c = dcfprm->zerobits; int i; parseprintf(DD_RAWDCF,("parse: convert_rawdcf: \"%s\"\n", buffer)); if (size < 57) { #ifndef PARSEKERNEL msyslog(LOG_ERR, "parse: convert_rawdcf: INCOMPLETE DATA - time code only has %d bits", size); #endif return CVT_NONE; } for (i = 0; i < size; i++) { if ((*s != *b) && (*s != *c)) { /* * we only have two types of bytes (ones and zeros) */ #ifndef PARSEKERNEL msyslog(LOG_ERR, "parse: convert_rawdcf: BAD DATA - no conversion"); #endif return CVT_NONE; } if (*b) b++; if (*c) c++; s++; } /* * check Start and Parity bits */ if ((ext_bf(buffer, DCF_S, dcfprm->zerobits) == 1) && pcheck(buffer, DCF_P_P1, dcfprm->zerobits) && pcheck(buffer, DCF_P_P2, dcfprm->zerobits) && pcheck(buffer, DCF_P_P3, dcfprm->zerobits)) { /* * buffer OK */ parseprintf(DD_RAWDCF,("parse: convert_rawdcf: parity check passed\n")); clock_time->flags = PARSEB_S_ANTENNA|PARSEB_S_LEAP; clock_time->utctime= 0; clock_time->usecond= 0; clock_time->second = 0; clock_time->minute = ext_bf(buffer, DCF_M10, dcfprm->zerobits); clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1, dcfprm->zerobits); clock_time->hour = ext_bf(buffer, DCF_H10, dcfprm->zerobits); clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1, dcfprm->zerobits); clock_time->day = ext_bf(buffer, DCF_D10, dcfprm->zerobits); clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1, dcfprm->zerobits); clock_time->month = ext_bf(buffer, DCF_MO0, dcfprm->zerobits); clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO, dcfprm->zerobits); clock_time->year = ext_bf(buffer, DCF_Y10, dcfprm->zerobits); clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1, dcfprm->zerobits); switch (ext_bf(buffer, DCF_Z, dcfprm->zerobits)) { case DCF_Z_MET: clock_time->utcoffset = -1*60*60; break; case DCF_Z_MED: clock_time->flags |= PARSEB_DST; clock_time->utcoffset = -2*60*60; break; default: parseprintf(DD_RAWDCF,("parse: convert_rawdcf: BAD TIME ZONE\n")); return CVT_FAIL|CVT_BADFMT; } if (ext_bf(buffer, DCF_A1, dcfprm->zerobits)) clock_time->flags |= PARSEB_ANNOUNCE; if (ext_bf(buffer, DCF_A2, dcfprm->zerobits)) clock_time->flags |= PARSEB_LEAPADD; /* default: DCF77 data format deficiency */ if (ext_bf(buffer, DCF_R, dcfprm->zerobits)) clock_time->flags |= PARSEB_CALLBIT; parseprintf(DD_RAWDCF,("parse: convert_rawdcf: TIME CODE OK: %d:%d, %d.%d.%d, flags 0x%lx\n", (int)clock_time->hour, (int)clock_time->minute, (int)clock_time->day, (int)clock_time->month,(int) clock_time->year, (u_long)clock_time->flags)); return CVT_OK; } else { /* * bad format - not for us */ #ifndef PARSEKERNEL msyslog(LOG_ERR, "parse: convert_rawdcf: parity check FAILED for \"%s\"", buffer); #endif return CVT_FAIL|CVT_BADFMT; } }
/* * do ioctls and * send stuff down - dont care about * flow control */ static int parsewput( queue_t *q, register mblk_t *mp ) { register int ok = 1; register mblk_t *datap; register struct iocblk *iocp; parsestream_t *parse = (parsestream_t *)(void *)q->q_ptr; parseprintf(DD_WPUT,("parse: parsewput\n")); switch (mp->b_datap->db_type) { default: putnext(q, mp); break; case M_IOCTL: iocp = (struct iocblk *)(void *)mp->b_rptr; switch (iocp->ioc_cmd) { default: parseprintf(DD_WPUT,("parse: parsewput - forward M_IOCTL\n")); putnext(q, mp); break; case CIOGETEV: /* * taken from Craig Leres ppsclock module (and modified) */ datap = allocb(sizeof(struct ppsclockev), BPRI_MED); if (datap == NULL || mp->b_cont) { mp->b_datap->db_type = M_IOCNAK; iocp->ioc_error = (datap == NULL) ? ENOMEM : EINVAL; if (datap != NULL) freeb(datap); qreply(q, mp); break; } mp->b_cont = datap; *(struct ppsclockev *)(void *)datap->b_wptr = parse->parse_ppsclockev; datap->b_wptr += sizeof(struct ppsclockev) / sizeof(*datap->b_wptr); mp->b_datap->db_type = M_IOCACK; iocp->ioc_count = sizeof(struct ppsclockev); qreply(q, mp); break; case PARSEIOC_ENABLE: case PARSEIOC_DISABLE: { parse->parse_status = (parse->parse_status & (unsigned)~PARSE_ENABLE) | (iocp->ioc_cmd == PARSEIOC_ENABLE) ? PARSE_ENABLE : 0; if (!setup_stream(RD(q), (parse->parse_status & PARSE_ENABLE) ? M_PARSE : M_NOPARSE)) { mp->b_datap->db_type = M_IOCNAK; } else { mp->b_datap->db_type = M_IOCACK; } qreply(q, mp); break; } case PARSEIOC_TIMECODE: case PARSEIOC_SETFMT: case PARSEIOC_GETFMT: case PARSEIOC_SETCS: if (iocp->ioc_count == sizeof(parsectl_t)) { parsectl_t *dct = (parsectl_t *)(void *)mp->b_cont->b_rptr; switch (iocp->ioc_cmd) { case PARSEIOC_TIMECODE: parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_TIMECODE\n")); ok = parse_timecode(dct, &parse->parse_io); break; case PARSEIOC_SETFMT: parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETFMT\n")); ok = parse_setfmt(dct, &parse->parse_io); break; case PARSEIOC_GETFMT: parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_GETFMT\n")); ok = parse_getfmt(dct, &parse->parse_io); break; case PARSEIOC_SETCS: parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETCS\n")); ok = parse_setcs(dct, &parse->parse_io); break; } mp->b_datap->db_type = ok ? M_IOCACK : M_IOCNAK; } else { mp->b_datap->db_type = M_IOCNAK; } parseprintf(DD_WPUT,("parse: parsewput qreply - %s\n", (mp->b_datap->db_type == M_IOCNAK) ? "M_IOCNAK" : "M_IOCACK")); qreply(q, mp); break; } } return 0; }
/* * parse_cvt_fnc_t cvt_rawdcf * raw dcf input routine - needs to fix up 50 baud * characters for 1/0 decision */ static u_long cvt_rawdcf( unsigned char *buffer, int size, struct format *param, clocktime_t *clock_time, void *local ) { last_tcode_t *t = (last_tcode_t *)local; unsigned char *s = (unsigned char *)buffer; unsigned char *e = s + size; const unsigned char *b = dcfparameter.onebits; const unsigned char *c = dcfparameter.zerobits; u_long rtc = CVT_NONE; unsigned int i, lowmax, highmax, cutoff, span; #define BITS 9 unsigned char histbuf[BITS]; /* * the input buffer contains characters with runs of consecutive * bits set. These set bits are an indication of the DCF77 pulse * length. We assume that we receive the pulse at 50 Baud. Thus * a 100ms pulse would generate a 4 bit train (20ms per bit and * start bit) * a 200ms pulse would create all zeroes (and probably a frame error) */ for (i = 0; i < BITS; i++) { histbuf[i] = 0; } cutoff = 0; lowmax = 0; while (s < e) { unsigned int ch = *s ^ 0xFF; /* * these lines are left as an excercise to the reader 8-) */ if (!((ch+1) & ch) || !*s) { for (i = 0; ch; i++) { ch >>= 1; } *s = (unsigned char) i; histbuf[i]++; cutoff += i; lowmax++; } else { parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: character check for 0x%x@%d FAILED\n", *s, (int)(s - (unsigned char *)buffer))); *s = (unsigned char)~0; rtc = CVT_FAIL|CVT_BADFMT; } s++; }
/*ARGSUSED*/ static int parseopen( queue_t *q, dev_t dev, int flag, int sflag ) { register parsestream_t *parse; static int notice = 0; parseprintf(DD_OPEN,("parse: OPEN\n")); if (sflag != MODOPEN) { /* open only for modules */ parseprintf(DD_OPEN,("parse: OPEN - FAILED - not MODOPEN\n")); return OPENFAIL; } if (q->q_ptr != (caddr_t)NULL) { u.u_error = EBUSY; parseprintf(DD_OPEN,("parse: OPEN - FAILED - EXCLUSIVE ONLY\n")); return OPENFAIL; } #ifdef VDDRV parsebusy++; #endif q->q_ptr = (caddr_t)kmem_alloc(sizeof(parsestream_t)); if (q->q_ptr == (caddr_t)0) { parseprintf(DD_OPEN,("parse: OPEN - FAILED - no memory\n")); #ifdef VDDRV parsebusy--; #endif return OPENFAIL; } WR(q)->q_ptr = q->q_ptr; parse = (parsestream_t *)(void *)q->q_ptr; bzero((caddr_t)parse, sizeof(*parse)); parse->parse_queue = q; parse->parse_status = PARSE_ENABLE; parse->parse_ppsclockev.tv.tv_sec = 0; parse->parse_ppsclockev.tv.tv_usec = 0; parse->parse_ppsclockev.serial = 0; if (!parse_ioinit(&parse->parse_io)) { /* * ok guys - beat it */ kmem_free((caddr_t)parse, sizeof(parsestream_t)); #ifdef VDDRV parsebusy--; #endif return OPENFAIL; } if (setup_stream(q, M_PARSE)) { (void) init_linemon(q); /* hook up PPS ISR routines if possible */ parseprintf(DD_OPEN,("parse: OPEN - SUCCEEDED\n")); /* * I know that you know the delete key, but you didn't write this * code, did you ? - So, keep the message in here. */ if (!notice) { #ifdef VDDRV printf("%s: Copyright (C) 1991-2005, Frank Kardel\n", parsesync_vd.Drv_name); #else printf("%s: Copyright (C) 1991-2005, Frank Kardel\n", "parsestreams.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A"); #endif notice = 1; } return MODOPEN; } else { kmem_free((caddr_t)parse, sizeof(parsestream_t)); #ifdef VDDRV parsebusy--; #endif return OPENFAIL; } }
/* * parse_inp_fnc_t gps_input * * grep binary data from input stream */ static u_long gps_input( parse_t *parseio, char ch, timestamp_t *tstamp ) { CSUM calc_csum; /* used to compare the incoming csums */ GPS_MSG_HDR header; struct msg_buf *msg_buf; msg_buf = (struct msg_buf *)parseio->parse_pdata; parseprintf(DD_PARSE, ("gps_input(0x%p, 0x%x, ...)\n", (void*)parseio, ch)); if (!msg_buf) return PARSE_INP_SKIP; if ( msg_buf->phase == MBG_NONE ) { /* not receiving yet */ switch (ch) { case SOH: parseprintf(DD_PARSE, ("gps_input: SOH seen\n")); msg_buf->len = sizeof( header ); /* prepare to receive msg header */ msg_buf->phase = MBG_HEADER; /* receiving header */ break; case STX: parseprintf(DD_PARSE, ("gps_input: STX seen\n")); msg_buf->len = 0; msg_buf->phase = MBG_STRING; /* prepare to receive ASCII ETX delimited message */ parseio->parse_index = 1; parseio->parse_data[0] = ch; break; default: return PARSE_INP_SKIP; /* keep searching */ } parseio->parse_dtime.parse_msglen = 1; /* reset buffer pointer */ parseio->parse_dtime.parse_msg[0] = ch; /* fill in first character */ parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ return PARSE_INP_SKIP; } /* SOH/STX has already been received */ /* save incoming character in both buffers if needbe */ if ((msg_buf->phase == MBG_STRING) && (parseio->parse_index < parseio->parse_dsize)) parseio->parse_data[parseio->parse_index++] = ch; parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch; if (parseio->parse_dtime.parse_msglen > sizeof(parseio->parse_dtime.parse_msg)) { msg_buf->phase = MBG_NONE; /* buffer overflow - discard */ parseio->parse_data[parseio->parse_index] = '\0'; memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1)); parseio->parse_ldsize = parseio->parse_index; return PARSE_INP_DATA; } switch (msg_buf->phase) { case MBG_HEADER: case MBG_DATA: msg_buf->len--; if ( msg_buf->len ) /* transfer not complete */ return PARSE_INP_SKIP; parseprintf(DD_PARSE, ("gps_input: %s complete\n", (msg_buf->phase == MBG_DATA) ? "data" : "header")); break; case MBG_STRING: if ((ch == ETX) || (parseio->parse_index >= parseio->parse_dsize)) { msg_buf->phase = MBG_NONE; parseprintf(DD_PARSE, ("gps_input: string complete\n")); parseio->parse_data[parseio->parse_index] = '\0'; memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1)); parseio->parse_ldsize = parseio->parse_index; parseio->parse_index = 0; return PARSE_INP_TIME; } else { return PARSE_INP_SKIP; } } /* cnt == 0, so the header or the whole message is complete */ if ( msg_buf->phase == MBG_HEADER ) { /* header complete now */ unsigned char *datap = parseio->parse_dtime.parse_msg + 1; get_mbg_header(&datap, &header); parseprintf(DD_PARSE, ("gps_input: header: cmd 0x%x, len %d, dcsum 0x%x, hcsum 0x%x\n", (int)header.cmd, (int)header.len, (int)header.data_csum, (int)header.hdr_csum)); calc_csum = mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg + 1, (unsigned short)6 ); if ( calc_csum != header.hdr_csum ) { parseprintf(DD_PARSE, ("gps_input: header checksum mismatch expected 0x%x, got 0x%x\n", (int)calc_csum, (int)mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg, (unsigned short)6 ))); msg_buf->phase = MBG_NONE; /* back to hunting mode */ return PARSE_INP_DATA; /* invalid header checksum received - pass up for detection */ } if ((header.len == 0) || /* no data to wait for */ (header.len >= (sizeof (parseio->parse_dtime.parse_msg) - sizeof(header) - 1))) /* blows anything we have space for */ { msg_buf->phase = MBG_NONE; /* back to hunting mode */ return (header.len == 0) ? PARSE_INP_DATA : PARSE_INP_SKIP; /* message complete/throwaway */ } parseprintf(DD_PARSE, ("gps_input: expecting %d bytes of data message\n", (int)header.len)); msg_buf->len = header.len;/* save number of bytes to wait for */ msg_buf->phase = MBG_DATA; /* flag header already complete */ return PARSE_INP_SKIP; } parseprintf(DD_PARSE, ("gps_input: message data complete\n")); /* Header and data have been received. The header checksum has been */ /* checked */ msg_buf->phase = MBG_NONE; /* back to hunting mode */ return PARSE_INP_DATA; /* message complete, must be evaluated */ }
/* * take external status interrupt (only CD interests us) */ static int zs_xsisr( struct zscom *zs ) { register struct zsaline *za = (struct zsaline *)(void *)zs->zs_priv; register struct zscc_device *zsaddr = zs->zs_addr; register queue_t *q; register unsigned char zsstatus; register int loopcheck; register char *dname; #ifdef PPS_SYNC register unsigned int s; register long usec; #endif /* * pick up current state */ zsstatus = zsaddr->zscc_control; if ((za->za_rr0 ^ zsstatus) & (cdmask)) { timestamp_t cdevent; register int status; za->za_rr0 = (za->za_rr0 & ~(cdmask)) | (zsstatus & (cdmask)); #ifdef PPS_SYNC s = splclock(); #ifdef PPS_NEW usec = timestamp.tv_usec; #else usec = pps_time.tv_usec; #endif #endif /* * time stamp */ uniqtime(&cdevent.tv); #ifdef PPS_SYNC (void)splx(s); #endif /* * logical state */ status = cd_invert ? (zsstatus & cdmask) == 0 : (zsstatus & cdmask) != 0; #ifdef PPS_SYNC if (status) { usec = cdevent.tv.tv_usec - usec; if (usec < 0) usec += 1000000; hardpps(&cdevent.tv, usec); } #endif q = za->za_ttycommon.t_readq; /* * ok - now the hard part - find ourself */ loopcheck = MAXDEPTH; while (q) { if (q->q_qinfo && q->q_qinfo->qi_minfo) { dname = q->q_qinfo->qi_minfo->mi_idname; if (!Strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname)) { /* * back home - phew (hopping along stream queues might * prove dangerous to your health) */ if ((((parsestream_t *)(void *)q->q_ptr)->parse_status & PARSE_ENABLE) && parse_iopps(&((parsestream_t *)(void *)q->q_ptr)->parse_io, (int)(status ? SYNC_ONE : SYNC_ZERO), &cdevent)) { /* * XXX - currently we do not pass up the message, as * we should. * for a correct behaviour wee need to block out * processing until parse_iodone has been posted via * a softcall-ed routine which does the message pass-up * right now PPS information relies on input being * received */ parse_iodone(&((parsestream_t *)(void *)q->q_ptr)->parse_io); } if (status) { ((parsestream_t *)(void *)q->q_ptr)->parse_ppsclockev.tv = cdevent.tv; ++(((parsestream_t *)(void *)q->q_ptr)->parse_ppsclockev.serial); } parseprintf(DD_ISR, ("zs_xsisr: CD event %s has been posted for \"%s\"\n", status ? "ONE" : "ZERO", dname)); break; } } q = q->q_next; if (!loopcheck--) { panic("zs_xsisr: STREAMS Queue corrupted - CD event"); } } /* * only pretend that CD has been handled */ ZSDELAY(2); if (!((za->za_rr0 ^ zsstatus) & ~(cdmask))) { /* * all done - kill status indication and return */ zsaddr->zscc_control = ZSWR0_RESET_STATUS; /* might kill other conditions here */ return 0; } } if (zsstatus & cdmask) /* fake CARRIER status */ za->za_flags |= ZAS_CARR_ON; else za->za_flags &= ~ZAS_CARR_ON; /* * we are now gathered here to process some unusual external status * interrupts. * any CD events have also been handled and shouldn't be processed * by the original routine (unless we have a VERY busy port pin) * some initializations are done here, which could have been done before for * both code paths but have been avoided for minimum path length to * the uniq_time routine */ dname = (char *) 0; q = za->za_ttycommon.t_readq; loopcheck = MAXDEPTH; /* * the real thing for everything else ... */ while (q) { if (q->q_qinfo && q->q_qinfo->qi_minfo) { dname = q->q_qinfo->qi_minfo->mi_idname; if (!Strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname)) { register int (*zsisr) (struct zscom *); /* * back home - phew (hopping along stream queues might * prove dangerous to your health) */ if ((zsisr = ((struct savedzsops *)((parsestream_t *)(void *)q->q_ptr)->parse_data)->oldzsops->zsop_xsint)) return zsisr(zs); else panic("zs_xsisr: unable to locate original ISR"); parseprintf(DD_ISR, ("zs_xsisr: non CD event was processed for \"%s\"\n", dname)); /* * now back to our program ... */ return 0; } } q = q->q_next; if (!loopcheck--) { panic("zs_xsisr: STREAMS Queue corrupted - non CD event"); } } /* * last resort - shouldn't even come here as it indicates * corrupted TTY structures */ printf("zs_zsisr: looking for \"%s\" - found \"%s\" - taking EMERGENCY path\n", parseinfo.st_rdinit->qi_minfo->mi_idname, dname ? dname : "-NIL-"); if (emergencyzs && emergencyzs->zsop_xsint) emergencyzs->zsop_xsint(zs); else panic("zs_xsisr: no emergency ISR handler"); return 0; }
static int init_zs_linemon( register queue_t *q, register queue_t *my_q ) { register struct zscom *zs; register struct savedzsops *szs; register parsestream_t *parsestream = (parsestream_t *)(void *)my_q->q_ptr; /* * we expect the zsaline pointer in the q_data pointer * from there on we insert our on EXTERNAL/STATUS ISR routine * into the interrupt path, before the standard handler */ zs = ((struct zsaline *)(void *)q->q_ptr)->za_common; if (!zs) { /* * well - not found on startup - just say no (shouldn't happen though) */ return 0; } else { unsigned long s; /* * we do a direct replacement, in case others fiddle also * if somebody else grabs our hook and we disconnect * we are in DEEP trouble - panic is likely to be next, sorry */ szs = (struct savedzsops *)(void *)kmem_alloc(sizeof(struct savedzsops)); if (szs == (struct savedzsops *)0) { parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor NOT installed - no memory\n")); return 0; } else { parsestream->parse_data = (void *)szs; s = splhigh(); parsestream->parse_dqueue = q; /* remember driver */ szs->zsops = *zs->zs_ops; szs->zsops.zsop_xsint = zs_xsisr; /* place our bastard */ szs->oldzsops = zs->zs_ops; emergencyzs = zs->zs_ops; zsopinit(zs, &szs->zsops); /* hook it up */ (void) splx(s); parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor installed\n")); return 1; } } }