selftests: move ptp tests from Documentation/ptp
authorShuah Khan <shuahkh@osg.samsung.com>
Tue, 13 Sep 2016 17:30:03 +0000 (11:30 -0600)
committerShuah Khan <shuahkh@osg.samsung.com>
Tue, 20 Sep 2016 15:54:38 +0000 (09:54 -0600)
Remove ptp from Makefile to move the test to selftests. Update ptp Makefile
to work under selftests. ptp will not be run as part of selftests suite and
will not be included in install targets. They can be built separately for
now.

Acked-by: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
Documentation/Makefile
Documentation/ptp/.gitignore [deleted file]
Documentation/ptp/Makefile [deleted file]
Documentation/ptp/testptp.c [deleted file]
Documentation/ptp/testptp.mk [deleted file]
tools/testing/selftests/ptp/.gitignore [new file with mode: 0644]
tools/testing/selftests/ptp/Makefile [new file with mode: 0644]
tools/testing/selftests/ptp/testptp.c [new file with mode: 0644]
tools/testing/selftests/ptp/testptp.mk [new file with mode: 0644]

index 7a28f6c267554cd10433c73a47d8afa5edead4ee..8cd6d1aaabfaa9c9ce450eebf3fe6172c42ad2f7 100644 (file)
@@ -1,3 +1,3 @@
 subdir-y := accounting auxdisplay blackfin \
        ia64 laptops mic misc-devices \
-       networking pcmcia ptp timers vDSO watchdog
+       networking pcmcia timers vDSO watchdog
diff --git a/Documentation/ptp/.gitignore b/Documentation/ptp/.gitignore
deleted file mode 100644 (file)
index f562e49..0000000
+++ /dev/null
@@ -1 +0,0 @@
-testptp
diff --git a/Documentation/ptp/Makefile b/Documentation/ptp/Makefile
deleted file mode 100644 (file)
index 293d6c0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# List of programs to build
-hostprogs-y := testptp
-
-# Tell kbuild to always build the programs
-always := $(hostprogs-y)
-
-HOSTCFLAGS_testptp.o += -I$(objtree)/usr/include
-HOSTLOADLIBES_testptp := -lrt
diff --git a/Documentation/ptp/testptp.c b/Documentation/ptp/testptp.c
deleted file mode 100644 (file)
index 5d2eae1..0000000
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- * PTP 1588 clock support - User space test program
- *
- * Copyright (C) 2010 OMICRON electronics GmbH
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#define _GNU_SOURCE
-#define __SANE_USERSPACE_TYPES__        /* For PPC64, to get LL64 types */
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <math.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/timex.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <linux/ptp_clock.h>
-
-#define DEVICE "/dev/ptp0"
-
-#ifndef ADJ_SETOFFSET
-#define ADJ_SETOFFSET 0x0100
-#endif
-
-#ifndef CLOCK_INVALID
-#define CLOCK_INVALID -1
-#endif
-
-/* clock_adjtime is not available in GLIBC < 2.14 */
-#if !__GLIBC_PREREQ(2, 14)
-#include <sys/syscall.h>
-static int clock_adjtime(clockid_t id, struct timex *tx)
-{
-       return syscall(__NR_clock_adjtime, id, tx);
-}
-#endif
-
-static clockid_t get_clockid(int fd)
-{
-#define CLOCKFD 3
-#define FD_TO_CLOCKID(fd)      ((~(clockid_t) (fd) << 3) | CLOCKFD)
-
-       return FD_TO_CLOCKID(fd);
-}
-
-static void handle_alarm(int s)
-{
-       printf("received signal %d\n", s);
-}
-
-static int install_handler(int signum, void (*handler)(int))
-{
-       struct sigaction action;
-       sigset_t mask;
-
-       /* Unblock the signal. */
-       sigemptyset(&mask);
-       sigaddset(&mask, signum);
-       sigprocmask(SIG_UNBLOCK, &mask, NULL);
-
-       /* Install the signal handler. */
-       action.sa_handler = handler;
-       action.sa_flags = 0;
-       sigemptyset(&action.sa_mask);
-       sigaction(signum, &action, NULL);
-
-       return 0;
-}
-
-static long ppb_to_scaled_ppm(int ppb)
-{
-       /*
-        * The 'freq' field in the 'struct timex' is in parts per
-        * million, but with a 16 bit binary fractional field.
-        * Instead of calculating either one of
-        *
-        *    scaled_ppm = (ppb / 1000) << 16  [1]
-        *    scaled_ppm = (ppb << 16) / 1000  [2]
-        *
-        * we simply use double precision math, in order to avoid the
-        * truncation in [1] and the possible overflow in [2].
-        */
-       return (long) (ppb * 65.536);
-}
-
-static int64_t pctns(struct ptp_clock_time *t)
-{
-       return t->sec * 1000000000LL + t->nsec;
-}
-
-static void usage(char *progname)
-{
-       fprintf(stderr,
-               "usage: %s [options]\n"
-               " -a val     request a one-shot alarm after 'val' seconds\n"
-               " -A val     request a periodic alarm every 'val' seconds\n"
-               " -c         query the ptp clock's capabilities\n"
-               " -d name    device to open\n"
-               " -e val     read 'val' external time stamp events\n"
-               " -f val     adjust the ptp clock frequency by 'val' ppb\n"
-               " -g         get the ptp clock time\n"
-               " -h         prints this message\n"
-               " -i val     index for event/trigger\n"
-               " -k val     measure the time offset between system and phc clock\n"
-               "            for 'val' times (Maximum 25)\n"
-               " -l         list the current pin configuration\n"
-               " -L pin,val configure pin index 'pin' with function 'val'\n"
-               "            the channel index is taken from the '-i' option\n"
-               "            'val' specifies the auxiliary function:\n"
-               "            0 - none\n"
-               "            1 - external time stamp\n"
-               "            2 - periodic output\n"
-               " -p val     enable output with a period of 'val' nanoseconds\n"
-               " -P val     enable or disable (val=1|0) the system clock PPS\n"
-               " -s         set the ptp clock time from the system time\n"
-               " -S         set the system time from the ptp clock time\n"
-               " -t val     shift the ptp clock time by 'val' seconds\n"
-               " -T val     set the ptp clock time to 'val' seconds\n",
-               progname);
-}
-
-int main(int argc, char *argv[])
-{
-       struct ptp_clock_caps caps;
-       struct ptp_extts_event event;
-       struct ptp_extts_request extts_request;
-       struct ptp_perout_request perout_request;
-       struct ptp_pin_desc desc;
-       struct timespec ts;
-       struct timex tx;
-
-       static timer_t timerid;
-       struct itimerspec timeout;
-       struct sigevent sigevent;
-
-       struct ptp_clock_time *pct;
-       struct ptp_sys_offset *sysoff;
-
-
-       char *progname;
-       unsigned int i;
-       int c, cnt, fd;
-
-       char *device = DEVICE;
-       clockid_t clkid;
-       int adjfreq = 0x7fffffff;
-       int adjtime = 0;
-       int capabilities = 0;
-       int extts = 0;
-       int gettime = 0;
-       int index = 0;
-       int list_pins = 0;
-       int oneshot = 0;
-       int pct_offset = 0;
-       int n_samples = 0;
-       int periodic = 0;
-       int perout = -1;
-       int pin_index = -1, pin_func;
-       int pps = -1;
-       int seconds = 0;
-       int settime = 0;
-
-       int64_t t1, t2, tp;
-       int64_t interval, offset;
-
-       progname = strrchr(argv[0], '/');
-       progname = progname ? 1+progname : argv[0];
-       while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghi:k:lL:p:P:sSt:T:v"))) {
-               switch (c) {
-               case 'a':
-                       oneshot = atoi(optarg);
-                       break;
-               case 'A':
-                       periodic = atoi(optarg);
-                       break;
-               case 'c':
-                       capabilities = 1;
-                       break;
-               case 'd':
-                       device = optarg;
-                       break;
-               case 'e':
-                       extts = atoi(optarg);
-                       break;
-               case 'f':
-                       adjfreq = atoi(optarg);
-                       break;
-               case 'g':
-                       gettime = 1;
-                       break;
-               case 'i':
-                       index = atoi(optarg);
-                       break;
-               case 'k':
-                       pct_offset = 1;
-                       n_samples = atoi(optarg);
-                       break;
-               case 'l':
-                       list_pins = 1;
-                       break;
-               case 'L':
-                       cnt = sscanf(optarg, "%d,%d", &pin_index, &pin_func);
-                       if (cnt != 2) {
-                               usage(progname);
-                               return -1;
-                       }
-                       break;
-               case 'p':
-                       perout = atoi(optarg);
-                       break;
-               case 'P':
-                       pps = atoi(optarg);
-                       break;
-               case 's':
-                       settime = 1;
-                       break;
-               case 'S':
-                       settime = 2;
-                       break;
-               case 't':
-                       adjtime = atoi(optarg);
-                       break;
-               case 'T':
-                       settime = 3;
-                       seconds = atoi(optarg);
-                       break;
-               case 'h':
-                       usage(progname);
-                       return 0;
-               case '?':
-               default:
-                       usage(progname);
-                       return -1;
-               }
-       }
-
-       fd = open(device, O_RDWR);
-       if (fd < 0) {
-               fprintf(stderr, "opening %s: %s\n", device, strerror(errno));
-               return -1;
-       }
-
-       clkid = get_clockid(fd);
-       if (CLOCK_INVALID == clkid) {
-               fprintf(stderr, "failed to read clock id\n");
-               return -1;
-       }
-
-       if (capabilities) {
-               if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
-                       perror("PTP_CLOCK_GETCAPS");
-               } else {
-                       printf("capabilities:\n"
-                              "  %d maximum frequency adjustment (ppb)\n"
-                              "  %d programmable alarms\n"
-                              "  %d external time stamp channels\n"
-                              "  %d programmable periodic signals\n"
-                              "  %d pulse per second\n"
-                              "  %d programmable pins\n"
-                              "  %d cross timestamping\n",
-                              caps.max_adj,
-                              caps.n_alarm,
-                              caps.n_ext_ts,
-                              caps.n_per_out,
-                              caps.pps,
-                              caps.n_pins,
-                              caps.cross_timestamping);
-               }
-       }
-
-       if (0x7fffffff != adjfreq) {
-               memset(&tx, 0, sizeof(tx));
-               tx.modes = ADJ_FREQUENCY;
-               tx.freq = ppb_to_scaled_ppm(adjfreq);
-               if (clock_adjtime(clkid, &tx)) {
-                       perror("clock_adjtime");
-               } else {
-                       puts("frequency adjustment okay");
-               }
-       }
-
-       if (adjtime) {
-               memset(&tx, 0, sizeof(tx));
-               tx.modes = ADJ_SETOFFSET;
-               tx.time.tv_sec = adjtime;
-               tx.time.tv_usec = 0;
-               if (clock_adjtime(clkid, &tx) < 0) {
-                       perror("clock_adjtime");
-               } else {
-                       puts("time shift okay");
-               }
-       }
-
-       if (gettime) {
-               if (clock_gettime(clkid, &ts)) {
-                       perror("clock_gettime");
-               } else {
-                       printf("clock time: %ld.%09ld or %s",
-                              ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
-               }
-       }
-
-       if (settime == 1) {
-               clock_gettime(CLOCK_REALTIME, &ts);
-               if (clock_settime(clkid, &ts)) {
-                       perror("clock_settime");
-               } else {
-                       puts("set time okay");
-               }
-       }
-
-       if (settime == 2) {
-               clock_gettime(clkid, &ts);
-               if (clock_settime(CLOCK_REALTIME, &ts)) {
-                       perror("clock_settime");
-               } else {
-                       puts("set time okay");
-               }
-       }
-
-       if (settime == 3) {
-               ts.tv_sec = seconds;
-               ts.tv_nsec = 0;
-               if (clock_settime(clkid, &ts)) {
-                       perror("clock_settime");
-               } else {
-                       puts("set time okay");
-               }
-       }
-
-       if (extts) {
-               memset(&extts_request, 0, sizeof(extts_request));
-               extts_request.index = index;
-               extts_request.flags = PTP_ENABLE_FEATURE;
-               if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
-                       perror("PTP_EXTTS_REQUEST");
-                       extts = 0;
-               } else {
-                       puts("external time stamp request okay");
-               }
-               for (; extts; extts--) {
-                       cnt = read(fd, &event, sizeof(event));
-                       if (cnt != sizeof(event)) {
-                               perror("read");
-                               break;
-                       }
-                       printf("event index %u at %lld.%09u\n", event.index,
-                              event.t.sec, event.t.nsec);
-                       fflush(stdout);
-               }
-               /* Disable the feature again. */
-               extts_request.flags = 0;
-               if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
-                       perror("PTP_EXTTS_REQUEST");
-               }
-       }
-
-       if (list_pins) {
-               int n_pins = 0;
-               if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
-                       perror("PTP_CLOCK_GETCAPS");
-               } else {
-                       n_pins = caps.n_pins;
-               }
-               for (i = 0; i < n_pins; i++) {
-                       desc.index = i;
-                       if (ioctl(fd, PTP_PIN_GETFUNC, &desc)) {
-                               perror("PTP_PIN_GETFUNC");
-                               break;
-                       }
-                       printf("name %s index %u func %u chan %u\n",
-                              desc.name, desc.index, desc.func, desc.chan);
-               }
-       }
-
-       if (oneshot) {
-               install_handler(SIGALRM, handle_alarm);
-               /* Create a timer. */
-               sigevent.sigev_notify = SIGEV_SIGNAL;
-               sigevent.sigev_signo = SIGALRM;
-               if (timer_create(clkid, &sigevent, &timerid)) {
-                       perror("timer_create");
-                       return -1;
-               }
-               /* Start the timer. */
-               memset(&timeout, 0, sizeof(timeout));
-               timeout.it_value.tv_sec = oneshot;
-               if (timer_settime(timerid, 0, &timeout, NULL)) {
-                       perror("timer_settime");
-                       return -1;
-               }
-               pause();
-               timer_delete(timerid);
-       }
-
-       if (periodic) {
-               install_handler(SIGALRM, handle_alarm);
-               /* Create a timer. */
-               sigevent.sigev_notify = SIGEV_SIGNAL;
-               sigevent.sigev_signo = SIGALRM;
-               if (timer_create(clkid, &sigevent, &timerid)) {
-                       perror("timer_create");
-                       return -1;
-               }
-               /* Start the timer. */
-               memset(&timeout, 0, sizeof(timeout));
-               timeout.it_interval.tv_sec = periodic;
-               timeout.it_value.tv_sec = periodic;
-               if (timer_settime(timerid, 0, &timeout, NULL)) {
-                       perror("timer_settime");
-                       return -1;
-               }
-               while (1) {
-                       pause();
-               }
-               timer_delete(timerid);
-       }
-
-       if (perout >= 0) {
-               if (clock_gettime(clkid, &ts)) {
-                       perror("clock_gettime");
-                       return -1;
-               }
-               memset(&perout_request, 0, sizeof(perout_request));
-               perout_request.index = index;
-               perout_request.start.sec = ts.tv_sec + 2;
-               perout_request.start.nsec = 0;
-               perout_request.period.sec = 0;
-               perout_request.period.nsec = perout;
-               if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
-                       perror("PTP_PEROUT_REQUEST");
-               } else {
-                       puts("periodic output request okay");
-               }
-       }
-
-       if (pin_index >= 0) {
-               memset(&desc, 0, sizeof(desc));
-               desc.index = pin_index;
-               desc.func = pin_func;
-               desc.chan = index;
-               if (ioctl(fd, PTP_PIN_SETFUNC, &desc)) {
-                       perror("PTP_PIN_SETFUNC");
-               } else {
-                       puts("set pin function okay");
-               }
-       }
-
-       if (pps != -1) {
-               int enable = pps ? 1 : 0;
-               if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
-                       perror("PTP_ENABLE_PPS");
-               } else {
-                       puts("pps for system time request okay");
-               }
-       }
-
-       if (pct_offset) {
-               if (n_samples <= 0 || n_samples > 25) {
-                       puts("n_samples should be between 1 and 25");
-                       usage(progname);
-                       return -1;
-               }
-
-               sysoff = calloc(1, sizeof(*sysoff));
-               if (!sysoff) {
-                       perror("calloc");
-                       return -1;
-               }
-               sysoff->n_samples = n_samples;
-
-               if (ioctl(fd, PTP_SYS_OFFSET, sysoff))
-                       perror("PTP_SYS_OFFSET");
-               else
-                       puts("system and phc clock time offset request okay");
-
-               pct = &sysoff->ts[0];
-               for (i = 0; i < sysoff->n_samples; i++) {
-                       t1 = pctns(pct+2*i);
-                       tp = pctns(pct+2*i+1);
-                       t2 = pctns(pct+2*i+2);
-                       interval = t2 - t1;
-                       offset = (t2 + t1) / 2 - tp;
-
-                       printf("system time: %lld.%u\n",
-                               (pct+2*i)->sec, (pct+2*i)->nsec);
-                       printf("phc    time: %lld.%u\n",
-                               (pct+2*i+1)->sec, (pct+2*i+1)->nsec);
-                       printf("system time: %lld.%u\n",
-                               (pct+2*i+2)->sec, (pct+2*i+2)->nsec);
-                       printf("system/phc clock time offset is %" PRId64 " ns\n"
-                              "system     clock time delay  is %" PRId64 " ns\n",
-                               offset, interval);
-               }
-
-               free(sysoff);
-       }
-
-       close(fd);
-       return 0;
-}
diff --git a/Documentation/ptp/testptp.mk b/Documentation/ptp/testptp.mk
deleted file mode 100644 (file)
index 4ef2d97..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-# PTP 1588 clock support - User space test program
-#
-# Copyright (C) 2010 OMICRON electronics GmbH
-#
-#  This program is free software; you can redistribute it and/or modify
-#  it under the terms of the GNU General Public License as published by
-#  the Free Software Foundation; either version 2 of the License, or
-#  (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software
-#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-CC        = $(CROSS_COMPILE)gcc
-INC       = -I$(KBUILD_OUTPUT)/usr/include
-CFLAGS    = -Wall $(INC)
-LDLIBS    = -lrt
-PROGS     = testptp
-
-all: $(PROGS)
-
-testptp: testptp.o
-
-clean:
-       rm -f testptp.o
-
-distclean: clean
-       rm -f $(PROGS)
diff --git a/tools/testing/selftests/ptp/.gitignore b/tools/testing/selftests/ptp/.gitignore
new file mode 100644 (file)
index 0000000..f562e49
--- /dev/null
@@ -0,0 +1 @@
+testptp
diff --git a/tools/testing/selftests/ptp/Makefile b/tools/testing/selftests/ptp/Makefile
new file mode 100644 (file)
index 0000000..83dd42b
--- /dev/null
@@ -0,0 +1,8 @@
+TEST_PROGS := testptp
+LDLIBS += -lrt
+all: $(TEST_PROGS)
+
+include ../lib.mk
+
+clean:
+       rm -fr $(TEST_PROGS)
diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c
new file mode 100644 (file)
index 0000000..5d2eae1
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * PTP 1588 clock support - User space test program
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#define _GNU_SOURCE
+#define __SANE_USERSPACE_TYPES__        /* For PPC64, to get LL64 types */
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <math.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/ptp_clock.h>
+
+#define DEVICE "/dev/ptp0"
+
+#ifndef ADJ_SETOFFSET
+#define ADJ_SETOFFSET 0x0100
+#endif
+
+#ifndef CLOCK_INVALID
+#define CLOCK_INVALID -1
+#endif
+
+/* clock_adjtime is not available in GLIBC < 2.14 */
+#if !__GLIBC_PREREQ(2, 14)
+#include <sys/syscall.h>
+static int clock_adjtime(clockid_t id, struct timex *tx)
+{
+       return syscall(__NR_clock_adjtime, id, tx);
+}
+#endif
+
+static clockid_t get_clockid(int fd)
+{
+#define CLOCKFD 3
+#define FD_TO_CLOCKID(fd)      ((~(clockid_t) (fd) << 3) | CLOCKFD)
+
+       return FD_TO_CLOCKID(fd);
+}
+
+static void handle_alarm(int s)
+{
+       printf("received signal %d\n", s);
+}
+
+static int install_handler(int signum, void (*handler)(int))
+{
+       struct sigaction action;
+       sigset_t mask;
+
+       /* Unblock the signal. */
+       sigemptyset(&mask);
+       sigaddset(&mask, signum);
+       sigprocmask(SIG_UNBLOCK, &mask, NULL);
+
+       /* Install the signal handler. */
+       action.sa_handler = handler;
+       action.sa_flags = 0;
+       sigemptyset(&action.sa_mask);
+       sigaction(signum, &action, NULL);
+
+       return 0;
+}
+
+static long ppb_to_scaled_ppm(int ppb)
+{
+       /*
+        * The 'freq' field in the 'struct timex' is in parts per
+        * million, but with a 16 bit binary fractional field.
+        * Instead of calculating either one of
+        *
+        *    scaled_ppm = (ppb / 1000) << 16  [1]
+        *    scaled_ppm = (ppb << 16) / 1000  [2]
+        *
+        * we simply use double precision math, in order to avoid the
+        * truncation in [1] and the possible overflow in [2].
+        */
+       return (long) (ppb * 65.536);
+}
+
+static int64_t pctns(struct ptp_clock_time *t)
+{
+       return t->sec * 1000000000LL + t->nsec;
+}
+
+static void usage(char *progname)
+{
+       fprintf(stderr,
+               "usage: %s [options]\n"
+               " -a val     request a one-shot alarm after 'val' seconds\n"
+               " -A val     request a periodic alarm every 'val' seconds\n"
+               " -c         query the ptp clock's capabilities\n"
+               " -d name    device to open\n"
+               " -e val     read 'val' external time stamp events\n"
+               " -f val     adjust the ptp clock frequency by 'val' ppb\n"
+               " -g         get the ptp clock time\n"
+               " -h         prints this message\n"
+               " -i val     index for event/trigger\n"
+               " -k val     measure the time offset between system and phc clock\n"
+               "            for 'val' times (Maximum 25)\n"
+               " -l         list the current pin configuration\n"
+               " -L pin,val configure pin index 'pin' with function 'val'\n"
+               "            the channel index is taken from the '-i' option\n"
+               "            'val' specifies the auxiliary function:\n"
+               "            0 - none\n"
+               "            1 - external time stamp\n"
+               "            2 - periodic output\n"
+               " -p val     enable output with a period of 'val' nanoseconds\n"
+               " -P val     enable or disable (val=1|0) the system clock PPS\n"
+               " -s         set the ptp clock time from the system time\n"
+               " -S         set the system time from the ptp clock time\n"
+               " -t val     shift the ptp clock time by 'val' seconds\n"
+               " -T val     set the ptp clock time to 'val' seconds\n",
+               progname);
+}
+
+int main(int argc, char *argv[])
+{
+       struct ptp_clock_caps caps;
+       struct ptp_extts_event event;
+       struct ptp_extts_request extts_request;
+       struct ptp_perout_request perout_request;
+       struct ptp_pin_desc desc;
+       struct timespec ts;
+       struct timex tx;
+
+       static timer_t timerid;
+       struct itimerspec timeout;
+       struct sigevent sigevent;
+
+       struct ptp_clock_time *pct;
+       struct ptp_sys_offset *sysoff;
+
+
+       char *progname;
+       unsigned int i;
+       int c, cnt, fd;
+
+       char *device = DEVICE;
+       clockid_t clkid;
+       int adjfreq = 0x7fffffff;
+       int adjtime = 0;
+       int capabilities = 0;
+       int extts = 0;
+       int gettime = 0;
+       int index = 0;
+       int list_pins = 0;
+       int oneshot = 0;
+       int pct_offset = 0;
+       int n_samples = 0;
+       int periodic = 0;
+       int perout = -1;
+       int pin_index = -1, pin_func;
+       int pps = -1;
+       int seconds = 0;
+       int settime = 0;
+
+       int64_t t1, t2, tp;
+       int64_t interval, offset;
+
+       progname = strrchr(argv[0], '/');
+       progname = progname ? 1+progname : argv[0];
+       while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghi:k:lL:p:P:sSt:T:v"))) {
+               switch (c) {
+               case 'a':
+                       oneshot = atoi(optarg);
+                       break;
+               case 'A':
+                       periodic = atoi(optarg);
+                       break;
+               case 'c':
+                       capabilities = 1;
+                       break;
+               case 'd':
+                       device = optarg;
+                       break;
+               case 'e':
+                       extts = atoi(optarg);
+                       break;
+               case 'f':
+                       adjfreq = atoi(optarg);
+                       break;
+               case 'g':
+                       gettime = 1;
+                       break;
+               case 'i':
+                       index = atoi(optarg);
+                       break;
+               case 'k':
+                       pct_offset = 1;
+                       n_samples = atoi(optarg);
+                       break;
+               case 'l':
+                       list_pins = 1;
+                       break;
+               case 'L':
+                       cnt = sscanf(optarg, "%d,%d", &pin_index, &pin_func);
+                       if (cnt != 2) {
+                               usage(progname);
+                               return -1;
+                       }
+                       break;
+               case 'p':
+                       perout = atoi(optarg);
+                       break;
+               case 'P':
+                       pps = atoi(optarg);
+                       break;
+               case 's':
+                       settime = 1;
+                       break;
+               case 'S':
+                       settime = 2;
+                       break;
+               case 't':
+                       adjtime = atoi(optarg);
+                       break;
+               case 'T':
+                       settime = 3;
+                       seconds = atoi(optarg);
+                       break;
+               case 'h':
+                       usage(progname);
+                       return 0;
+               case '?':
+               default:
+                       usage(progname);
+                       return -1;
+               }
+       }
+
+       fd = open(device, O_RDWR);
+       if (fd < 0) {
+               fprintf(stderr, "opening %s: %s\n", device, strerror(errno));
+               return -1;
+       }
+
+       clkid = get_clockid(fd);
+       if (CLOCK_INVALID == clkid) {
+               fprintf(stderr, "failed to read clock id\n");
+               return -1;
+       }
+
+       if (capabilities) {
+               if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
+                       perror("PTP_CLOCK_GETCAPS");
+               } else {
+                       printf("capabilities:\n"
+                              "  %d maximum frequency adjustment (ppb)\n"
+                              "  %d programmable alarms\n"
+                              "  %d external time stamp channels\n"
+                              "  %d programmable periodic signals\n"
+                              "  %d pulse per second\n"
+                              "  %d programmable pins\n"
+                              "  %d cross timestamping\n",
+                              caps.max_adj,
+                              caps.n_alarm,
+                              caps.n_ext_ts,
+                              caps.n_per_out,
+                              caps.pps,
+                              caps.n_pins,
+                              caps.cross_timestamping);
+               }
+       }
+
+       if (0x7fffffff != adjfreq) {
+               memset(&tx, 0, sizeof(tx));
+               tx.modes = ADJ_FREQUENCY;
+               tx.freq = ppb_to_scaled_ppm(adjfreq);
+               if (clock_adjtime(clkid, &tx)) {
+                       perror("clock_adjtime");
+               } else {
+                       puts("frequency adjustment okay");
+               }
+       }
+
+       if (adjtime) {
+               memset(&tx, 0, sizeof(tx));
+               tx.modes = ADJ_SETOFFSET;
+               tx.time.tv_sec = adjtime;
+               tx.time.tv_usec = 0;
+               if (clock_adjtime(clkid, &tx) < 0) {
+                       perror("clock_adjtime");
+               } else {
+                       puts("time shift okay");
+               }
+       }
+
+       if (gettime) {
+               if (clock_gettime(clkid, &ts)) {
+                       perror("clock_gettime");
+               } else {
+                       printf("clock time: %ld.%09ld or %s",
+                              ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
+               }
+       }
+
+       if (settime == 1) {
+               clock_gettime(CLOCK_REALTIME, &ts);
+               if (clock_settime(clkid, &ts)) {
+                       perror("clock_settime");
+               } else {
+                       puts("set time okay");
+               }
+       }
+
+       if (settime == 2) {
+               clock_gettime(clkid, &ts);
+               if (clock_settime(CLOCK_REALTIME, &ts)) {
+                       perror("clock_settime");
+               } else {
+                       puts("set time okay");
+               }
+       }
+
+       if (settime == 3) {
+               ts.tv_sec = seconds;
+               ts.tv_nsec = 0;
+               if (clock_settime(clkid, &ts)) {
+                       perror("clock_settime");
+               } else {
+                       puts("set time okay");
+               }
+       }
+
+       if (extts) {
+               memset(&extts_request, 0, sizeof(extts_request));
+               extts_request.index = index;
+               extts_request.flags = PTP_ENABLE_FEATURE;
+               if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
+                       perror("PTP_EXTTS_REQUEST");
+                       extts = 0;
+               } else {
+                       puts("external time stamp request okay");
+               }
+               for (; extts; extts--) {
+                       cnt = read(fd, &event, sizeof(event));
+                       if (cnt != sizeof(event)) {
+                               perror("read");
+                               break;
+                       }
+                       printf("event index %u at %lld.%09u\n", event.index,
+                              event.t.sec, event.t.nsec);
+                       fflush(stdout);
+               }
+               /* Disable the feature again. */
+               extts_request.flags = 0;
+               if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
+                       perror("PTP_EXTTS_REQUEST");
+               }
+       }
+
+       if (list_pins) {
+               int n_pins = 0;
+               if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
+                       perror("PTP_CLOCK_GETCAPS");
+               } else {
+                       n_pins = caps.n_pins;
+               }
+               for (i = 0; i < n_pins; i++) {
+                       desc.index = i;
+                       if (ioctl(fd, PTP_PIN_GETFUNC, &desc)) {
+                               perror("PTP_PIN_GETFUNC");
+                               break;
+                       }
+                       printf("name %s index %u func %u chan %u\n",
+                              desc.name, desc.index, desc.func, desc.chan);
+               }
+       }
+
+       if (oneshot) {
+               install_handler(SIGALRM, handle_alarm);
+               /* Create a timer. */
+               sigevent.sigev_notify = SIGEV_SIGNAL;
+               sigevent.sigev_signo = SIGALRM;
+               if (timer_create(clkid, &sigevent, &timerid)) {
+                       perror("timer_create");
+                       return -1;
+               }
+               /* Start the timer. */
+               memset(&timeout, 0, sizeof(timeout));
+               timeout.it_value.tv_sec = oneshot;
+               if (timer_settime(timerid, 0, &timeout, NULL)) {
+                       perror("timer_settime");
+                       return -1;
+               }
+               pause();
+               timer_delete(timerid);
+       }
+
+       if (periodic) {
+               install_handler(SIGALRM, handle_alarm);
+               /* Create a timer. */
+               sigevent.sigev_notify = SIGEV_SIGNAL;
+               sigevent.sigev_signo = SIGALRM;
+               if (timer_create(clkid, &sigevent, &timerid)) {
+                       perror("timer_create");
+                       return -1;
+               }
+               /* Start the timer. */
+               memset(&timeout, 0, sizeof(timeout));
+               timeout.it_interval.tv_sec = periodic;
+               timeout.it_value.tv_sec = periodic;
+               if (timer_settime(timerid, 0, &timeout, NULL)) {
+                       perror("timer_settime");
+                       return -1;
+               }
+               while (1) {
+                       pause();
+               }
+               timer_delete(timerid);
+       }
+
+       if (perout >= 0) {
+               if (clock_gettime(clkid, &ts)) {
+                       perror("clock_gettime");
+                       return -1;
+               }
+               memset(&perout_request, 0, sizeof(perout_request));
+               perout_request.index = index;
+               perout_request.start.sec = ts.tv_sec + 2;
+               perout_request.start.nsec = 0;
+               perout_request.period.sec = 0;
+               perout_request.period.nsec = perout;
+               if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
+                       perror("PTP_PEROUT_REQUEST");
+               } else {
+                       puts("periodic output request okay");
+               }
+       }
+
+       if (pin_index >= 0) {
+               memset(&desc, 0, sizeof(desc));
+               desc.index = pin_index;
+               desc.func = pin_func;
+               desc.chan = index;
+               if (ioctl(fd, PTP_PIN_SETFUNC, &desc)) {
+                       perror("PTP_PIN_SETFUNC");
+               } else {
+                       puts("set pin function okay");
+               }
+       }
+
+       if (pps != -1) {
+               int enable = pps ? 1 : 0;
+               if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
+                       perror("PTP_ENABLE_PPS");
+               } else {
+                       puts("pps for system time request okay");
+               }
+       }
+
+       if (pct_offset) {
+               if (n_samples <= 0 || n_samples > 25) {
+                       puts("n_samples should be between 1 and 25");
+                       usage(progname);
+                       return -1;
+               }
+
+               sysoff = calloc(1, sizeof(*sysoff));
+               if (!sysoff) {
+                       perror("calloc");
+                       return -1;
+               }
+               sysoff->n_samples = n_samples;
+
+               if (ioctl(fd, PTP_SYS_OFFSET, sysoff))
+                       perror("PTP_SYS_OFFSET");
+               else
+                       puts("system and phc clock time offset request okay");
+
+               pct = &sysoff->ts[0];
+               for (i = 0; i < sysoff->n_samples; i++) {
+                       t1 = pctns(pct+2*i);
+                       tp = pctns(pct+2*i+1);
+                       t2 = pctns(pct+2*i+2);
+                       interval = t2 - t1;
+                       offset = (t2 + t1) / 2 - tp;
+
+                       printf("system time: %lld.%u\n",
+                               (pct+2*i)->sec, (pct+2*i)->nsec);
+                       printf("phc    time: %lld.%u\n",
+                               (pct+2*i+1)->sec, (pct+2*i+1)->nsec);
+                       printf("system time: %lld.%u\n",
+                               (pct+2*i+2)->sec, (pct+2*i+2)->nsec);
+                       printf("system/phc clock time offset is %" PRId64 " ns\n"
+                              "system     clock time delay  is %" PRId64 " ns\n",
+                               offset, interval);
+               }
+
+               free(sysoff);
+       }
+
+       close(fd);
+       return 0;
+}
diff --git a/tools/testing/selftests/ptp/testptp.mk b/tools/testing/selftests/ptp/testptp.mk
new file mode 100644 (file)
index 0000000..4ef2d97
--- /dev/null
@@ -0,0 +1,33 @@
+# PTP 1588 clock support - User space test program
+#
+# Copyright (C) 2010 OMICRON electronics GmbH
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+CC        = $(CROSS_COMPILE)gcc
+INC       = -I$(KBUILD_OUTPUT)/usr/include
+CFLAGS    = -Wall $(INC)
+LDLIBS    = -lrt
+PROGS     = testptp
+
+all: $(PROGS)
+
+testptp: testptp.o
+
+clean:
+       rm -f testptp.o
+
+distclean: clean
+       rm -f $(PROGS)