From 38318cdddf26419d60ce35eee46ec855a187e8ff Mon Sep 17 00:00:00 2001
From: Folkert de Vries <folkert@folkertdev.nl>
Date: Wed, 20 Nov 2024 21:23:26 +0100
Subject: [PATCH] add `ptp_clock_caps`

---
 libc-test/build.rs               | 13 +++++++++++--
 libc-test/semver/linux.txt       |  2 ++
 src/unix/linux_like/linux/mod.rs | 19 +++++++++++++++----
 3 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/libc-test/build.rs b/libc-test/build.rs
index 5aa5636b953e..617d9e93686d 100644
--- a/libc-test/build.rs
+++ b/libc-test/build.rs
@@ -3885,7 +3885,8 @@ fn test_linux(target: &str) {
                 return true;
             }
             // FIXME: Requires >= 5.4 kernel headers
-            if name == "PTP_ENABLE_PPS2" 
+            if name == "PTP_CLOCK_GETCAPS2"
+                || name == "PTP_ENABLE_PPS2" 
                 || name == "PTP_EXTTS_REQUEST2"
                 || name == "PTP_PEROUT_REQUEST2"
                 || name == "PTP_PIN_GETFUNC2"
@@ -4333,7 +4334,11 @@ fn test_linux(target: &str) {
         // `anonymous_1` is an anonymous union
         (struct_ == "ptp_perout_request" && field == "anonymous_1") ||
         // `anonymous_2` is an anonymous union
-        (struct_ == "ptp_perout_request" && field == "anonymous_2")
+        (struct_ == "ptp_perout_request" && field == "anonymous_2") ||
+        // FIXME(linux): `adjust_phase` requires >= 5.7 kernel headers
+        // FIXME(linux): `max_phase_adj` requires >= 5.19 kernel headers
+        // the rsv field shrunk when those fields got added, so is omitted too
+        (struct_ == "ptp_clock_caps" && (loongarch64 || sparc64) && (["adjust_phase", "max_phase_adj", "rsv"].contains(&field)))
     });
 
     cfg.volatile_item(|i| {
@@ -4410,6 +4415,10 @@ fn test_linux(target: &str) {
         (struct_ == "ptp_perout_request" && field == "anonymous_1") ||
         // `anonymous_2` is an anonymous union
         (struct_ == "ptp_perout_request" && field == "anonymous_2") ||
+        // FIXME(linux): `adjust_phase` requires >= 5.7 kernel headers
+        // FIXME(linux): `max_phase_adj` requires >= 5.19 kernel headers
+        // the rsv field shrunk when those fields got added, so is omitted too
+        (struct_ == "ptp_clock_caps" && (loongarch64 || sparc64) && (["adjust_phase", "max_phase_adj", "rsv"].contains(&field))) ||
         // invalid application of 'sizeof' to incomplete type 'long unsigned int[]'
         (musl && struct_ == "mcontext_t" && field == "__extcontext" && loongarch64) ||
         // FIXME(#4121): a new field was added from `f_spare`
diff --git a/libc-test/semver/linux.txt b/libc-test/semver/linux.txt
index a983d62341dc..acce49b096d5 100644
--- a/libc-test/semver/linux.txt
+++ b/libc-test/semver/linux.txt
@@ -2252,6 +2252,7 @@ PTHREAD_PRIO_PROTECT
 PTHREAD_PROCESS_PRIVATE
 PTHREAD_PROCESS_SHARED
 PTHREAD_STACK_MIN
+PTP_CLOCK_GETCAPS2
 PTP_ENABLE_PPS
 PTP_ENABLE_PPS2
 PTP_EXTTS_REQUEST
@@ -3945,6 +3946,7 @@ pthread_spin_lock
 pthread_spin_trylock
 pthread_spin_unlock
 pthread_spinlock_t
+ptp_clock_caps
 ptp_clock_time
 ptp_extts_event
 ptp_extts_request
diff --git a/src/unix/linux_like/linux/mod.rs b/src/unix/linux_like/linux/mod.rs
index 2bfd2fc145a9..4094374280ca 100644
--- a/src/unix/linux_like/linux/mod.rs
+++ b/src/unix/linux_like/linux/mod.rs
@@ -1195,6 +1195,19 @@ s! {
         pub rsv: [::c_uint; 5],
     }
 
+    pub struct ptp_clock_caps {
+        pub max_adj: ::c_int,
+        pub n_alarm: ::c_int,
+        pub n_ext_ts: ::c_int,
+        pub n_per_out: ::c_int,
+        pub pps: ::c_int,
+        pub n_pins: ::c_int,
+        pub cross_timestamping: ::c_int,
+        pub adjust_phase: ::c_int,
+        pub max_phase_adj: ::c_int,
+        pub rsv: [::c_int; 11],
+    }
+
     // linux/if_xdp.h
     pub struct xsk_tx_metadata_completion {
         pub tx_timestamp: ::__u64,
@@ -4566,8 +4579,7 @@ pub const PTP_MAX_SAMPLES: ::c_uint = 25; // Maximum allowed offset measurement
 
 const PTP_CLK_MAGIC: u32 = b'=' as u32;
 
-// FIXME: needs the ptp_clock_caps struct
-// pub const PTP_CLOCK_GETCAPS: ::c_uint = _IOR::<ptp_clock_caps>(PTP_CLK_MAGIC, 1);
+pub const PTP_CLOCK_GETCAPS: ::c_uint = _IOR::<ptp_clock_caps>(PTP_CLK_MAGIC, 1);
 pub const PTP_EXTTS_REQUEST: ::c_uint = _IOW::<ptp_extts_request>(PTP_CLK_MAGIC, 2);
 pub const PTP_PEROUT_REQUEST: ::c_uint = _IOW::<ptp_perout_request>(PTP_CLK_MAGIC, 3);
 pub const PTP_ENABLE_PPS: ::c_uint = _IOW::<::c_int>(PTP_CLK_MAGIC, 4);
@@ -4577,8 +4589,7 @@ pub const PTP_PIN_SETFUNC: ::c_uint = _IOW::<ptp_pin_desc>(PTP_CLK_MAGIC, 7);
 pub const PTP_SYS_OFFSET_PRECISE: ::c_uint = _IOWR::<ptp_sys_offset_precise>(PTP_CLK_MAGIC, 8);
 pub const PTP_SYS_OFFSET_EXTENDED: ::c_uint = _IOWR::<ptp_sys_offset_extended>(PTP_CLK_MAGIC, 9);
 
-// FIXME: needs the ptp_clock_caps struct
-// pub const PTP_CLOCK_GETCAPS2: ::c_uint = _IOR::<ptp_clock_caps>(PTP_CLK_MAGIC, 10);
+pub const PTP_CLOCK_GETCAPS2: ::c_uint = _IOR::<ptp_clock_caps>(PTP_CLK_MAGIC, 10);
 pub const PTP_EXTTS_REQUEST2: ::c_uint = _IOW::<ptp_extts_request>(PTP_CLK_MAGIC, 11);
 pub const PTP_PEROUT_REQUEST2: ::c_uint = _IOW::<ptp_perout_request>(PTP_CLK_MAGIC, 12);
 pub const PTP_ENABLE_PPS2: ::c_uint = _IOW::<::c_int>(PTP_CLK_MAGIC, 13);