static void xpp_set_syncer(xbus_t *xbus, bool on) { if(syncer != xbus && on) { XBUS_DBG(SYNC, xbus, "New syncer\n"); syncer = xbus; } else if(syncer == xbus && !on) { XBUS_DBG(SYNC, xbus, "Lost syncer\n"); syncer = NULL; } else XBUS_DBG(SYNC, xbus, "ignore %s (current syncer: %s)\n", (on)?"ON":"OFF", (syncer) ? syncer->busname : "NO-SYNC"); }
static void reset_sync_counters(void) { int i; //DBG(SYNC, "%d\n", atomic_read(&xpp_tick_counter)); for(i = 0; i < MAX_BUSES; i++) { xbus_t *xbus = get_xbus(i); if(!xbus) continue; /* * Don't send to non self_ticking Astribanks: * - Maybe they didn't finish initialization * - Or maybe they didn't answer us in the first place (e.g: wrong firmware version, etc). */ if (TRANSPORT_RUNNING(xbus) && xbus->self_ticking) { if(XBUS_GET(xbus)) { /* Reset sync LEDs once in a while */ CALL_PROTO(GLOBAL, RESET_SYNC_COUNTERS, xbus, NULL); XBUS_PUT(xbus); } else { static int rate_limit; if((rate_limit++ % 1003) == 0) XBUS_DBG(GENERAL, xbus, "Dropped packet. Is shutting down. (%d)\n", rate_limit); } } put_xbus(xbus); } }
void xbus_set_command_timer(xbus_t *xbus, bool on) { XBUS_DBG(SYNC, xbus, "%s\n", (on)?"ON":"OFF"); if(on) { if(!timer_pending(&xbus->command_timer)) { XBUS_DBG(SYNC, xbus, "add_timer\n"); xbus->command_timer.function = xbus_command_timer; xbus->command_timer.data = (unsigned long)xbus; xbus->command_timer.expires = jiffies + 1; add_timer(&xbus->command_timer); } } else if(timer_pending(&xbus->command_timer)) { XBUS_DBG(SYNC, xbus, "del_timer\n"); del_timer(&xbus->command_timer); } }
static void xpp_dev_release(struct device *dev) { xbus_t *xbus; BUG_ON(!dev); xbus = dev_to_xbus(dev); XBUS_DBG(GENERAL, xbus, "\n"); }
static int astribank_probe(struct device *dev) { xbus_t *xbus; xbus = dev_to_xbus(dev); XBUS_DBG(DEVICES, xbus, "SYSFS\n"); return 0; }
/* * called from elect_syncer() * if new_syncer is NULL, than we move all to SYNC_MODE_PLL * for ZAPTEL sync. */ static void update_sync_master(xbus_t *new_syncer) { const char *msg = (force_zaptel_sync) ? "ZAPTEL" : "NO-SYNC"; int i; unsigned long flags; DBG(SYNC, "%s => %s\n", (syncer) ? syncer->busname : msg, (new_syncer) ? new_syncer->busname : msg); /* * This global locking protects: * - The ref_ticker so it won't be used while we change it. * - The xbus_drift_clear() from corrupting driftinfo data. */ spin_lock_irqsave(&ref_ticker_lock, flags); if(syncer) xbus_drift_clear(syncer); /* Clean old data */ if(new_syncer) { XBUS_DBG(SYNC, new_syncer, "pcm_rx_counter=%d\n", atomic_read(&new_syncer->pcm_rx_counter)); force_zaptel_sync = 0; ref_ticker = &new_syncer->ticker; xbus_drift_clear(new_syncer); /* Clean new data */ xbus_request_sync(new_syncer, SYNC_MODE_AB); } else if(force_zaptel_sync) { ref_ticker = &zaptel_ticker; } else { ref_ticker = NULL; } spin_unlock_irqrestore(&ref_ticker_lock, flags); DBG(SYNC, "stop unwanted syncers\n"); /* Shut all down except the wanted sync master */ for(i = 0; i < MAX_BUSES; i++) { xbus_t *xbus = get_xbus(i); if(!xbus) continue; if(TRANSPORT_RUNNING(xbus) && xbus != new_syncer) { if(xbus->self_ticking) xbus_request_sync(xbus, SYNC_MODE_PLL); else XBUS_DBG(SYNC, xbus, "Not self_ticking yet. Ignore\n"); } put_xbus(xbus); } }
void astribank_uevent_send(xbus_t *xbus, enum kobject_action act) { struct kobject *kobj; kobj = &xbus->astribank.kobj; XBUS_DBG(DEVICES, xbus, "SYFS bus_id=%s action=%d\n", dev_name(&xbus->astribank), act); kobject_uevent(kobj, act); }
int xbus_sysfs_create(xbus_t *xbus) { struct device *astribank; int ret = 0; BUG_ON(!xbus); astribank = &xbus->astribank; BUG_ON(!astribank); XBUS_DBG(GENERAL, xbus, "\n"); device_initialize(astribank); astribank->bus = &xpp_bus_type; astribank->parent = &xpp_bus; snprintf(astribank->bus_id, BUS_ID_SIZE, "xbus-%02d", xbus->num); astribank->driver_data = NULL; /* override below */ astribank->release = xpp_dev_release; ret = device_register(astribank); if(ret) { XBUS_ERR(xbus, "%s: device_add failed: %d\n", __FUNCTION__, ret); goto out; } ret = device_create_file(astribank, &dev_attr_connector); if(ret) { XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret); goto out; } ret = device_create_file(astribank, &dev_attr_label); if(ret) { XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret); goto out; } ret = device_create_file(astribank, &dev_attr_status); if(ret) { XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret); goto out; } ret = device_create_file(astribank, &dev_attr_timing); if(ret) { XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret); goto out; } ret = device_create_file(astribank, &dev_attr_cls); if(ret) { XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret); goto out; } #ifdef SAMPLE_TICKS ret = device_create_file(astribank, &dev_attr_samples); if(ret) { XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret); goto out; } #endif astribank->driver_data = xbus; /* Everything is good */ out: return ret; }
/* * Called when the Astribank replies to a sync change request */ void got_new_syncer(xbus_t *xbus, enum sync_mode mode, int drift) { unsigned long flags; XBUS_DBG(SYNC, xbus, "Mode %s (%d), drift=%d (pcm_rx_counter=%d)\n", sync_mode_name(mode), mode, drift, atomic_read(&xbus->pcm_rx_counter)); spin_lock_irqsave(&xbus->lock, flags); xbus->sync_adjustment = (signed char)drift; if(xbus->sync_mode == mode) { XBUS_DBG(SYNC, xbus, "Already in mode '%s'. Ignored\n", sync_mode_name(mode)); goto out; } switch(mode) { case SYNC_MODE_AB: xbus->sync_mode = mode; xbus_set_command_timer(xbus, 0); xbus->self_ticking = 1; xpp_set_syncer(xbus, 1); global_ticker = xbus; break; case SYNC_MODE_PLL: xbus->sync_mode = mode; xbus_set_command_timer(xbus, 0); xbus->self_ticking = 1; xpp_set_syncer(xbus, 0); global_ticker = xbus; break; case SYNC_MODE_NONE: /* lost sync source */ xbus->sync_mode = mode; xbus_set_command_timer(xbus, 1); xbus->self_ticking = 0; xpp_set_syncer(xbus, 0); break; case SYNC_MODE_QUERY: /* ignore */ break; default: XBUS_ERR(xbus, "%s: unknown mode=0x%X\n", __FUNCTION__, mode); } out: spin_unlock_irqrestore(&xbus->lock, flags); }
int zaptel_sync_tick(struct zt_span *span, int is_master) { xpd_t *xpd = span->pvt; static int redundant_ticks; /* for extra spans */ struct timeval now; if(!force_zaptel_sync) goto noop; do_gettimeofday(&now); BUG_ON(!xpd); /* * Detect if any of our spans is zaptel sync master */ if(is_master) { static int rate_limit; if(xpd->xbus != syncer && ((rate_limit % 1003) == 0)) { XPD_ERR(xpd, "Zaptel master, but syncer=%s\n", xpd->xbus->busname); } if((rate_limit % 5003) == 0) XPD_NOTICE(xpd, "Zaptel master: ignore ZAPTEL sync\n"); rate_limit++; goto noop; } /* Now we know for sure someone else is zaptel sync master */ if(syncer) { static int rate_limit; if((rate_limit++ % 5003) == 0) XBUS_DBG(SYNC, syncer, "Already a syncer, ignore ZAPTEL sync\n"); goto noop; } /* ignore duplicate calls from all our registered spans */ if((redundant_ticks++ % total_registered_spans()) != 0) { #if 0 static int rate_limit; if((rate_limit++ % 1003) < 16) XPD_NOTICE(xpd, "boop (%d)\n", zaptel_tick_count); #endif goto noop; } xpp_ticker_step(&zaptel_ticker, &now); zaptel_tick_count++; //flip_parport_bit(1); return 0; noop: return 0; /* No auto sync from zaptel */ }
static int xframe_receive_cmd(xbus_t *xbus, xframe_t *xframe) { byte *xframe_end; xpacket_t *pack; byte *p; int len; int ret; if(debug & DBG_COMMANDS) dump_xframe("RX-CMD", xbus, xframe, DBG_ANY); p = xframe->packets; xframe_end = p + XFRAME_LEN(xframe); do { pack = (xpacket_t *)p; len = XPACKET_LEN(pack); /* Sanity checks */ if(unlikely(XPACKET_OP(pack) == XPROTO_NAME(GLOBAL,PCM_READ))) { static int rate_limit; if((rate_limit++ % 1003) == 0) { XBUS_DBG(GENERAL, xbus, "A PCM packet within a Non-PCM xframe\n"); dump_xframe("In Non-PCM xframe", xbus, xframe, debug); } ret = -EPROTO; goto out; } p += len; if(p > xframe_end || len < RPACKET_HEADERSIZE) { static int rate_limit; if((rate_limit++ % 1003) == 0) { XBUS_NOTICE(xbus, "Invalid packet length %d\n", len); dump_xframe("BAD LENGTH", xbus, xframe, debug); } ret = -EPROTO; goto out; } ret = packet_process(xbus, pack); if(unlikely(ret < 0)) break; } while(p < xframe_end); out: FREE_RECV_XFRAME(xbus, xframe); return ret; }
static void send_drift(xbus_t *xbus, int drift) { struct timeval now; const char *msg; BUG_ON(abs(drift) > SYNC_ADJ_MAX); do_gettimeofday(&now); if(drift > xbus->sync_adjustment) msg = "up"; else msg = "down"; XBUS_DBG(SYNC, xbus, "%sDRIFT adjust %s (%d) (last update %ld seconds ago)\n", (disable_pll_sync) ? "Fake " : "", msg, drift, now.tv_sec - xbus->pll_updated_at); if(!disable_pll_sync) CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_PLL, drift); xbus->pll_updated_at = now.tv_sec; }
static DEVICE_ATTR_WRITER(xbus_state_store, dev, buf, count) { xbus_t *xbus; xbus = dev_to_xbus(dev); XBUS_DBG(GENERAL, xbus, "%s\n", buf); if (strncmp(buf, "stop", 4) == 0) xbus_deactivate(xbus); else if (XBUS_IS(xbus, IDLE) && strncmp(buf, "start", 5) == 0) xbus_activate(xbus); else { XBUS_NOTICE(xbus, "%s: Illegal action %s in state %s. Ignored.\n", __func__, buf, xbus_statename(XBUS_STATE(xbus))); return -EINVAL; } return count; }
int xframe_receive(xbus_t *xbus, xframe_t *xframe) { int ret = 0; struct timeval now; struct timeval tv_received; int usec; if(XFRAME_LEN(xframe) < RPACKET_HEADERSIZE) { static int rate_limit; if((rate_limit++ % 1003) == 0) { XBUS_NOTICE(xbus, "short xframe\n"); dump_xframe("short xframe", xbus, xframe, debug); } FREE_RECV_XFRAME(xbus, xframe); return -EPROTO; } if(!XBUS_FLAGS(xbus, CONNECTED)) { XBUS_DBG(GENERAL, xbus, "Dropped xframe. Is shutting down.\n"); return -ENODEV; } tv_received = xframe->tv_received; /* * We want to check that xframes do not mix PCM and other commands */ if(XPACKET_IS_PCM((xpacket_t *)xframe->packets)) { if(!XBUS_IS(xbus, READY)) FREE_RECV_XFRAME(xbus, xframe); else xframe_receive_pcm(xbus, xframe); } else { XBUS_COUNTER(xbus, RX_CMD)++; ret = xframe_receive_cmd(xbus, xframe); } /* Calculate total processing time */ do_gettimeofday(&now); usec = (now.tv_sec - tv_received.tv_sec) * 1000000 + now.tv_usec - tv_received.tv_usec; if(usec > xbus->max_rx_process) xbus->max_rx_process = usec; return ret; }
void xbus_sysfs_remove(xbus_t *xbus) { struct device *astribank; BUG_ON(!xbus); XBUS_DBG(GENERAL, xbus, "\n"); astribank = &xbus->astribank; BUG_ON(!astribank); if(!astribank->driver_data) return; BUG_ON(astribank->driver_data != xbus); #ifdef SAMPLE_TICKS device_remove_file(&xbus->astribank, &dev_attr_samples); #endif device_remove_file(&xbus->astribank, &dev_attr_cls); device_remove_file(&xbus->astribank, &dev_attr_timing); device_remove_file(&xbus->astribank, &dev_attr_status); device_remove_file(&xbus->astribank, &dev_attr_label); device_remove_file(&xbus->astribank, &dev_attr_connector); device_unregister(&xbus->astribank); }
static inline void pcm_frame_out(xbus_t *xbus, xframe_t *xframe) { unsigned long flags; struct timeval now; unsigned long usec; spin_lock_irqsave(&xbus->lock, flags); do_gettimeofday(&now); if(unlikely(disable_pcm || !TRANSPORT_RUNNING(xbus))) goto dropit; if(XPACKET_ADDR_SYNC((xpacket_t *)xframe->packets)) { usec = usec_diff(&now, &xbus->last_tx_sync); xbus->last_tx_sync = now; /* ignore startup statistics */ if(likely(atomic_read(&xbus->pcm_rx_counter) > BIG_TICK_INTERVAL)) { if(abs(usec - 1000) > TICK_TOLERANCE) { static int rate_limit; if((rate_limit++ % 5003) == 0) XBUS_DBG(SYNC, xbus, "Bad PCM TX timing(%d): usec=%ld.\n", rate_limit, usec); } if(usec > xbus->max_tx_sync) xbus->max_tx_sync = usec; if(usec < xbus->min_tx_sync) xbus->min_tx_sync = usec; } } spin_unlock_irqrestore(&xbus->lock, flags); /* OK, really send it */ if(debug & DBG_PCM ) dump_xframe("TX_XFRAME_PCM", xbus, xframe, debug); send_pcm_frame(xbus, xframe); XBUS_COUNTER(xbus, TX_XFRAME_PCM)++; return; dropit: spin_unlock_irqrestore(&xbus->lock, flags); FREE_SEND_XFRAME(xbus, xframe); }
void elect_syncer(const char *msg) { int i; int j; uint timing_priority = 0; xpd_t *best_xpd = NULL; xbus_t *the_xbus = NULL; for(i = 0; i < MAX_BUSES; i++) { xbus_t *xbus = get_xbus(i); if(!xbus) continue; if(!the_xbus) the_xbus = xbus; if (TRANSPORT_RUNNING(xbus)) { for(j = 0; j < MAX_XPDS; j++) { xpd_t *xpd = xpd_of(xbus, j); if(!xpd || !xpd->card_present) continue; if(xpd->timing_priority > timing_priority) { timing_priority = xpd->timing_priority; best_xpd = xpd; } } } put_xbus(xbus); } if(best_xpd) { the_xbus = best_xpd->xbus; XPD_DBG(SYNC, best_xpd, "%s: elected with priority %d\n", msg, timing_priority); } else if(the_xbus) { XBUS_DBG(SYNC, the_xbus, "%s: elected\n", msg); } else DBG(SYNC, "%s: No more syncers\n", msg); if(the_xbus != syncer) update_sync_master(the_xbus); }
static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv) { struct xpp_drift *driftinfo = &xbus->drift; struct xpp_ticker *ticker = &xbus->ticker; unsigned long flags; bool cycled; spin_lock_irqsave(&driftinfo->lock, flags); cycled = xpp_ticker_step(&xbus->ticker, tv); if(ref_ticker && syncer && xbus->sync_mode == SYNC_MODE_PLL) { int new_delta_tick = ticker->count - ref_ticker->count; int lost_ticks = new_delta_tick - driftinfo->delta_tick; driftinfo->delta_tick = new_delta_tick; if(lost_ticks) { driftinfo->lost_ticks++; driftinfo->lost_tick_count += abs(lost_ticks); XBUS_DBG(SYNC, xbus, "Lost %d tick%s\n", lost_ticks, (abs(lost_ticks) > 1) ? "s": ""); ticker->cycle = SYNC_ADJ_QUICK; if(abs(lost_ticks) > 100) ticker->count = ref_ticker->count; } else { long usec_delta; bool nofix = 0; usec_delta = (long)usec_diff( &ticker->last_sample.tv, &ref_ticker->last_sample.tv); usec_delta -= driftinfo->wanted_offset; sample_tick(xbus, usec_delta); if(abs(usec_delta) > 300) { /* * We are close to the edge, send a brutal * fix, and skip calculation until next time. */ if(usec_delta > 0 && xbus->sync_adjustment > -SYNC_ADJ_MAX) { XBUS_DBG(SYNC, xbus, "Pullback usec_delta=%ld\n", usec_delta); send_drift(xbus, -SYNC_ADJ_MAX); /* emergency push */ } if(usec_delta < 0 && xbus->sync_adjustment < SYNC_ADJ_MAX) { XBUS_DBG(SYNC, xbus, "Pushback usec_delta=%ld\n", usec_delta); send_drift(xbus, SYNC_ADJ_MAX); /* emergency push */ } ticker->cycle = SYNC_ADJ_QUICK; nofix = 1; } else { /* good data, use it */ if(usec_delta > driftinfo->delta_max) driftinfo->delta_max = usec_delta; if(usec_delta < driftinfo->delta_min) driftinfo->delta_min = usec_delta; } if(!nofix && cycled) { int offset = 0; driftinfo->median = (driftinfo->delta_max + driftinfo->delta_min) / 2; driftinfo->jitter = driftinfo->delta_max - driftinfo->delta_min; if(abs(driftinfo->median) >= 150) { /* more than 1 usb uframe */ int factor = abs(driftinfo->median) / 125; factor = 1 + (factor * 8000) / ticker->cycle; if(driftinfo->median > 0) offset = driftinfo->calc_drift - factor; else offset = driftinfo->calc_drift + factor; /* for large median, push some more */ if(abs(driftinfo->median) >= 300) { /* more than 2 usb uframes */ ticker->cycle = SYNC_ADJ_QUICK; XBUS_NOTICE(xbus, "Back to quick: median=%d\n", driftinfo->median); } } else { ticker->cycle += 500; if(ticker->cycle >= SYNC_ADJ_SLOW) ticker->cycle = SYNC_ADJ_SLOW; } driftinfo->calc_drift = offset; XBUS_DBG(SYNC, xbus, "ADJ: min=%d max=%d jitter=%d median=%d offset=%d\n", driftinfo->delta_min, driftinfo->delta_max, driftinfo->jitter, driftinfo->median, offset); if(offset < -SYNC_ADJ_MAX) offset = -SYNC_ADJ_MAX; if(offset > SYNC_ADJ_MAX) offset = SYNC_ADJ_MAX; xbus->sync_adjustment_offset = offset; if(xbus != syncer && xbus->sync_adjustment != offset) send_drift(xbus, offset); driftinfo_recalc(driftinfo); } } } spin_unlock_irqrestore(&driftinfo->lock, flags); }
void xbus_request_sync(xbus_t *xbus, enum sync_mode mode) { BUG_ON(!xbus); XBUS_DBG(SYNC, xbus, "sent request (mode=%d)\n", mode); CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, mode, 0); }