1 Index: linux-2.6.23.17/Documentation/pps/Makefile
2 ===================================================================
4 +++ linux-2.6.23.17/Documentation/pps/Makefile
6 +TARGETS = ppstest ppsctl
8 +CFLAGS += -Wall -O2 -D_GNU_SOURCE
12 +# -- Actions section ----------------------------------------------------------
14 +.PHONY : all depend dep
16 +all : .depend $(TARGETS)
19 + $(CC) $(CFLAGS) -M $(TARGETS:=.c) > .depend
21 +ifeq (.depend,$(wildcard .depend))
26 +# -- Clean section ------------------------------------------------------------
31 + rm -f *.o *~ core .depend
33 Index: linux-2.6.23.17/Documentation/pps/pps.txt
34 ===================================================================
36 +++ linux-2.6.23.17/Documentation/pps/pps.txt
39 + PPS - Pulse Per Second
40 + ----------------------
42 +(C) Copyright 2007 Rodolfo Giometti <giometti@enneenne.com>
44 +This program is free software; you can redistribute it and/or modify
45 +it under the terms of the GNU General Public License as published by
46 +the Free Software Foundation; either version 2 of the License, or
47 +(at your option) any later version.
49 +This program is distributed in the hope that it will be useful,
50 +but WITHOUT ANY WARRANTY; without even the implied warranty of
51 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
52 +GNU General Public License for more details.
59 +LinuxPPS provides a programming interface (API) to define into the
60 +system several PPS sources.
62 +PPS means "pulse per second" and a PPS source is just a device which
63 +provides a high precision signal each second so that an application
64 +can use it to adjust system clock time.
66 +A PPS source can be connected to a serial port (usually to the Data
67 +Carrier Detect pin) or to a parallel port (ACK-pin) or to a special
68 +CPU's GPIOs (this is the common case in embedded systems) but in each
69 +case when a new pulse comes the system must apply to it a timestamp
70 +and record it for the userland.
72 +Common use is the combination of the NTPD as userland program with a
73 +GPS receiver as PPS source to obtain a wallclock-time with
74 +sub-millisecond synchronisation to UTC.
80 +While implementing a PPS API as RFC 2783 defines and using an embedded
81 +CPU GPIO-Pin as physical link to the signal, I encountered a deeper
84 + At startup it needs a file descriptor as argument for the function
87 +This implies that the source has a /dev/... entry. This assumption is
88 +ok for the serial and parallel port, where you can do something
89 +useful besides(!) the gathering of timestamps as it is the central
90 +task for a PPS-API. But this assumption does not work for a single
91 +purpose GPIO line. In this case even basic file-related functionality
92 +(like read() and write()) makes no sense at all and should not be a
93 +precondition for the use of a PPS-API.
95 +The problem can be simply solved if you consider that a PPS source is
96 +not always connected with a GPS data source.
98 +So your programs should check if the GPS data source (the serial port
99 +for instance) is a PPS source too, otherwise they should provide the
100 +possibility to open another device as PPS source.
102 +In LinuxPPS the PPS sources are simply char devices usually mapped
103 +into files /dev/pps0, /dev/pps1, etc..
109 +To register a PPS source into the kernel you should define a struct
110 +pps_source_info_s as follow:
112 + static struct pps_source_info_s pps_ktimer_info = {
115 + mode : PPS_CAPTUREASSERT | PPS_OFFSETASSERT | \
117 + PPS_CANWAIT | PPS_TSFMT_TSPEC,
118 + echo : pps_ktimer_echo,
119 + owner : THIS_MODULE,
122 +and then calling the function pps_register_source() in your
123 +intialization routine as follow:
125 + source = pps_register_source(&pps_ktimer_info,
126 + PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
128 +The pps_register_source() prototype is:
130 + int pps_register_source(struct pps_source_info_s *info, int default_params)
132 +where "info" is a pointer to a structure that describes a particular
133 +PPS source, "default_params" tells the system what the initial default
134 +parameters for the device should be (is obvious that these parameters
135 +must be a subset of ones defined into the struct
136 +pps_source_info_s which describe the capabilities of the driver).
138 +Once you have registered a new PPS source into the system you can
139 +signal an assert event (for example in the interrupt handler routine)
142 + pps_event(source, PPS_CAPTUREASSERT, ptr);
144 +The same function may also run the defined echo function
145 +(pps_ktimer_echo(), passing to it the "ptr" pointer) if the user
146 +asked for that... etc..
148 +Please see the file drivers/pps/clients/ktimer.c for an example code.
154 +If the SYSFS filesystem is enabled in the kernel it provides a new class:
156 + $ ls /sys/class/pps/
159 +Every directory is the ID of a PPS sources defined into the system and
160 +inside you find several files:
162 + $ ls /sys/class/pps/pps0/
163 + assert clear echo mode name path subsystem@ uevent
165 +Inside each "assert" and "clear" file you can find the timestamp and a
168 + $ cat /sys/class/pps/pps0/assert
169 + 1170026870.983207967#8
171 +Where before the "#" is the timestamp in seconds and after it is the
172 +sequence number. Other files are:
174 +* echo: reports if the PPS source has an echo function or not;
176 +* mode: reports available PPS functioning modes;
178 +* name: reports the PPS source's name;
180 +* path: reports the PPS source's device path, that is the device the
181 + PPS source is connected to (if it exists).
184 +Testing the PPS support
185 +-----------------------
187 +In order to test the PPS support even without specific hardware you can use
188 +the ktimer driver (see the client subsection in the PPS configuration menu)
189 +and the userland tools provided into Documentaion/pps/ directory.
191 +Once you have enabled the compilation of ktimer just modprobe it (if
192 +not statically compiled):
196 +and the run ppstest as follow:
198 + $ ./ppstest /dev/pps0
199 + trying PPS source "/dev/pps1"
200 + found PPS source "/dev/pps1"
201 + ok, found 1 source(s), now start fetching data...
202 + source 0 - assert 1186592699.388832443, sequence: 364 - clear 0.000000000, sequence: 0
203 + source 0 - assert 1186592700.388931295, sequence: 365 - clear 0.000000000, sequence: 0
204 + source 0 - assert 1186592701.389032765, sequence: 366 - clear 0.000000000, sequence: 0
206 +Please, note that to compile userland programs you need the file timepps.h
207 +(see Documentation/pps/).
208 Index: linux-2.6.23.17/Documentation/pps/ppsctl.c
209 ===================================================================
211 +++ linux-2.6.23.17/Documentation/pps/ppsctl.c
217 +#include <sys/ioctl.h>
218 +#include <sys/types.h>
219 +#include <sys/stat.h>
222 +#include <linux/serial.h>
224 +void usage(char *name)
226 + fprintf(stderr, "usage: %s <ttyS> [enable|disable]\n", name);
228 + exit(EXIT_FAILURE);
231 +int main(int argc, char *argv[])
235 + struct serial_struct ss;
240 + fd = open(argv[1], O_RDWR);
243 + exit(EXIT_FAILURE);
246 + ret = ioctl(fd, TIOCGSERIAL, &ss);
248 + perror("ioctl(TIOCGSERIAL)");
249 + exit(EXIT_FAILURE);
252 + if (argc < 3) { /* just read PPS status */
253 + printf("PPS is %sabled\n",
254 + ss.flags & ASYNC_HARDPPS_CD ? "en" : "dis");
255 + exit(EXIT_SUCCESS);
258 + if (argv[2][0] == 'e' || argv[2][0] == '1')
259 + ss.flags |= ASYNC_HARDPPS_CD;
260 + else if (argv[2][0] == 'd' || argv[2][0] == '0')
261 + ss.flags &= ~ASYNC_HARDPPS_CD;
263 + fprintf(stderr, "invalid state argument \"%s\"\n", argv[2]);
264 + exit(EXIT_FAILURE);
267 + ret = ioctl(fd, TIOCSSERIAL, &ss);
269 + perror("ioctl(TIOCSSERIAL)");
270 + exit(EXIT_FAILURE);
275 Index: linux-2.6.23.17/Documentation/pps/ppsfind
276 ===================================================================
278 +++ linux-2.6.23.17/Documentation/pps/ppsfind
282 +SYS="/sys/class/pps/"
284 +if [ $# -lt 1 ] ; then
285 + echo "usage: ppsfind <name>" >&2
289 +for d in $(ls $SYS) ; do
290 + if grep $1 $SYS/$d/name >& /dev/null || \
291 + grep $1 $SYS/$d/path >& /dev/null ; then
292 + echo "$d: name=$(cat $SYS/$d/name) path=$(cat $SYS/$d/path)"
297 Index: linux-2.6.23.17/Documentation/pps/ppstest.c
298 ===================================================================
300 +++ linux-2.6.23.17/Documentation/pps/ppstest.c
307 +#include <sys/types.h>
308 +#include <sys/stat.h>
311 +#include <timepps.h>
313 +int find_source(char *path, pps_handle_t *handle, int *avail_mode)
315 + pps_params_t params;
318 + printf("trying PPS source \"%s\"\n", path);
320 + /* Try to find the source by using the supplied "path" name */
321 + ret = open(path, O_RDWR);
323 + fprintf(stderr, "unable to open device \"%s\" (%m)\n", path);
327 + /* Open the PPS source (and check the file descriptor) */
328 + ret = time_pps_create(ret, handle);
330 + fprintf(stderr, "cannot create a PPS source from device "
331 + "\"%s\" (%m)\n", path);
334 + printf("found PPS source \"%s\"\n", path);
336 + /* Find out what features are supported */
337 + ret = time_pps_getcap(*handle, avail_mode);
339 + fprintf(stderr, "cannot get capabilities (%m)\n");
342 + if ((*avail_mode & PPS_CAPTUREASSERT) == 0) {
343 + fprintf(stderr, "cannot CAPTUREASSERT\n");
346 + if ((*avail_mode & PPS_OFFSETASSERT) == 0) {
347 + fprintf(stderr, "cannot OFFSETASSERT\n");
351 + /* Capture assert timestamps, and compensate for a 675 nsec
352 + * propagation delay */
353 + ret = time_pps_getparams(*handle, ¶ms);
355 + fprintf(stderr, "cannot get parameters (%m)\n");
358 + params.assert_offset.tv_sec = 0;
359 + params.assert_offset.tv_nsec = 675;
360 + params.mode |= PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
361 + ret = time_pps_setparams(*handle, ¶ms);
363 + fprintf(stderr, "cannot set parameters (%m)\n");
370 +int fetch_source(int i, pps_handle_t *handle, int *avail_mode)
372 + struct timespec timeout;
373 + pps_info_t infobuf;
376 + /* create a zero-valued timeout */
377 + timeout.tv_sec = 3;
378 + timeout.tv_nsec = 0;
381 + if (*avail_mode & PPS_CANWAIT) /* waits for the next event */
382 + ret = time_pps_fetch(*handle, PPS_TSFMT_TSPEC, &infobuf,
386 + ret = time_pps_fetch(*handle, PPS_TSFMT_TSPEC, &infobuf,
390 + if (ret == -EINTR) {
391 + fprintf(stderr, "time_pps_fetch() got a signal!\n");
395 + fprintf(stderr, "time_pps_fetch() error %d (%m)\n", ret);
399 + printf("source %d - "
400 + "assert %ld.%09ld, sequence: %ld - "
401 + "clear %ld.%09ld, sequence: %ld\n",
403 + infobuf.assert_timestamp.tv_sec,
404 + infobuf.assert_timestamp.tv_nsec,
405 + infobuf.assert_sequence,
406 + infobuf.clear_timestamp.tv_sec,
407 + infobuf.clear_timestamp.tv_nsec, infobuf.clear_sequence);
412 +void usage(char *name)
414 + fprintf(stderr, "usage: %s <ppsdev> [<ppsdev> ...]\n", name);
415 + exit(EXIT_FAILURE);
418 +int main(int argc, char *argv[])
421 + pps_handle_t handle[4];
426 + /* Check the command line */
430 + for (i = 1; i < argc && i <= 4; i++) {
431 + ret = find_source(argv[i], &handle[i - 1], &avail_mode[i - 1]);
433 + exit(EXIT_FAILURE);
437 + printf("ok, found %d source(s), now start fetching data...\n", num);
439 + /* loop, printing the most recent timestamp every second or so */
441 + for (i = 0; i < num; i++) {
442 + ret = fetch_source(i, &handle[i], &avail_mode[i]);
443 + if (ret < 0 && errno != ETIMEDOUT)
444 + exit(EXIT_FAILURE);
448 + for (; i >= 0; i--)
449 + time_pps_destroy(handle[i]);
453 Index: linux-2.6.23.17/Documentation/pps/timepps.h
454 ===================================================================
456 +++ linux-2.6.23.17/Documentation/pps/timepps.h
459 + * timepps.h -- PPS API main header
461 + * Copyright (C) 2005-2007 Rodolfo Giometti <giometti@linux.it>
463 + * This program is free software; you can redistribute it and/or modify
464 + * it under the terms of the GNU General Public License as published by
465 + * the Free Software Foundation; either version 2 of the License, or
466 + * (at your option) any later version.
468 + * This program is distributed in the hope that it will be useful,
469 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
470 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
471 + * GNU General Public License for more details.
473 + * You should have received a copy of the GNU General Public License
474 + * along with this program; if not, write to the Free Software
475 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
478 +#ifndef _SYS_TIMEPPS_H_
479 +#define _SYS_TIMEPPS_H_
481 +#include <sys/syscall.h>
484 +#include <linux/pps.h>
487 + * New data structures
491 + unsigned int integral;
492 + unsigned int fractional;
496 + struct timespec tspec;
497 + struct ntp_fp ntpfp;
498 + unsigned long longpad[3];
502 + unsigned long assert_sequence; /* seq. num. of assert event */
503 + unsigned long clear_sequence; /* seq. num. of clear event */
504 + union pps_timeu assert_tu; /* time of assert event */
505 + union pps_timeu clear_tu; /* time of clear event */
506 + int current_mode; /* current mode bits */
510 + int api_version; /* API version # */
511 + int mode; /* mode bits */
512 + union pps_timeu assert_off_tu; /* offset compensation for assert */
513 + union pps_timeu clear_off_tu; /* offset compensation for clear */
516 +typedef int pps_handle_t; /* represents a PPS source */
517 +typedef unsigned long pps_seq_t; /* sequence number */
518 +typedef struct ntp_fp ntp_fp_t; /* NTP-compatible time stamp */
519 +typedef union pps_timeu pps_timeu_t; /* generic data type for time stamps */
520 +typedef struct pps_info pps_info_t;
521 +typedef struct pps_params pps_params_t;
523 +#define assert_timestamp assert_tu.tspec
524 +#define clear_timestamp clear_tu.tspec
526 +#define assert_timestamp_ntpfp assert_tu.ntpfp
527 +#define clear_timestamp_ntpfp clear_tu.ntpfp
529 +#define assert_offset assert_off_tu.tspec
530 +#define clear_offset clear_off_tu.tspec
532 +#define assert_offset_ntpfp assert_off_tu.ntpfp
533 +#define clear_offset_ntpfp clear_off_tu.ntpfp
539 +static __inline int time_pps_create(int source, pps_handle_t *handle)
548 + /* First we check if current device is a PPS valid PPS one...
550 + ret = ioctl(source, PPS_CHECK);
552 + errno = EOPNOTSUPP;
556 + /* ... then since in LinuxPPS there are no differences between a
557 + * "PPS source" and a "PPS handle", we simply return the same value.
564 +static __inline int time_pps_destroy(pps_handle_t handle)
566 + return close(handle);
569 +static __inline int time_pps_getparams(pps_handle_t handle,
570 + pps_params_t *ppsparams)
573 + struct pps_kparams __ppsparams;
575 + ret = ioctl(handle, PPS_GETPARAMS, &__ppsparams);
577 + ppsparams->api_version = __ppsparams.api_version;
578 + ppsparams->mode = __ppsparams.mode;
579 + ppsparams->assert_off_tu.tspec.tv_sec = __ppsparams.assert_off_tu.sec;
580 + ppsparams->assert_off_tu.tspec.tv_nsec = __ppsparams.assert_off_tu.nsec;
581 + ppsparams->clear_off_tu.tspec.tv_sec = __ppsparams.clear_off_tu.sec;
582 + ppsparams->clear_off_tu.tspec.tv_nsec = __ppsparams.clear_off_tu.nsec;
587 +static __inline int time_pps_setparams(pps_handle_t handle,
588 + const pps_params_t *ppsparams)
590 + struct pps_kparams __ppsparams;
592 + __ppsparams.api_version = ppsparams->api_version;
593 + __ppsparams.mode = ppsparams->mode;
594 + __ppsparams.assert_off_tu.sec = ppsparams->assert_off_tu.tspec.tv_sec;
595 + __ppsparams.assert_off_tu.nsec = ppsparams->assert_off_tu.tspec.tv_nsec;
596 + __ppsparams.clear_off_tu.sec = ppsparams->clear_off_tu.tspec.tv_sec;
597 + __ppsparams.clear_off_tu.nsec = ppsparams->clear_off_tu.tspec.tv_nsec;
599 + return ioctl(handle, PPS_SETPARAMS, &__ppsparams);
602 +/* Get capabilities for handle */
603 +static __inline int time_pps_getcap(pps_handle_t handle, int *mode)
605 + return ioctl(handle, PPS_GETCAP, mode);
608 +static __inline int time_pps_fetch(pps_handle_t handle, const int tsformat,
609 + pps_info_t *ppsinfobuf,
610 + const struct timespec *timeout)
612 + struct pps_fdata __fdata;
615 + /* Sanity checks */
616 + if (tsformat != PPS_TSFMT_TSPEC) {
622 + __fdata.timeout.sec = timeout->tv_sec;
623 + __fdata.timeout.nsec = timeout->tv_nsec;
624 + __fdata.timeout.flags = ~PPS_TIME_INVALID;
626 + __fdata.timeout.flags = PPS_TIME_INVALID;
628 + ret = ioctl(handle, PPS_FETCH, &__fdata);
630 + ppsinfobuf->assert_sequence = __fdata.info.assert_sequence;
631 + ppsinfobuf->clear_sequence = __fdata.info.clear_sequence;
632 + ppsinfobuf->assert_tu.tspec.tv_sec = __fdata.info.assert_tu.sec;
633 + ppsinfobuf->assert_tu.tspec.tv_nsec = __fdata.info.assert_tu.nsec;
634 + ppsinfobuf->clear_tu.tspec.tv_sec = __fdata.info.clear_tu.sec;
635 + ppsinfobuf->clear_tu.tspec.tv_nsec = __fdata.info.clear_tu.nsec;
636 + ppsinfobuf->current_mode = __fdata.info.current_mode;
641 +static __inline int time_pps_kcbind(pps_handle_t handle,
642 + const int kernel_consumer,
643 + const int edge, const int tsformat)
645 + /* LinuxPPS doesn't implement kernel consumer feature */
646 + errno = EOPNOTSUPP;
650 +#endif /* _SYS_TIMEPPS_H_ */
651 Index: linux-2.6.23.17/MAINTAINERS
652 ===================================================================
653 --- linux-2.6.23.17.orig/MAINTAINERS
654 +++ linux-2.6.23.17/MAINTAINERS
655 @@ -3011,6 +3011,13 @@ P: James Chapman
656 M: jchapman@katalix.com
661 +M: giometti@enneenne.com
662 +W: http://wiki.enneenne.com/index.php/LinuxPPS_support
663 +L: linuxpps@ml.enneenne.com
669 Index: linux-2.6.23.17/drivers/Kconfig
670 ===================================================================
671 --- linux-2.6.23.17.orig/drivers/Kconfig
672 +++ linux-2.6.23.17/drivers/Kconfig
673 @@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
675 source "drivers/spi/Kconfig"
677 +source "drivers/pps/Kconfig"
679 source "drivers/w1/Kconfig"
681 source "drivers/power/Kconfig"
682 Index: linux-2.6.23.17/drivers/Makefile
683 ===================================================================
684 --- linux-2.6.23.17.orig/drivers/Makefile
685 +++ linux-2.6.23.17/drivers/Makefile
686 @@ -63,6 +63,7 @@ obj-$(CONFIG_INPUT) += input/
687 obj-$(CONFIG_I2O) += message/
688 obj-$(CONFIG_RTC_LIB) += rtc/
690 +obj-$(CONFIG_PPS) += pps/
691 obj-$(CONFIG_W1) += w1/
692 obj-$(CONFIG_POWER_SUPPLY) += power/
693 obj-$(CONFIG_HWMON) += hwmon/
694 Index: linux-2.6.23.17/drivers/char/lp.c
695 ===================================================================
696 --- linux-2.6.23.17.orig/drivers/char/lp.c
697 +++ linux-2.6.23.17/drivers/char/lp.c
698 @@ -746,6 +746,27 @@ static struct console lpcons = {
700 #endif /* console on line printer */
702 +/* Support for PPS signal on the line printer */
704 +#ifdef CONFIG_PPS_CLIENT_LP
706 +static void lp_pps_echo(int source, int event, void *data)
708 + struct parport *port = data;
709 + unsigned char status = parport_read_status(port);
711 + /* echo event via SEL bit */
712 + parport_write_control(port,
713 + parport_read_control(port) | PARPORT_CONTROL_SELECT);
715 + /* signal no event */
716 + if ((status & PARPORT_STATUS_ACK) != 0)
717 + parport_write_control(port,
718 + parport_read_control(port) & ~PARPORT_CONTROL_SELECT);
723 /* --- initialisation code ------------------------------------- */
725 static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
726 @@ -817,6 +838,38 @@ static int lp_register(int nr, struct pa
730 +#ifdef CONFIG_PPS_CLIENT_LP
731 + port->pps_info.owner = THIS_MODULE;
732 + port->pps_info.dev = port->dev;
733 + snprintf(port->pps_info.path, PPS_MAX_NAME_LEN, "/dev/lp%d", nr);
735 + /* No PPS support if lp port has no IRQ line */
736 + if (port->irq != PARPORT_IRQ_NONE) {
737 + strncpy(port->pps_info.name, port->name, PPS_MAX_NAME_LEN);
739 + port->pps_info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT | \
741 + PPS_CANWAIT | PPS_TSFMT_TSPEC;
743 + port->pps_info.echo = lp_pps_echo;
745 + port->pps_source = pps_register_source(&(port->pps_info),
746 + PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
747 + if (port->pps_source < 0)
749 + "cannot register PPS source \"%s\"\n",
750 + port->pps_info.path);
752 + dev_info(port->dev, "PPS source #%d \"%s\" added\n",
753 + port->pps_source, port->pps_info.path);
755 + port->pps_source = -1;
756 + dev_err(port->dev, "PPS support disabled due port \"%s\" is "
757 + "in polling mode\n",
758 + port->pps_info.path);
765 @@ -860,6 +913,14 @@ static void lp_detach (struct parport *p
766 console_registered = NULL;
768 #endif /* CONFIG_LP_CONSOLE */
770 +#ifdef CONFIG_PPS_CLIENT_LP
771 + if (port->pps_source >= 0) {
772 + pps_unregister_source(port->pps_source);
773 + dev_dbg(port->dev, "PPS source #%d \"%s\" removed\n",
774 + port->pps_source, port->pps_info.path);
779 static struct parport_driver lp_driver = {
780 Index: linux-2.6.23.17/drivers/pps/Kconfig
781 ===================================================================
783 +++ linux-2.6.23.17/drivers/pps/Kconfig
786 +# PPS support configuration
792 + tristate "PPS support"
793 + depends on EXPERIMENTAL
795 + PPS (Pulse Per Second) is a special pulse provided by some GPS
796 + antennae. Userland can use it to get an high time reference.
798 + Some antennae's PPS signals are connected with the CD (Carrier
799 + Detect) pin of the serial line they use to communicate with the
800 + host. In this case use the SERIAL_LINE client support.
802 + Some antennae's PPS signals are connected with some special host
803 + inputs so you have to enable the corresponding client support.
805 + To compile this driver as a module, choose M here: the module
806 + will be called pps_core.ko.
809 + bool "PPS debugging messages"
812 + Say Y here if you want the PPS support to produce a bunch of debug
813 + messages to the system log. Select this if you are having a
814 + problem with PPS support and want to see more of what is going on.
816 +source drivers/pps/clients/Kconfig
819 Index: linux-2.6.23.17/drivers/pps/Makefile
820 ===================================================================
822 +++ linux-2.6.23.17/drivers/pps/Makefile
825 +# Makefile for the PPS core.
828 +pps_core-objs += pps.o kapi.o sysfs.o
829 +obj-$(CONFIG_PPS) += pps_core.o
832 +ifeq ($(CONFIG_PPS_DEBUG),y)
833 +EXTRA_CFLAGS += -DDEBUG
835 Index: linux-2.6.23.17/drivers/pps/clients/Kconfig
836 ===================================================================
838 +++ linux-2.6.23.17/drivers/pps/clients/Kconfig
841 +# PPS clients configuration
846 +comment "PPS clients support"
848 +config PPS_CLIENT_KTIMER
849 + tristate "Kernel timer client (Testing client, use for debug)"
851 + If you say yes here you get support for a PPS debugging client
852 + which uses a kernel timer to generate the PPS signal.
854 + This driver can also be built as a module. If so, the module
855 + will be called ktimer.ko.
857 +comment "UART serial support (forced off)"
858 + depends on ! (SERIAL_CORE != n && !(PPS = m && SERIAL_CORE = y))
860 +config PPS_CLIENT_UART
861 + bool "UART serial support"
862 + depends on SERIAL_CORE != n && !(PPS = m && SERIAL_CORE = y)
864 + If you say yes here you get support for a PPS source connected
865 + with the CD (Carrier Detect) pin of your serial port.
867 +comment "Parallel printer support (forced off)"
868 + depends on !( PRINTER != n && !(PPS = m && PRINTER = y))
870 +config PPS_CLIENT_LP
871 + bool "Parallel printer support"
872 + depends on PRINTER != n && !(PPS = m && PRINTER = y)
874 + If you say yes here you get support for a PPS source connected
875 + with the interrupt pin of your parallel port.
878 Index: linux-2.6.23.17/drivers/pps/clients/Makefile
879 ===================================================================
881 +++ linux-2.6.23.17/drivers/pps/clients/Makefile
884 +# Makefile for PPS clients.
887 +obj-$(CONFIG_PPS_CLIENT_KTIMER) += ktimer.o
889 +ifeq ($(CONFIG_PPS_DEBUG),y)
890 +EXTRA_CFLAGS += -DDEBUG
892 Index: linux-2.6.23.17/drivers/pps/clients/ktimer.c
893 ===================================================================
895 +++ linux-2.6.23.17/drivers/pps/clients/ktimer.c
898 + * ktimer.c -- kernel timer test client
901 + * Copyright (C) 2005-2006 Rodolfo Giometti <giometti@linux.it>
903 + * This program is free software; you can redistribute it and/or modify
904 + * it under the terms of the GNU General Public License as published by
905 + * the Free Software Foundation; either version 2 of the License, or
906 + * (at your option) any later version.
908 + * This program is distributed in the hope that it will be useful,
909 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
910 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
911 + * GNU General Public License for more details.
913 + * You should have received a copy of the GNU General Public License
914 + * along with this program; if not, write to the Free Software
915 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
919 +#include <linux/kernel.h>
920 +#include <linux/module.h>
921 +#include <linux/init.h>
922 +#include <linux/time.h>
923 +#include <linux/timer.h>
925 +#include <linux/pps.h>
932 +static struct timer_list ktimer;
938 +static void pps_ktimer_event(unsigned long ptr)
940 + pr_info("PPS event at %lu\n", jiffies);
942 + pps_event(source, PPS_CAPTUREASSERT, NULL);
944 + mod_timer(&ktimer, jiffies + HZ);
948 + * The echo function
951 +static void pps_ktimer_echo(int source, int event, void *data)
953 + pr_info("echo %s %s for source %d\n",
954 + event & PPS_CAPTUREASSERT ? "assert" : "",
955 + event & PPS_CAPTURECLEAR ? "clear" : "",
960 + * The PPS info struct
963 +static struct pps_source_info pps_ktimer_info = {
966 + mode : PPS_CAPTUREASSERT | PPS_OFFSETASSERT | \
968 + PPS_CANWAIT | PPS_TSFMT_TSPEC,
969 + echo : pps_ktimer_echo,
970 + owner : THIS_MODULE,
977 +static void __exit pps_ktimer_exit(void)
979 + del_timer_sync(&ktimer);
980 + pps_unregister_source(source);
982 + pr_info("ktimer PPS source unregistered\n");
985 +static int __init pps_ktimer_init(void)
989 + ret = pps_register_source(&pps_ktimer_info,
990 + PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
992 + printk(KERN_ERR "cannot register ktimer source\n");
997 + setup_timer(&ktimer, pps_ktimer_event, 0);
998 + mod_timer(&ktimer, jiffies + HZ);
1000 + pr_info("ktimer PPS source registered at %d\n", source);
1005 +module_init(pps_ktimer_init);
1006 +module_exit(pps_ktimer_exit);
1008 +MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
1009 +MODULE_DESCRIPTION("dummy PPS source by using a kernel timer (just for debug)");
1010 +MODULE_LICENSE("GPL");
1011 Index: linux-2.6.23.17/drivers/pps/kapi.c
1012 ===================================================================
1014 +++ linux-2.6.23.17/drivers/pps/kapi.c
1017 + * kapi.c -- kernel API
1020 + * Copyright (C) 2005-2007 Rodolfo Giometti <giometti@linux.it>
1022 + * This program is free software; you can redistribute it and/or modify
1023 + * it under the terms of the GNU General Public License as published by
1024 + * the Free Software Foundation; either version 2 of the License, or
1025 + * (at your option) any later version.
1027 + * This program is distributed in the hope that it will be useful,
1028 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1029 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1030 + * GNU General Public License for more details.
1032 + * You should have received a copy of the GNU General Public License
1033 + * along with this program; if not, write to the Free Software
1034 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1038 +#include <linux/kernel.h>
1039 +#include <linux/module.h>
1040 +#include <linux/init.h>
1041 +#include <linux/sched.h>
1042 +#include <linux/time.h>
1043 +#include <linux/spinlock.h>
1044 +#include <linux/idr.h>
1045 +#include <linux/fs.h>
1046 +#include <linux/pps.h>
1052 +static spinlock_t idr_lock = SPIN_LOCK_UNLOCKED;
1053 +static DEFINE_IDR(pps_idr);
1059 +static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
1061 + ts->nsec += offset->nsec;
1062 + if (ts->nsec >= NSEC_PER_SEC) {
1063 + ts->nsec -= NSEC_PER_SEC;
1065 + } else if (ts->nsec < 0) {
1066 + ts->nsec += NSEC_PER_SEC;
1069 + ts->sec += offset->sec;
1073 + * Exported functions
1076 +int pps_register_source(struct pps_source_info *info, int default_params)
1078 + struct pps_device *pps;
1082 + /* Sanity checks */
1083 + if ((info->mode & default_params) != default_params) {
1084 + printk(KERN_ERR "pps: %s: unsupported default parameters\n",
1087 + goto pps_register_source_exit;
1089 + if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
1090 + info->echo == NULL) {
1091 + printk(KERN_ERR "pps: %s: echo function is not defined\n",
1094 + goto pps_register_source_exit;
1096 + if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
1097 + printk(KERN_ERR "pps: %s: unspecified time format\n",
1100 + goto pps_register_source_exit;
1103 + /* Allocate memory for the new PPS source struct */
1104 + pps = kzalloc(sizeof(struct pps_device), GFP_KERNEL);
1105 + if (pps == NULL) {
1107 + goto pps_register_source_exit;
1110 + /* Get new ID for the new PPS source */
1111 + if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) {
1116 + spin_lock_irq(&idr_lock);
1117 + err = idr_get_new(&pps_idr, pps, &id);
1118 + spin_unlock_irq(&idr_lock);
1123 + id = id & MAX_ID_MASK;
1124 + if (id >= PPS_MAX_SOURCES) {
1125 + printk(KERN_ERR "pps: %s: too much PPS sources in the system\n",
1132 + pps->params.api_version = PPS_API_VERS;
1133 + pps->params.mode = default_params;
1134 + pps->info = *info;
1136 + init_waitqueue_head(&pps->queue);
1137 + spin_lock_init(&pps->lock);
1138 + atomic_set(&pps->usage, 0);
1139 + init_waitqueue_head(&pps->usage_queue);
1141 + /* Create the char device */
1142 + err = pps_register_cdev(pps);
1144 + printk(KERN_ERR "pps: %s: unable to create char device\n",
1149 + /* Create the sysfs entry */
1150 + err = pps_sysfs_create_source_entry(pps);
1152 + printk(KERN_ERR "pps: %s: unable to create sysfs entries\n",
1154 + goto unregister_cdev;
1157 + pr_info("new PPS source %s at ID %d\n", info->name, id);
1162 + pps_unregister_cdev(pps);
1165 + spin_lock_irq(&idr_lock);
1166 + idr_remove(&pps_idr, id);
1167 + spin_unlock_irq(&idr_lock);
1172 +pps_register_source_exit:
1173 + printk(KERN_ERR "pps: %s: unable to register source\n", info->name);
1177 +EXPORT_SYMBOL(pps_register_source);
1179 +void pps_unregister_source(int source)
1181 + struct pps_device *pps;
1183 + spin_lock_irq(&idr_lock);
1184 + pps = idr_find(&pps_idr, source);
1187 + spin_unlock_irq(&idr_lock);
1191 + /* This should be done first in order to deny IRQ handlers
1192 + * to access PPS structs
1195 + idr_remove(&pps_idr, pps->id);
1196 + spin_unlock_irq(&idr_lock);
1198 + wait_event(pps->usage_queue, atomic_read(&pps->usage) == 0);
1200 + pps_sysfs_remove_source_entry(pps);
1201 + pps_unregister_cdev(pps);
1204 +EXPORT_SYMBOL(pps_unregister_source);
1206 +void pps_event(int source, int event, void *data)
1208 + struct pps_device *pps;
1209 + struct timespec __ts;
1210 + struct pps_ktime ts;
1211 + unsigned long flags;
1213 + /* First of all we get the time stamp... */
1214 + getnstimeofday(&__ts);
1216 + /* ... and translate it to PPS time data struct */
1217 + ts.sec = __ts.tv_sec;
1218 + ts.nsec = __ts.tv_nsec;
1220 + if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0 ) {
1221 + printk(KERN_ERR "pps: unknown event (%x) for source %d\n",
1226 + spin_lock_irqsave(&idr_lock, flags);
1227 + pps = idr_find(&pps_idr, source);
1229 + /* If we find a valid PPS source we lock it before leaving
1233 + atomic_inc(&pps->usage);
1234 + spin_unlock_irqrestore(&idr_lock, flags);
1239 + pr_debug("PPS event on source %d at at %llu.%06u\n",
1240 + pps->id, ts.sec, ts.nsec);
1242 + spin_lock_irqsave(&pps->lock, flags);
1244 + /* Must call the echo function? */
1245 + if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
1246 + pps->info.echo(source, event, data);
1248 + /* Check the event */
1249 + pps->current_mode = pps->params.mode;
1250 + if (event & PPS_CAPTUREASSERT) {
1251 + /* We have to add an offset? */
1252 + if (pps->params.mode & PPS_OFFSETASSERT)
1253 + pps_add_offset(&ts, &pps->params.assert_off_tu);
1255 + /* Save the time stamp */
1256 + pps->assert_tu = ts;
1257 + pps->assert_sequence++;
1258 + pr_debug("capture assert seq #%u for source %d\n",
1259 + pps->assert_sequence, source);
1261 + if (event & PPS_CAPTURECLEAR) {
1262 + /* We have to add an offset? */
1263 + if (pps->params.mode & PPS_OFFSETCLEAR)
1264 + pps_add_offset(&ts, &pps->params.clear_off_tu);
1266 + /* Save the time stamp */
1267 + pps->clear_tu = ts;
1268 + pps->clear_sequence++;
1269 + pr_debug("capture clear seq #%u for source %d\n",
1270 + pps->clear_sequence, source);
1274 + wake_up_interruptible(&pps->queue);
1276 + kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
1278 + spin_unlock_irqrestore(&pps->lock, flags);
1280 + /* Now we can release the PPS source for (possible) deregistration */
1281 + spin_lock_irqsave(&idr_lock, flags);
1282 + atomic_dec(&pps->usage);
1283 + wake_up_all(&pps->usage_queue);
1284 + spin_unlock_irqrestore(&idr_lock, flags);
1286 +EXPORT_SYMBOL(pps_event);
1287 Index: linux-2.6.23.17/drivers/pps/pps.c
1288 ===================================================================
1290 +++ linux-2.6.23.17/drivers/pps/pps.c
1293 + * pps.c -- Main PPS support file
1296 + * Copyright (C) 2005-2007 Rodolfo Giometti <giometti@linux.it>
1298 + * This program is free software; you can redistribute it and/or modify
1299 + * it under the terms of the GNU General Public License as published by
1300 + * the Free Software Foundation; either version 2 of the License, or
1301 + * (at your option) any later version.
1303 + * This program is distributed in the hope that it will be useful,
1304 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1305 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1306 + * GNU General Public License for more details.
1308 + * You should have received a copy of the GNU General Public License
1309 + * along with this program; if not, write to the Free Software
1310 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1314 +#include <linux/kernel.h>
1315 +#include <linux/version.h>
1316 +#include <linux/module.h>
1317 +#include <linux/init.h>
1318 +#include <linux/sched.h>
1319 +#include <linux/uaccess.h>
1320 +#include <linux/cdev.h>
1321 +#include <linux/poll.h>
1322 +#include <linux/pps.h>
1328 +static dev_t pps_devt;
1329 +static struct class *pps_class;
1332 + * Char device methods
1335 +static unsigned int pps_cdev_poll(struct file *file, poll_table *wait)
1337 + struct pps_device *pps = file->private_data;
1339 + poll_wait(file, &pps->queue, wait);
1341 + return POLLIN | POLLRDNORM;
1344 +static int pps_cdev_fasync(int fd, struct file *file, int on)
1346 + struct pps_device *pps = file->private_data;
1347 + return fasync_helper(fd, file, on, &pps->async_queue);
1350 +static int pps_cdev_ioctl(struct inode *inode, struct file *file,
1351 + unsigned int cmd, unsigned long arg)
1353 + struct pps_device *pps = file->private_data;
1354 + struct pps_kparams params;
1355 + struct pps_fdata fdata;
1356 + unsigned long ticks;
1357 + void __user *uarg = (void __user *) arg;
1358 + int __user *iuarg = (int __user *) arg;
1364 + /* This does nothing but signal we are a PPS source... */
1368 + case PPS_GETPARAMS:
1369 + pr_debug("PPS_GETPARAMS: source %d\n", pps->id);
1371 + /* Sanity checks */
1375 + /* Return current parameters */
1376 + err = copy_to_user(uarg, &pps->params,
1377 + sizeof(struct pps_kparams));
1383 + case PPS_SETPARAMS:
1384 + pr_debug("PPS_SETPARAMS: source %d\n", pps->id);
1386 + /* Check the capabilities */
1387 + if (!capable(CAP_SYS_TIME))
1390 + /* Sanity checks */
1393 + err = copy_from_user(¶ms, uarg, sizeof(struct pps_kparams));
1396 + if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
1397 + pr_debug("capture mode unspecified (%x)\n",
1402 + /* Check for supported capabilities */
1403 + if ((params.mode & ~pps->info.mode) != 0) {
1404 + pr_debug("unsupported capabilities (%x)\n",
1409 + spin_lock_irq(&pps->lock);
1411 + /* Save the new parameters */
1412 + pps->params = params;
1414 + /* Restore the read only parameters */
1415 + if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
1416 + /* section 3.3 of RFC 2783 interpreted */
1417 + pr_debug("time format unspecified (%x)\n",
1419 + pps->params.mode |= PPS_TSFMT_TSPEC;
1421 + if (pps->info.mode & PPS_CANWAIT)
1422 + pps->params.mode |= PPS_CANWAIT;
1423 + pps->params.api_version = PPS_API_VERS;
1425 + spin_unlock_irq(&pps->lock);
1430 + pr_debug("PPS_GETCAP: source %d\n", pps->id);
1432 + /* Sanity checks */
1436 + err = put_user(pps->info.mode, iuarg);
1443 + pr_debug("PPS_FETCH: source %d\n", pps->id);
1447 + err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata));
1453 + /* Manage the timeout */
1454 + if (fdata.timeout.flags & PPS_TIME_INVALID)
1455 + err = wait_event_interruptible(pps->queue, pps->go);
1457 + pr_debug("timeout %lld.%09d\n",
1458 + fdata.timeout.sec, fdata.timeout.nsec);
1459 + ticks = fdata.timeout.sec * HZ;
1460 + ticks += fdata.timeout.nsec / (NSEC_PER_SEC / HZ);
1463 + err = wait_event_interruptible_timeout(
1464 + pps->queue, pps->go, ticks);
1466 + return -ETIMEDOUT;
1470 + /* Check for pending signals */
1471 + if (err == -ERESTARTSYS) {
1472 + pr_debug("pending signal caught\n");
1476 + /* Return the fetched timestamp */
1477 + spin_lock_irq(&pps->lock);
1479 + fdata.info.assert_sequence = pps->assert_sequence;
1480 + fdata.info.clear_sequence = pps->clear_sequence;
1481 + fdata.info.assert_tu = pps->assert_tu;
1482 + fdata.info.clear_tu = pps->clear_tu;
1483 + fdata.info.current_mode = pps->current_mode;
1485 + spin_unlock_irq(&pps->lock);
1487 + err = copy_to_user(uarg, &fdata, sizeof(struct pps_fdata));
1501 +static int pps_cdev_open(struct inode *inode, struct file *file)
1503 + struct pps_device *pps = container_of(inode->i_cdev,
1504 + struct pps_device, cdev);
1506 + /* Lock the PPS source against (possible) deregistration */
1507 + atomic_inc(&pps->usage);
1509 + file->private_data = pps;
1514 +static int pps_cdev_release(struct inode *inode, struct file *file)
1516 + struct pps_device *pps = file->private_data;
1518 + /* Free the PPS source and wake up (possible) deregistration */
1519 + atomic_dec(&pps->usage);
1520 + wake_up_all(&pps->usage_queue);
1526 + * Char device stuff
1529 +static const struct file_operations pps_cdev_fops = {
1530 + .owner = THIS_MODULE,
1531 + .llseek = no_llseek,
1532 + .poll = pps_cdev_poll,
1533 + .fasync = pps_cdev_fasync,
1534 + .ioctl = pps_cdev_ioctl,
1535 + .open = pps_cdev_open,
1536 + .release = pps_cdev_release,
1539 +int pps_register_cdev(struct pps_device *pps)
1543 + pps->devno = MKDEV(MAJOR(pps_devt), pps->id);
1544 + cdev_init(&pps->cdev, &pps_cdev_fops);
1545 + pps->cdev.owner = pps->info.owner;
1547 + err = cdev_add(&pps->cdev, pps->devno, 1);
1549 + printk(KERN_ERR "pps: %s: failed to add char device %d:%d\n",
1550 + pps->info.name, MAJOR(pps_devt), pps->id);
1553 + pps->dev = device_create(pps_class, pps->info.dev, pps->devno,
1554 + "pps%d", pps->id);
1557 + dev_set_drvdata(pps->dev, pps);
1559 + pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
1560 + MAJOR(pps_devt), pps->id);
1565 + cdev_del(&pps->cdev);
1570 +void pps_unregister_cdev(struct pps_device *pps)
1572 + device_destroy(pps_class, pps->devno);
1573 + cdev_del(&pps->cdev);
1580 +static void __exit pps_exit(void)
1582 + class_destroy(pps_class);
1585 + unregister_chrdev_region(pps_devt, PPS_MAX_SOURCES);
1587 + pr_info("LinuxPPS API ver. %d removed\n", PPS_API_VERS);
1590 +static int __init pps_init(void)
1594 + pps_class = class_create(THIS_MODULE, "pps");
1596 + printk(KERN_ERR "pps: ailed to allocate class\n");
1600 + err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps");
1602 + printk(KERN_ERR "pps: failed to allocate char device region\n");
1603 + goto remove_class;
1606 + pr_info("LinuxPPS API ver. %d registered\n", PPS_API_VERS);
1607 + pr_info("Software ver. %s - Copyright 2005-2007 Rodolfo Giometti "
1608 + "<giometti@linux.it>\n", PPS_VERSION);
1613 + class_destroy(pps_class);
1618 +subsys_initcall(pps_init);
1619 +module_exit(pps_exit);
1621 +MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
1622 +MODULE_DESCRIPTION("LinuxPPS support (RFC 2783) - ver. " PPS_VERSION);
1623 +MODULE_LICENSE("GPL");
1624 Index: linux-2.6.23.17/drivers/pps/sysfs.c
1625 ===================================================================
1627 +++ linux-2.6.23.17/drivers/pps/sysfs.c
1630 + * sysfs.c -- sysfs support
1633 + * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
1635 + * This program is free software; you can redistribute it and/or modify
1636 + * it under the terms of the GNU General Public License as published by
1637 + * the Free Software Foundation; either version 2 of the License, or
1638 + * (at your option) any later version.
1640 + * This program is distributed in the hope that it will be useful,
1641 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1642 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1643 + * GNU General Public License for more details.
1645 + * You should have received a copy of the GNU General Public License
1646 + * along with this program; if not, write to the Free Software
1647 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1651 +#include <linux/device.h>
1652 +#include <linux/module.h>
1653 +#include <linux/string.h>
1654 +#include <linux/pps.h>
1657 + * Attribute functions
1660 +static ssize_t pps_show_assert(struct device *dev,
1661 + struct device_attribute *attr, char *buf)
1663 + struct pps_device *pps = dev_get_drvdata(dev);
1665 + return sprintf(buf, "%lld.%09d#%d\n",
1666 + pps->assert_tu.sec, pps->assert_tu.nsec,
1667 + pps->assert_sequence);
1669 +DEVICE_ATTR(assert, S_IRUGO, pps_show_assert, NULL);
1671 +static ssize_t pps_show_clear(struct device *dev,
1672 + struct device_attribute *attr, char *buf)
1674 + struct pps_device *pps = dev_get_drvdata(dev);
1676 + return sprintf(buf, "%lld.%09d#%d\n",
1677 + pps->clear_tu.sec, pps->clear_tu.nsec,
1678 + pps->clear_sequence);
1680 +DEVICE_ATTR(clear, S_IRUGO, pps_show_clear, NULL);
1682 +static ssize_t pps_show_mode(struct device *dev,
1683 + struct device_attribute *attr, char *buf)
1685 + struct pps_device *pps = dev_get_drvdata(dev);
1687 + return sprintf(buf, "%4x\n", pps->info.mode);
1689 +DEVICE_ATTR(mode, S_IRUGO, pps_show_mode, NULL);
1691 +static ssize_t pps_show_echo(struct device *dev,
1692 + struct device_attribute *attr, char *buf)
1694 + struct pps_device *pps = dev_get_drvdata(dev);
1696 + return sprintf(buf, "%d\n", !!pps->info.echo);
1698 +DEVICE_ATTR(echo, S_IRUGO, pps_show_echo, NULL);
1700 +static ssize_t pps_show_name(struct device *dev,
1701 + struct device_attribute *attr, char *buf)
1703 + struct pps_device *pps = dev_get_drvdata(dev);
1705 + return sprintf(buf, "%s\n", pps->info.name);
1707 +DEVICE_ATTR(name, S_IRUGO, pps_show_name, NULL);
1709 +static ssize_t pps_show_path(struct device *dev,
1710 + struct device_attribute *attr, char *buf)
1712 + struct pps_device *pps = dev_get_drvdata(dev);
1714 + return sprintf(buf, "%s\n", pps->info.path);
1716 +DEVICE_ATTR(path, S_IRUGO, pps_show_path, NULL);
1719 + * Public functions
1722 +void pps_sysfs_remove_source_entry(struct pps_device *pps)
1724 + /* Delete info files */
1725 + if (pps->info.mode & PPS_CAPTUREASSERT)
1726 + device_remove_file(pps->dev, &dev_attr_assert);
1728 + if (pps->info.mode & PPS_CAPTURECLEAR)
1729 + device_remove_file(pps->dev, &dev_attr_clear);
1731 + device_remove_file(pps->dev, &dev_attr_mode);
1732 + device_remove_file(pps->dev, &dev_attr_echo);
1733 + device_remove_file(pps->dev, &dev_attr_name);
1734 + device_remove_file(pps->dev, &dev_attr_path);
1737 +int pps_sysfs_create_source_entry(struct pps_device *pps)
1739 + /* Create file "assert" and "clear" according to source capability */
1740 + if (pps->info.mode & PPS_CAPTUREASSERT)
1741 + device_create_file(pps->dev, &dev_attr_assert);
1743 + if (pps->info.mode & PPS_CAPTURECLEAR)
1744 + device_create_file(pps->dev, &dev_attr_clear);
1746 + device_create_file(pps->dev, &dev_attr_mode);
1747 + device_create_file(pps->dev, &dev_attr_echo);
1748 + device_create_file(pps->dev, &dev_attr_name);
1749 + device_create_file(pps->dev, &dev_attr_path);
1753 Index: linux-2.6.23.17/drivers/serial/8250.c
1754 ===================================================================
1755 --- linux-2.6.23.17.orig/drivers/serial/8250.c
1756 +++ linux-2.6.23.17/drivers/serial/8250.c
1757 @@ -2118,6 +2118,8 @@ serial8250_set_termios(struct uart_port
1758 up->ier |= UART_IER_MSI;
1759 if (up->capabilities & UART_CAP_UUE)
1760 up->ier |= UART_IER_UUE | UART_IER_RTOIE;
1761 + if (up->port.flags & UPF_HARDPPS_CD)
1762 + up->ier |= UART_IER_MSI; /* enable interrupts */
1764 serial_out(up, UART_IER, up->ier);
1766 Index: linux-2.6.23.17/drivers/serial/serial_core.c
1767 ===================================================================
1768 --- linux-2.6.23.17.orig/drivers/serial/serial_core.c
1769 +++ linux-2.6.23.17/drivers/serial/serial_core.c
1771 #include <linux/serial.h> /* for serial_state and serial_icounter_struct */
1772 #include <linux/delay.h>
1773 #include <linux/mutex.h>
1774 +#include <linux/pps.h>
1776 #include <asm/irq.h>
1777 #include <asm/uaccess.h>
1778 @@ -633,6 +634,54 @@ static int uart_get_info(struct uart_sta
1782 +#ifdef CONFIG_PPS_CLIENT_UART
1785 +uart_register_pps_port(struct uart_state *state, struct uart_port *port)
1787 + struct tty_driver *drv = port->info->tty->driver;
1790 + state->pps_info.owner = THIS_MODULE;
1791 + state->pps_info.dev = port->dev;
1792 + snprintf(state->pps_info.name, PPS_MAX_NAME_LEN, "%s%d",
1793 + drv->driver_name, port->line);
1794 + snprintf(state->pps_info.path, PPS_MAX_NAME_LEN, "/dev/%s%d",
1795 + drv->name, port->line);
1797 + state->pps_info.mode = PPS_CAPTUREBOTH | \
1798 + PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
1799 + PPS_CANWAIT | PPS_TSFMT_TSPEC;
1801 + ret = pps_register_source(&state->pps_info, PPS_CAPTUREBOTH | \
1802 + PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
1804 + dev_err(port->dev, "cannot register PPS source \"%s\"\n",
1805 + state->pps_info.path);
1808 + port->pps_source = ret;
1809 + dev_dbg(port->dev, "PPS source #%d \"%s\" added\n",
1810 + port->pps_source, state->pps_info.path);
1816 +uart_unregister_pps_port(struct uart_state *state, struct uart_port *port)
1818 + pps_unregister_source(port->pps_source);
1819 + dev_dbg(port->dev, "PPS source #%d \"%s\" removed\n",
1820 + port->pps_source, state->pps_info.path);
1825 +#define uart_register_pps_port(state, port) do { } while (0)
1826 +#define uart_unregister_pps_port(state, port) do { } while (0)
1828 +#endif /* CONFIG_PPS_CLIENT_UART */
1830 static int uart_set_info(struct uart_state *state,
1831 struct serial_struct __user *newinfo)
1833 @@ -807,11 +856,19 @@ static int uart_set_info(struct uart_sta
1834 (port->flags & UPF_LOW_LATENCY) ? 1 : 0;
1837 + /* PPS support enabled/disabled? */
1838 + if ((old_flags & UPF_HARDPPS_CD) != (new_flags & UPF_HARDPPS_CD)) {
1839 + if (new_flags & UPF_HARDPPS_CD)
1840 + uart_register_pps_port(state, port);
1842 + uart_unregister_pps_port(state, port);
1846 if (port->type == PORT_UNKNOWN)
1848 if (state->info->flags & UIF_INITIALIZED) {
1849 - if (((old_flags ^ port->flags) & UPF_SPD_MASK) ||
1850 + if (((old_flags ^ port->flags) & (UPF_SPD_MASK|UPF_HARDPPS_CD)) ||
1851 old_custom_divisor != port->custom_divisor) {
1853 * If they're setting up a custom divisor or speed,
1854 @@ -2110,6 +2167,12 @@ uart_configure_port(struct uart_driver *
1855 port->ops->config_port(port, flags);
1859 + * Add the PPS support for the current port.
1861 + if (port->flags & UPF_HARDPPS_CD)
1862 + uart_register_pps_port(state, port);
1864 if (port->type != PORT_UNKNOWN) {
1865 unsigned long flags;
1867 @@ -2359,6 +2422,12 @@ int uart_remove_one_port(struct uart_dri
1868 mutex_unlock(&state->mutex);
1871 + * Remove PPS support from the current port.
1873 + if (port->flags & UPF_HARDPPS_CD)
1874 + uart_unregister_pps_port(state, port);
1877 * Remove the devices from the tty layer
1879 tty_unregister_device(drv->tty_driver, port->line);
1880 Index: linux-2.6.23.17/include/linux/Kbuild
1881 ===================================================================
1882 --- linux-2.6.23.17.orig/include/linux/Kbuild
1883 +++ linux-2.6.23.17/include/linux/Kbuild
1884 @@ -295,6 +295,7 @@ unifdef-y += pmu.h
1886 unifdef-y += ppp_defs.h
1887 unifdef-y += ppp-comp.h
1889 unifdef-y += ptrace.h
1890 unifdef-y += qnx4_fs.h
1891 unifdef-y += quota.h
1892 Index: linux-2.6.23.17/include/linux/parport.h
1893 ===================================================================
1894 --- linux-2.6.23.17.orig/include/linux/parport.h
1895 +++ linux-2.6.23.17/include/linux/parport.h
1896 @@ -100,6 +100,7 @@ typedef enum {
1897 #include <linux/proc_fs.h>
1898 #include <linux/spinlock.h>
1899 #include <linux/wait.h>
1900 +#include <linux/pps.h>
1901 #include <asm/system.h>
1902 #include <asm/ptrace.h>
1903 #include <asm/semaphore.h>
1904 @@ -327,6 +328,11 @@ struct parport {
1906 struct list_head full_list;
1907 struct parport *slaves[3];
1909 +#ifdef CONFIG_PPS_CLIENT_LP
1910 + struct pps_source_info pps_info;
1911 + int pps_source; /* PPS source ID */
1915 #define DEFAULT_SPIN_TIME 500 /* us */
1916 @@ -517,6 +523,12 @@ extern int parport_daisy_select (struct
1917 /* Lowlevel drivers _can_ call this support function to handle irqs. */
1918 static __inline__ void parport_generic_irq(int irq, struct parport *port)
1920 +#ifdef CONFIG_PPS_CLIENT_LP
1921 + pps_event(port->pps_source, PPS_CAPTUREASSERT, port);
1922 + dev_dbg(port->dev, "PPS assert at %lu on source #%d\n",
1923 + jiffies, port->pps_source);
1926 parport_ieee1284_interrupt (irq, port);
1927 read_lock(&port->cad_lock);
1928 if (port->cad && port->cad->irq_func)
1929 Index: linux-2.6.23.17/include/linux/pps.h
1930 ===================================================================
1932 +++ linux-2.6.23.17/include/linux/pps.h
1935 + * pps.h -- PPS API kernel header.
1938 + * Copyright (C) 2005-2007 Rodolfo Giometti <giometti@linux.it>
1940 + * This program is free software; you can redistribute it and/or modify
1941 + * it under the terms of the GNU General Public License as published by
1942 + * the Free Software Foundation; either version 2 of the License, or
1943 + * (at your option) any later version.
1945 + * This program is distributed in the hope that it will be useful,
1946 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1947 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1948 + * GNU General Public License for more details.
1950 + * You should have received a copy of the GNU General Public License
1951 + * along with this program; if not, write to the Free Software
1952 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1959 +/* Implementation note: the logical states ``assert'' and ``clear''
1960 + * are implemented in terms of the chip register, i.e. ``assert''
1961 + * means the bit is set. */
1964 + * 3.2 New data structures
1968 +#include <linux/types.h>
1969 +#include <sys/time.h>
1970 +#include <sys/ioctl.h>
1972 +#include <linux/time.h>
1975 +#define PPS_API_VERS 1
1976 +#define PPS_MAX_NAME_LEN 32
1978 +/* 32-bit vs. 64-bit compatibility.
1980 + * 0n i386, the alignment of a uint64_t is only 4 bytes, while on most other
1981 + * architectures it's 8 bytes. On i386, there will be no padding between the
1982 + * two consecutive 'struct pps_ktime' members of struct pps_kinfo and struct
1983 + * pps_kparams. But on most platforms there will be padding to ensure correct
1986 + * The simple fix is probably to add an explicit padding.
1987 + * [David Woodhouse]
1994 +#define PPS_TIME_INVALID (1<<0) /* used to specify timeout==NULL */
1997 + __u32 assert_sequence; /* seq. num. of assert event */
1998 + __u32 clear_sequence; /* seq. num. of clear event */
1999 + struct pps_ktime assert_tu; /* time of assert event */
2000 + struct pps_ktime clear_tu; /* time of clear event */
2001 + int current_mode; /* current mode bits */
2004 +struct pps_kparams {
2005 + int api_version; /* API version # */
2006 + int mode; /* mode bits */
2007 + struct pps_ktime assert_off_tu; /* offset compensation for assert */
2008 + struct pps_ktime clear_off_tu; /* offset compensation for clear */
2012 + * 3.3 Mode bit definitions
2015 +/* Device/implementation parameters */
2016 +#define PPS_CAPTUREASSERT 0x01 /* capture assert events */
2017 +#define PPS_CAPTURECLEAR 0x02 /* capture clear events */
2018 +#define PPS_CAPTUREBOTH 0x03 /* capture assert and clear events */
2020 +#define PPS_OFFSETASSERT 0x10 /* apply compensation for assert ev. */
2021 +#define PPS_OFFSETCLEAR 0x20 /* apply compensation for clear ev. */
2023 +#define PPS_CANWAIT 0x100 /* can we wait for an event? */
2024 +#define PPS_CANPOLL 0x200 /* bit reserved for future use */
2026 +/* Kernel actions */
2027 +#define PPS_ECHOASSERT 0x40 /* feed back assert event to output */
2028 +#define PPS_ECHOCLEAR 0x80 /* feed back clear event to output */
2030 +/* Timestamp formats */
2031 +#define PPS_TSFMT_TSPEC 0x1000 /* select timespec format */
2032 +#define PPS_TSFMT_NTPFP 0x2000 /* select NTP format */
2035 + * 3.4.4 New functions: disciplining the kernel timebase
2038 +/* Kernel consumers */
2039 +#define PPS_KC_HARDPPS 0 /* hardpps() (or equivalent) */
2040 +#define PPS_KC_HARDPPS_PLL 1 /* hardpps() constrained to
2041 + use a phase-locked loop */
2042 +#define PPS_KC_HARDPPS_FLL 2 /* hardpps() constrained to
2043 + use a frequency-locked loop */
2045 + * Here begins the implementation-specific part!
2049 + struct pps_kinfo info;
2050 + struct pps_ktime timeout;
2053 +#include <linux/ioctl.h>
2055 +#define PPS_CHECK _IO('P', 0)
2056 +#define PPS_GETPARAMS _IOR('P', 1, struct pps_kparams *)
2057 +#define PPS_SETPARAMS _IOW('P', 2, struct pps_kparams *)
2058 +#define PPS_GETCAP _IOR('P', 3, int *)
2059 +#define PPS_FETCH _IOWR('P', 4, struct pps_fdata *)
2063 +#include <linux/cdev.h>
2064 +#include <linux/device.h>
2066 +#define PPS_VERSION "5.0.0-rc2"
2067 +#define PPS_MAX_SOURCES 16 /* should be enought... */
2073 +/* The specific PPS source info */
2074 +struct pps_source_info {
2075 + char name[PPS_MAX_NAME_LEN]; /* simbolic name */
2076 + char path[PPS_MAX_NAME_LEN]; /* path of connected device */
2077 + int mode; /* PPS's allowed mode */
2079 + void (*echo)(int source, int event, void *data); /* PPS echo function */
2081 + struct module *owner;
2082 + struct device *dev;
2085 +/* The main struct */
2086 +struct pps_device {
2087 + struct pps_source_info info; /* PSS source info */
2089 + struct pps_kparams params; /* PPS's current params */
2091 + __u32 assert_sequence; /* PPS' assert event seq # */
2092 + __u32 clear_sequence; /* PPS' clear event seq # */
2093 + struct pps_ktime assert_tu;
2094 + struct pps_ktime clear_tu;
2095 + int current_mode; /* PPS mode at event time */
2097 + int go; /* PPS event is arrived? */
2098 + wait_queue_head_t queue; /* PPS event queue */
2100 + unsigned int id; /* PPS source unique ID */
2102 + struct device *dev;
2104 + struct fasync_struct *async_queue; /* fasync method */
2107 + atomic_t usage; /* usage count */
2108 + wait_queue_head_t usage_queue;
2110 + struct class_device class_dev;
2114 + * Exported functions
2117 +extern int pps_register_source(struct pps_source_info *info,
2118 + int default_params);
2119 +extern void pps_unregister_source(int source);
2120 +extern int pps_register_cdev(struct pps_device *pps);
2121 +extern void pps_unregister_cdev(struct pps_device *pps);
2122 +extern void pps_event(int source, int event, void *data);
2124 +extern int pps_sysfs_create_source_entry(struct pps_device *pps);
2125 +extern void pps_sysfs_remove_source_entry(struct pps_device *pps);
2127 +#endif /* __KERNEL__ */
2129 +#endif /* _PPS_H_ */
2130 Index: linux-2.6.23.17/include/linux/serial_core.h
2131 ===================================================================
2132 --- linux-2.6.23.17.orig/include/linux/serial_core.h
2133 +++ linux-2.6.23.17/include/linux/serial_core.h
2135 #include <linux/tty.h>
2136 #include <linux/mutex.h>
2137 #include <linux/sysrq.h>
2138 +#include <linux/pps.h>
2142 @@ -236,6 +237,9 @@ struct uart_port {
2143 unsigned char regshift; /* reg offset shift */
2144 unsigned char iotype; /* io access style */
2145 unsigned char unused1;
2146 +#ifdef CONFIG_PPS_CLIENT_UART
2147 + int pps_source; /* PPS source ID */
2150 #define UPIO_PORT (0)
2151 #define UPIO_HUB6 (1)
2152 @@ -280,7 +284,8 @@ struct uart_port {
2153 #define UPF_IOREMAP ((__force upf_t) (1 << 31))
2155 #define UPF_CHANGE_MASK ((__force upf_t) (0x17fff))
2156 -#define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))
2157 +#define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY\
2160 unsigned int mctrl; /* current modem ctrl settings */
2161 unsigned int timeout; /* character-based timeout */
2162 @@ -312,6 +317,10 @@ struct uart_state {
2163 struct uart_info *info;
2164 struct uart_port *port;
2166 +#ifdef CONFIG_PPS_CLIENT_UART
2167 + struct pps_source_info pps_info;
2173 @@ -476,13 +485,22 @@ uart_handle_dcd_change(struct uart_port
2175 struct uart_info *info = port->info;
2177 - port->icount.dcd++;
2179 -#ifdef CONFIG_HARD_PPS
2180 - if ((port->flags & UPF_HARDPPS_CD) && status)
2182 +#ifdef CONFIG_PPS_CLIENT_UART
2183 + if (port->flags & UPF_HARDPPS_CD) {
2185 + pps_event(port->pps_source, PPS_CAPTUREASSERT, port);
2186 + dev_dbg(port->dev, "PPS assert at %lu on source #%d\n",
2187 + jiffies, port->pps_source);
2189 + pps_event(port->pps_source, PPS_CAPTURECLEAR, port);
2190 + dev_dbg(port->dev, "PPS clear at %lu on source #%d\n",
2191 + jiffies, port->pps_source);
2196 + port->icount.dcd++;
2198 if (info->flags & UIF_CHECK_CD) {
2200 wake_up_interruptible(&info->open_wait);