drivers/ptp/ptp_chardev.c

Source file repositories/reference/linux-study-clean/drivers/ptp/ptp_chardev.c

File Facts

System
Linux kernel
Corpus path
drivers/ptp/ptp_chardev.c
Extension
.c
Size
17354 bytes
Lines
647
Domain
Driver Families
Bucket
drivers/ptp
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (perout->flags & PTP_PEROUT_DUTY_CYCLE) {
			/* The duty cycle must be subunitary. */
			if (perout->on.sec > perout->period.sec ||
			    (perout->on.sec == perout->period.sec &&
			     perout->on.nsec > perout->period.nsec))
				return -ERANGE;
		}

		if (perout->flags & PTP_PEROUT_PHASE) {
			/*
			 * The phase should be specified modulo the period,
			 * therefore anything equal or larger than 1 period
			 * is invalid.
			 */
			if (perout->phase.sec > perout->period.sec ||
			    (perout->phase.sec == perout->period.sec &&
			     perout->phase.nsec >= perout->period.nsec))
				return -ERANGE;
		}
	} else {
		perout->flags &= PTP_PEROUT_V1_VALID_FLAGS;
		memset(perout->rsv, 0, sizeof(perout->rsv));
	}

	if (perout->index >= ops->n_per_out)
		return -EINVAL;
	if (perout->flags & ~ops->supported_perout_flags)
		return -EOPNOTSUPP;

	scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &ptp->pincfg_mux)
		return ops->enable(ops, &req, perout->period.sec || perout->period.nsec);
}

static long ptp_enable_pps(struct ptp_clock *ptp, bool enable)
{
	struct ptp_clock_request req = { .type = PTP_CLK_REQ_PPS };
	struct ptp_clock_info *ops = ptp->info;

	if (!capable(CAP_SYS_TIME))
		return -EPERM;

	scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &ptp->pincfg_mux)
		return ops->enable(ops, &req, enable);
}

typedef int (*ptp_crosststamp_fn)(struct ptp_clock_info *,
				  struct system_device_crosststamp *);

static long ptp_sys_offset_precise(struct ptp_clock *ptp, void __user *arg,
				   ptp_crosststamp_fn crosststamp_fn)
{
	struct system_device_crosststamp xtstamp = { .clock_id = CLOCK_REALTIME };
	struct ptp_sys_offset_precise precise_offset;
	struct timespec64 ts;
	int err;

	if (!crosststamp_fn)
		return -EOPNOTSUPP;

	err = crosststamp_fn(ptp->info, &xtstamp);
	if (err)
		return err;

	memset(&precise_offset, 0, sizeof(precise_offset));
	ts = ktime_to_timespec64(xtstamp.device);
	precise_offset.device.sec = ts.tv_sec;
	precise_offset.device.nsec = ts.tv_nsec;
	ts = ktime_to_timespec64(xtstamp.sys_systime);
	precise_offset.sys_realtime.sec = ts.tv_sec;
	precise_offset.sys_realtime.nsec = ts.tv_nsec;
	ts = ktime_to_timespec64(xtstamp.sys_monoraw);
	precise_offset.sys_monoraw.sec = ts.tv_sec;
	precise_offset.sys_monoraw.nsec = ts.tv_nsec;

	return copy_to_user(arg, &precise_offset, sizeof(precise_offset)) ? -EFAULT : 0;
}

typedef int (*ptp_gettimex_fn)(struct ptp_clock_info *,
			       struct timespec64 *,
			       struct ptp_system_timestamp *);

static long ptp_sys_offset_extended(struct ptp_clock *ptp, void __user *arg,
				    ptp_gettimex_fn gettimex_fn)
{
	struct ptp_sys_offset_extended *extoff __free(kfree) = NULL;
	struct ptp_system_timestamp sts;

	if (!gettimex_fn)
		return -EOPNOTSUPP;

Annotation

Implementation Notes