Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abfe5a01 authored by Stefan Richter's avatar Stefan Richter
Browse files

firewire: cdev: add more flexible cycle timer ioctl

The system time from CLOCK_REALTIME is not monotonic, hence problematic
for the main user of the FW_CDEV_IOC_GET_CYCLE_TIMER ioctl.  This issue
exists in its successor ABI, i.e. raw1394, too.
http://subversion.ffado.org/ticket/242



We now offer an alternative ioctl which lets the caller choose between
CLOCK_REALTIME, CLOCK_MONOTONIC, and CLOCK_MONOTONIC_RAW as source of
the local time, very similar to the clock_gettime libc function.  The
format of the local time return value matches that of clock_gettime
(seconds and nanoseconds, instead of a single microseconds value from
the existing ioctl).

Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent fd6e0c51
Loading
Loading
Loading
Loading
+32 −6
Original line number Diff line number Diff line
@@ -1031,23 +1031,47 @@ static int ioctl_stop_iso(struct client *client, void *buffer)
	return fw_iso_context_stop(client->iso_context);
}

static int ioctl_get_cycle_timer(struct client *client, void *buffer)
static int ioctl_get_cycle_timer2(struct client *client, void *buffer)
{
	struct fw_cdev_get_cycle_timer *request = buffer;
	struct fw_cdev_get_cycle_timer2 *request = buffer;
	struct fw_card *card = client->device->card;
	struct timeval tv;
	struct timespec ts = {0, 0};
	u32 cycle_time;
	int ret = 0;

	local_irq_disable();

	cycle_time = card->driver->get_cycle_time(card);
	do_gettimeofday(&tv);

	switch (request->clk_id) {
	case CLOCK_REALTIME:      getnstimeofday(&ts);                   break;
	case CLOCK_MONOTONIC:     do_posix_clock_monotonic_gettime(&ts); break;
	case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts);                  break;
	default:
		ret = -EINVAL;
	}

	local_irq_enable();

	request->local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
	request->tv_sec		= ts.tv_sec;
	request->tv_nsec	= ts.tv_nsec;
	request->cycle_timer	= cycle_time;

	return ret;
}

static int ioctl_get_cycle_timer(struct client *client, void *buffer)
{
	struct fw_cdev_get_cycle_timer *request = buffer;
	struct fw_cdev_get_cycle_timer2 ct2;

	ct2.clk_id = CLOCK_REALTIME;
	ioctl_get_cycle_timer2(client, &ct2);

	request->local_time	= ct2.tv_sec * USEC_PER_SEC +
				  ct2.tv_nsec / NSEC_PER_USEC;
	request->cycle_timer	= ct2.cycle_timer;

	return 0;
}

@@ -1320,6 +1344,7 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
	ioctl_get_speed,
	ioctl_send_broadcast_request,
	ioctl_send_stream_packet,
	ioctl_get_cycle_timer2,
};

static int dispatch_ioctl(struct client *client,
@@ -1341,6 +1366,7 @@ static int dispatch_ioctl(struct client *client,
		struct fw_cdev_get_cycle_timer		_0c;
		struct fw_cdev_allocate_iso_resource	_0d;
		struct fw_cdev_send_stream_packet	_13;
		struct fw_cdev_get_cycle_timer2		_14;
	})];
	int ret;

+27 −4
Original line number Diff line number Diff line
@@ -248,6 +248,9 @@ union fw_cdev_event {
#define FW_CDEV_IOC_SEND_BROADCAST_REQUEST       _IOW('#', 0x12, struct fw_cdev_send_request)
#define FW_CDEV_IOC_SEND_STREAM_PACKET           _IOW('#', 0x13, struct fw_cdev_send_stream_packet)

/* available since kernel version 2.6.34 */
#define FW_CDEV_IOC_GET_CYCLE_TIMER2   _IOWR('#', 0x14, struct fw_cdev_get_cycle_timer2)

/*
 * FW_CDEV_VERSION History
 *  1  (2.6.22)  - initial version
@@ -544,20 +547,40 @@ struct fw_cdev_stop_iso {
/**
 * struct fw_cdev_get_cycle_timer - read cycle timer register
 * @local_time:   system time, in microseconds since the Epoch
 * @cycle_timer:  isochronous cycle timer, as per OHCI 1.1 clause 5.13
 * @cycle_timer:  Cycle Time register contents
 *
 * The %FW_CDEV_IOC_GET_CYCLE_TIMER ioctl reads the isochronous cycle timer
 * and also the system clock.  This allows to express the receive time of an
 * isochronous packet as a system time with microsecond accuracy.
 * and also the system clock (%CLOCK_REALTIME).  This allows to express the
 * receive time of an isochronous packet as a system time.
 *
 * @cycle_timer consists of 7 bits cycleSeconds, 13 bits cycleCount, and
 * 12 bits cycleOffset, in host byte order.
 * 12 bits cycleOffset, in host byte order.  Cf. the Cycle Time register
 * per IEEE 1394 or Isochronous Cycle Timer register per OHCI-1394.
 */
struct fw_cdev_get_cycle_timer {
	__u64 local_time;
	__u32 cycle_timer;
};

/**
 * struct fw_cdev_get_cycle_timer2 - read cycle timer register
 * @tv_sec:       system time, seconds
 * @tv_nsec:      system time, sub-seconds part in nanoseconds
 * @clk_id:       input parameter, clock from which to get the system time
 * @cycle_timer:  Cycle Time register contents
 *
 * The %FW_CDEV_IOC_GET_CYCLE_TIMER2 works like
 * %FW_CDEV_IOC_GET_CYCLE_TIMER but lets you choose a clock like with POSIX'
 * clock_gettime function.  Supported @clk_id values are POSIX' %CLOCK_REALTIME
 * and %CLOCK_MONOTONIC and Linux' %CLOCK_MONOTONIC_RAW.
 */
struct fw_cdev_get_cycle_timer2 {
	__s64 tv_sec;
	__s32 tv_nsec;
	__s32 clk_id;
	__u32 cycle_timer;
};

/**
 * struct fw_cdev_allocate_iso_resource - (De)allocate a channel or bandwidth
 * @closure:	Passed back to userspace in correponding iso resource events