diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-02-20 06:13:49 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-02-24 14:36:54 -0500 |
commit | abfe5a01ef1e463cbafdae461b693db34e308c02 (patch) | |
tree | e33056c7d8b80a3128f7714c31b083091be3ea9b | |
parent | fd6e0c518121d22b50060d26c8aec2b701c6aab7 (diff) |
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 <stefanr@s5r6.in-berlin.de>
-rw-r--r-- | drivers/firewire/core-cdev.c | 38 | ||||
-rw-r--r-- | 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 3c1ac0933d24..a4aa477b9b2c 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) | |||
1031 | return fw_iso_context_stop(client->iso_context); | 1031 | return fw_iso_context_stop(client->iso_context); |
1032 | } | 1032 | } |
1033 | 1033 | ||
1034 | static int ioctl_get_cycle_timer(struct client *client, void *buffer) | 1034 | static int ioctl_get_cycle_timer2(struct client *client, void *buffer) |
1035 | { | 1035 | { |
1036 | struct fw_cdev_get_cycle_timer *request = buffer; | 1036 | struct fw_cdev_get_cycle_timer2 *request = buffer; |
1037 | struct fw_card *card = client->device->card; | 1037 | struct fw_card *card = client->device->card; |
1038 | struct timeval tv; | 1038 | struct timespec ts = {0, 0}; |
1039 | u32 cycle_time; | 1039 | u32 cycle_time; |
1040 | int ret = 0; | ||
1040 | 1041 | ||
1041 | local_irq_disable(); | 1042 | local_irq_disable(); |
1042 | 1043 | ||
1043 | cycle_time = card->driver->get_cycle_time(card); | 1044 | cycle_time = card->driver->get_cycle_time(card); |
1044 | do_gettimeofday(&tv); | 1045 | |
1046 | switch (request->clk_id) { | ||
1047 | case CLOCK_REALTIME: getnstimeofday(&ts); break; | ||
1048 | case CLOCK_MONOTONIC: do_posix_clock_monotonic_gettime(&ts); break; | ||
1049 | case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break; | ||
1050 | default: | ||
1051 | ret = -EINVAL; | ||
1052 | } | ||
1045 | 1053 | ||
1046 | local_irq_enable(); | 1054 | local_irq_enable(); |
1047 | 1055 | ||
1048 | request->local_time = tv.tv_sec * 1000000ULL + tv.tv_usec; | 1056 | request->tv_sec = ts.tv_sec; |
1049 | request->cycle_timer = cycle_time; | 1057 | request->tv_nsec = ts.tv_nsec; |
1058 | request->cycle_timer = cycle_time; | ||
1059 | |||
1060 | return ret; | ||
1061 | } | ||
1062 | |||
1063 | static int ioctl_get_cycle_timer(struct client *client, void *buffer) | ||
1064 | { | ||
1065 | struct fw_cdev_get_cycle_timer *request = buffer; | ||
1066 | struct fw_cdev_get_cycle_timer2 ct2; | ||
1067 | |||
1068 | ct2.clk_id = CLOCK_REALTIME; | ||
1069 | ioctl_get_cycle_timer2(client, &ct2); | ||
1070 | |||
1071 | request->local_time = ct2.tv_sec * USEC_PER_SEC + | ||
1072 | ct2.tv_nsec / NSEC_PER_USEC; | ||
1073 | request->cycle_timer = ct2.cycle_timer; | ||
1050 | 1074 | ||
1051 | return 0; | 1075 | return 0; |
1052 | } | 1076 | } |
@@ -1320,6 +1344,7 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { | |||
1320 | ioctl_get_speed, | 1344 | ioctl_get_speed, |
1321 | ioctl_send_broadcast_request, | 1345 | ioctl_send_broadcast_request, |
1322 | ioctl_send_stream_packet, | 1346 | ioctl_send_stream_packet, |
1347 | ioctl_get_cycle_timer2, | ||
1323 | }; | 1348 | }; |
1324 | 1349 | ||
1325 | static int dispatch_ioctl(struct client *client, | 1350 | static int dispatch_ioctl(struct client *client, |
@@ -1341,6 +1366,7 @@ static int dispatch_ioctl(struct client *client, | |||
1341 | struct fw_cdev_get_cycle_timer _0c; | 1366 | struct fw_cdev_get_cycle_timer _0c; |
1342 | struct fw_cdev_allocate_iso_resource _0d; | 1367 | struct fw_cdev_allocate_iso_resource _0d; |
1343 | struct fw_cdev_send_stream_packet _13; | 1368 | struct fw_cdev_send_stream_packet _13; |
1369 | struct fw_cdev_get_cycle_timer2 _14; | ||
1344 | })]; | 1370 | })]; |
1345 | int ret; | 1371 | int ret; |
1346 | 1372 | ||
diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h index 520ecf86cbb3..baa8290c8416 100644 --- a/include/linux/firewire-cdev.h +++ b/include/linux/firewire-cdev.h | |||
@@ -248,6 +248,9 @@ union fw_cdev_event { | |||
248 | #define FW_CDEV_IOC_SEND_BROADCAST_REQUEST _IOW('#', 0x12, struct fw_cdev_send_request) | 248 | #define FW_CDEV_IOC_SEND_BROADCAST_REQUEST _IOW('#', 0x12, struct fw_cdev_send_request) |
249 | #define FW_CDEV_IOC_SEND_STREAM_PACKET _IOW('#', 0x13, struct fw_cdev_send_stream_packet) | 249 | #define FW_CDEV_IOC_SEND_STREAM_PACKET _IOW('#', 0x13, struct fw_cdev_send_stream_packet) |
250 | 250 | ||
251 | /* available since kernel version 2.6.34 */ | ||
252 | #define FW_CDEV_IOC_GET_CYCLE_TIMER2 _IOWR('#', 0x14, struct fw_cdev_get_cycle_timer2) | ||
253 | |||
251 | /* | 254 | /* |
252 | * FW_CDEV_VERSION History | 255 | * FW_CDEV_VERSION History |
253 | * 1 (2.6.22) - initial version | 256 | * 1 (2.6.22) - initial version |
@@ -544,14 +547,15 @@ struct fw_cdev_stop_iso { | |||
544 | /** | 547 | /** |
545 | * struct fw_cdev_get_cycle_timer - read cycle timer register | 548 | * struct fw_cdev_get_cycle_timer - read cycle timer register |
546 | * @local_time: system time, in microseconds since the Epoch | 549 | * @local_time: system time, in microseconds since the Epoch |
547 | * @cycle_timer: isochronous cycle timer, as per OHCI 1.1 clause 5.13 | 550 | * @cycle_timer: Cycle Time register contents |
548 | * | 551 | * |
549 | * The %FW_CDEV_IOC_GET_CYCLE_TIMER ioctl reads the isochronous cycle timer | 552 | * The %FW_CDEV_IOC_GET_CYCLE_TIMER ioctl reads the isochronous cycle timer |
550 | * and also the system clock. This allows to express the receive time of an | 553 | * and also the system clock (%CLOCK_REALTIME). This allows to express the |
551 | * isochronous packet as a system time with microsecond accuracy. | 554 | * receive time of an isochronous packet as a system time. |
552 | * | 555 | * |
553 | * @cycle_timer consists of 7 bits cycleSeconds, 13 bits cycleCount, and | 556 | * @cycle_timer consists of 7 bits cycleSeconds, 13 bits cycleCount, and |
554 | * 12 bits cycleOffset, in host byte order. | 557 | * 12 bits cycleOffset, in host byte order. Cf. the Cycle Time register |
558 | * per IEEE 1394 or Isochronous Cycle Timer register per OHCI-1394. | ||
555 | */ | 559 | */ |
556 | struct fw_cdev_get_cycle_timer { | 560 | struct fw_cdev_get_cycle_timer { |
557 | __u64 local_time; | 561 | __u64 local_time; |
@@ -559,6 +563,25 @@ struct fw_cdev_get_cycle_timer { | |||
559 | }; | 563 | }; |
560 | 564 | ||
561 | /** | 565 | /** |
566 | * struct fw_cdev_get_cycle_timer2 - read cycle timer register | ||
567 | * @tv_sec: system time, seconds | ||
568 | * @tv_nsec: system time, sub-seconds part in nanoseconds | ||
569 | * @clk_id: input parameter, clock from which to get the system time | ||
570 | * @cycle_timer: Cycle Time register contents | ||
571 | * | ||
572 | * The %FW_CDEV_IOC_GET_CYCLE_TIMER2 works like | ||
573 | * %FW_CDEV_IOC_GET_CYCLE_TIMER but lets you choose a clock like with POSIX' | ||
574 | * clock_gettime function. Supported @clk_id values are POSIX' %CLOCK_REALTIME | ||
575 | * and %CLOCK_MONOTONIC and Linux' %CLOCK_MONOTONIC_RAW. | ||
576 | */ | ||
577 | struct fw_cdev_get_cycle_timer2 { | ||
578 | __s64 tv_sec; | ||
579 | __s32 tv_nsec; | ||
580 | __s32 clk_id; | ||
581 | __u32 cycle_timer; | ||
582 | }; | ||
583 | |||
584 | /** | ||
562 | * struct fw_cdev_allocate_iso_resource - (De)allocate a channel or bandwidth | 585 | * struct fw_cdev_allocate_iso_resource - (De)allocate a channel or bandwidth |
563 | * @closure: Passed back to userspace in correponding iso resource events | 586 | * @closure: Passed back to userspace in correponding iso resource events |
564 | * @channels: Isochronous channels of which one is to be (de)allocated | 587 | * @channels: Isochronous channels of which one is to be (de)allocated |