#define SIGNAL 0 #define NO_SIGNAL PARPORT_CONTROL_STROBE
/* module parameters */
#define SEND_DELAY_MAX 100000
staticunsignedint send_delay = 30000;
MODULE_PARM_DESC(delay, "Delay between setting and dropping the signal (ns)");
module_param_named(delay, send_delay, uint, 0);
#define SAFETY_INTERVAL 3000 /* set the hrtimer earlier for safety (ns) */
/* internal per port structure */ struct pps_generator_pp { struct pardevice *pardev; /* parport device */ struct hrtimer timer; long port_write_time; /* calibrated port write time (ns) */
};
/* We have to disable interrupts here. The idea is to prevent * other interrupts on the same processor to introduce random * lags while polling the clock. ktime_get_real_ts64() takes <1us on * most machines while other interrupt handlers can take much * more potentially. * * NB: approx time with blocked interrupts = * send_delay + 3 * SAFETY_INTERVAL
*/
local_irq_save(flags);
/* first of all we get the time stamp... */
ktime_get_real_ts64(&ts1);
expire_time = ktime_to_timespec64(hrtimer_get_softexpires(timer));
dev = container_of(timer, struct pps_generator_pp, timer);
lim = NSEC_PER_SEC - send_delay - dev->port_write_time;
/* check if we are late */ if (expire_time.tv_sec != ts1.tv_sec || ts1.tv_nsec > lim) {
local_irq_restore(flags);
pr_err("we are late this time %lld.%09ld\n",
(s64)ts1.tv_sec, ts1.tv_nsec); goto done;
}
/* busy loop until the time is right for an assert edge */ do {
ktime_get_real_ts64(&ts2);
} while (expire_time.tv_sec == ts2.tv_sec && ts2.tv_nsec < lim);
/* set the signal */
port = dev->pardev->port;
port->ops->write_control(port, SIGNAL);
/* busy loop until the time is right for a clear edge */
lim = NSEC_PER_SEC - dev->port_write_time; do {
ktime_get_real_ts64(&ts2);
} while (expire_time.tv_sec == ts2.tv_sec && ts2.tv_nsec < lim);
/* unset the signal */
port->ops->write_control(port, NO_SIGNAL);
ktime_get_real_ts64(&ts3);
local_irq_restore(flags);
/* update calibrated port write time */
dts = timespec64_sub(ts3, ts2);
dev->port_write_time =
(dev->port_write_time + timespec64_to_ns(&dts)) >> 1;
done: /* update calibrated hrtimer error */
dts = timespec64_sub(ts1, expire_time);
delta = timespec64_to_ns(&dts); /* If the new error value is bigger then the old, use the new * value, if not then slowly move towards the new value. This * way it should be safe in bad conditions and efficient in * good conditions.
*/ if (delta >= hrtimer_error)
hrtimer_error = delta; else
hrtimer_error = (3 * hrtimer_error + delta) >> 2;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.