From abfe5a01ef1e463cbafdae461b693db34e308c02 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 20 Feb 2010 12:13:49 +0100 Subject: [PATCH] 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: Stefan Richter --- drivers/firewire/core-cdev.c | 38 ++++++++++++++++++++++++++++++++------ include/linux/firewire-cdev.h | 31 +++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 3c1ac09..a4aa477 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -1031,22 +1031,46 @@ 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->cycle_timer = cycle_time; + 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; diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h index 520ecf8..baa8290 100644 --- a/include/linux/firewire-cdev.h +++ b/include/linux/firewire-cdev.h @@ -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,14 +547,15 @@ 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; @@ -559,6 +563,25 @@ struct fw_cdev_get_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 * @channels: Isochronous channels of which one is to be (de)allocated -- 2.7.4