diff options
-rw-r--r-- | drivers/firewire/fw-cdev.c | 26 | ||||
-rw-r--r-- | include/linux/firewire-cdev.h | 15 |
2 files changed, 41 insertions, 0 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index b960fd996918..290d9f036199 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c @@ -25,11 +25,14 @@ #include <linux/device.h> #include <linux/vmalloc.h> #include <linux/poll.h> +#include <linux/preempt.h> +#include <linux/time.h> #include <linux/delay.h> #include <linux/mm.h> #include <linux/idr.h> #include <linux/compat.h> #include <linux/firewire-cdev.h> +#include <asm/system.h> #include <asm/uaccess.h> #include "fw-transaction.h" #include "fw-topology.h" @@ -811,6 +814,28 @@ 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) +{ + struct fw_cdev_get_cycle_timer *request = buffer; + struct fw_card *card = client->device->card; + unsigned long long bus_time; + struct timeval tv; + unsigned long flags; + + preempt_disable(); + local_irq_save(flags); + + bus_time = card->driver->get_bus_time(card); + do_gettimeofday(&tv); + + local_irq_restore(flags); + preempt_enable(); + + request->local_time = tv.tv_sec * 1000000ULL + tv.tv_usec; + request->cycle_timer = bus_time & 0xffffffff; + return 0; +} + static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { ioctl_get_info, ioctl_send_request, @@ -824,6 +849,7 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { ioctl_queue_iso, ioctl_start_iso, ioctl_stop_iso, + ioctl_get_cycle_timer, }; static int diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h index 1a45d6f41b09..0f0e271f97fa 100644 --- a/include/linux/firewire-cdev.h +++ b/include/linux/firewire-cdev.h @@ -178,6 +178,7 @@ union fw_cdev_event { #define FW_CDEV_IOC_QUEUE_ISO _IOWR('#', 0x09, struct fw_cdev_queue_iso) #define FW_CDEV_IOC_START_ISO _IOW('#', 0x0a, struct fw_cdev_start_iso) #define FW_CDEV_IOC_STOP_ISO _IOW('#', 0x0b, struct fw_cdev_stop_iso) +#define FW_CDEV_IOC_GET_CYCLE_TIMER _IOR('#', 0x0c, struct fw_cdev_get_cycle_timer) /* FW_CDEV_VERSION History * @@ -459,4 +460,18 @@ struct fw_cdev_stop_iso { __u32 handle; }; +/** + * 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 + * + * 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. + */ +struct fw_cdev_get_cycle_timer { + __u64 local_time; + __u32 cycle_timer; +}; + #endif /* _LINUX_FIREWIRE_CDEV_H */ |