refresh generic 2.6.23 patches
[oweals/openwrt.git] / target / linux / generic-2.6 / patches-2.6.23 / 230-pps_support.patch
1 Index: linux-2.6.23.17/Documentation/pps/Makefile
2 ===================================================================
3 --- /dev/null
4 +++ linux-2.6.23.17/Documentation/pps/Makefile
5 @@ -0,0 +1,27 @@
6 +TARGETS = ppstest ppsctl
7 +
8 +CFLAGS += -Wall -O2 -D_GNU_SOURCE
9 +CFLAGS += -I .
10 +CFLAGS += -ggdb
11 +
12 +# -- Actions section ----------------------------------------------------------
13 +
14 +.PHONY : all depend dep
15 +
16 +all : .depend $(TARGETS)
17 +
18 +.depend depend dep :
19 +       $(CC) $(CFLAGS) -M $(TARGETS:=.c) > .depend
20 +
21 +ifeq (.depend,$(wildcard .depend))
22 +include .depend
23 +endif
24 +
25 +
26 +# -- Clean section ------------------------------------------------------------
27 +
28 +.PHONY : clean
29 +
30 +clean :
31 +       rm -f *.o *~ core .depend
32 +       rm -f ${TARGETS}
33 Index: linux-2.6.23.17/Documentation/pps/pps.txt
34 ===================================================================
35 --- /dev/null
36 +++ linux-2.6.23.17/Documentation/pps/pps.txt
37 @@ -0,0 +1,170 @@
38 +
39 +                       PPS - Pulse Per Second
40 +                       ----------------------
41 +
42 +(C) Copyright 2007 Rodolfo Giometti <giometti@enneenne.com>
43 +
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.
48 +
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.
53 +
54 +
55 +
56 +Overview
57 +--------
58 +
59 +LinuxPPS provides a programming interface (API) to define into the
60 +system several PPS sources.
61 +
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.
65 +
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.
71 +
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.
75 +
76 +
77 +RFC considerations
78 +------------------
79 +
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
82 +problem:
83 +
84 +   At startup it needs a file descriptor as argument for the function
85 +   time_pps_create().
86 +
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.
94 +
95 +The problem can be simply solved if you consider that a PPS source is
96 +not always connected with a GPS data source.
97 +
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.
101 +
102 +In LinuxPPS the PPS sources are simply char devices usually mapped
103 +into files /dev/pps0, /dev/pps1, etc..
104 +
105 +
106 +Coding example
107 +--------------
108 +
109 +To register a PPS source into the kernel you should define a struct
110 +pps_source_info_s as follow:
111 +
112 +    static struct pps_source_info_s pps_ktimer_info = {
113 +            name         : "ktimer",
114 +            path         : "",
115 +            mode         : PPS_CAPTUREASSERT | PPS_OFFSETASSERT | \
116 +                          PPS_ECHOASSERT | \
117 +                           PPS_CANWAIT | PPS_TSFMT_TSPEC,
118 +            echo         : pps_ktimer_echo,
119 +            owner        : THIS_MODULE,
120 +    };
121 +
122 +and then calling the function pps_register_source() in your
123 +intialization routine as follow:
124 +
125 +    source = pps_register_source(&pps_ktimer_info,
126 +                       PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
127 +
128 +The pps_register_source() prototype is:
129 +
130 +  int pps_register_source(struct pps_source_info_s *info, int default_params)
131 +
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).
137 +
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)
140 +just using:
141 +
142 +    pps_event(source, PPS_CAPTUREASSERT, ptr);
143 +
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..
147 +
148 +Please see the file drivers/pps/clients/ktimer.c for an example code.
149 +
150 +
151 +SYSFS support
152 +-------------
153 +
154 +If the SYSFS filesystem is enabled in the kernel it provides a new class:
155 +
156 +   $ ls /sys/class/pps/
157 +   pps0/  pps1/  pps2/
158 +
159 +Every directory is the ID of a PPS sources defined into the system and
160 +inside you find several files:
161 +
162 +    $ ls /sys/class/pps/pps0/
163 +    assert     clear  echo  mode  name  path  subsystem@  uevent
164 +
165 +Inside each "assert" and "clear" file you can find the timestamp and a
166 +sequence number:
167 +
168 +    $ cat /sys/class/pps/pps0/assert
169 +    1170026870.983207967#8
170 +
171 +Where before the "#" is the timestamp in seconds and after it is the
172 +sequence number. Other files are:
173 +
174 +* echo: reports if the PPS source has an echo function or not;
175 +
176 +* mode: reports available PPS functioning modes;
177 +
178 +* name: reports the PPS source's name;
179 +
180 +* path: reports the PPS source's device path, that is the device the
181 +  PPS source is connected to (if it exists).
182 +
183 +
184 +Testing the PPS support
185 +-----------------------
186 +
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.
190 +
191 +Once you have enabled the compilation of ktimer just modprobe it (if
192 +not statically compiled):
193 +
194 +   # modprobe ktimer
195 +
196 +and the run ppstest as follow:
197 +
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
205 +
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 ===================================================================
210 --- /dev/null
211 +++ linux-2.6.23.17/Documentation/pps/ppsctl.c
212 @@ -0,0 +1,62 @@
213 +#include <stdio.h>
214 +#include <unistd.h>
215 +#include <stdlib.h>
216 +#include <errno.h>
217 +#include <sys/ioctl.h>
218 +#include <sys/types.h>
219 +#include <sys/stat.h>
220 +#include <fcntl.h>
221 +#include <string.h>
222 +#include <linux/serial.h>
223 +
224 +void usage(char *name)
225 +{
226 +       fprintf(stderr, "usage: %s <ttyS> [enable|disable]\n", name);
227 +
228 +       exit(EXIT_FAILURE);
229 +}
230 +
231 +int main(int argc, char *argv[])
232 +{
233 +       int fd;
234 +       int ret;
235 +       struct serial_struct ss;
236 +
237 +       if (argc < 2)
238 +               usage(argv[0]);
239 +
240 +       fd = open(argv[1], O_RDWR);
241 +       if (fd < 0) {
242 +               perror("open");
243 +               exit(EXIT_FAILURE);
244 +       }
245 +
246 +       ret = ioctl(fd, TIOCGSERIAL, &ss);
247 +       if (ret < 0) {
248 +               perror("ioctl(TIOCGSERIAL)");
249 +               exit(EXIT_FAILURE);
250 +       }
251 +
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);
256 +       }
257 +
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;
262 +       else {
263 +               fprintf(stderr, "invalid state argument \"%s\"\n", argv[2]);
264 +               exit(EXIT_FAILURE);
265 +       }
266 +
267 +       ret = ioctl(fd, TIOCSSERIAL, &ss);
268 +       if (ret < 0) {
269 +               perror("ioctl(TIOCSSERIAL)");
270 +               exit(EXIT_FAILURE);
271 +       }
272 +
273 +       return 0;
274 +}
275 Index: linux-2.6.23.17/Documentation/pps/ppsfind
276 ===================================================================
277 --- /dev/null
278 +++ linux-2.6.23.17/Documentation/pps/ppsfind
279 @@ -0,0 +1,17 @@
280 +#!/bin/sh
281 +
282 +SYS="/sys/class/pps/"
283 +
284 +if [ $# -lt 1 ] ; then
285 +       echo "usage: ppsfind <name>" >&2
286 +       exit 1
287 +fi
288 +
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)"
293 +       fi
294 +done
295 +
296 +exit 0
297 Index: linux-2.6.23.17/Documentation/pps/ppstest.c
298 ===================================================================
299 --- /dev/null
300 +++ linux-2.6.23.17/Documentation/pps/ppstest.c
301 @@ -0,0 +1,151 @@
302 +#include <stdio.h>
303 +#include <stdlib.h>
304 +#include <unistd.h>
305 +#include <errno.h>
306 +#include <string.h>
307 +#include <sys/types.h>
308 +#include <sys/stat.h>
309 +#include <fcntl.h>
310 +
311 +#include <timepps.h>
312 +
313 +int find_source(char *path, pps_handle_t *handle, int *avail_mode)
314 +{
315 +       pps_params_t params;
316 +       int ret;
317 +
318 +       printf("trying PPS source \"%s\"\n", path);
319 +
320 +       /* Try to find the source by using the supplied "path" name */
321 +       ret = open(path, O_RDWR);
322 +       if (ret < 0) {
323 +               fprintf(stderr, "unable to open device \"%s\" (%m)\n", path);
324 +               return ret;
325 +       }
326 +
327 +       /* Open the PPS source (and check the file descriptor) */
328 +       ret = time_pps_create(ret, handle);
329 +       if (ret < 0) {
330 +               fprintf(stderr, "cannot create a PPS source from device "
331 +                               "\"%s\" (%m)\n", path);
332 +               return -1;
333 +       }
334 +       printf("found PPS source \"%s\"\n", path);
335 +
336 +       /* Find out what features are supported */
337 +       ret = time_pps_getcap(*handle, avail_mode);
338 +       if (ret < 0) {
339 +               fprintf(stderr, "cannot get capabilities (%m)\n");
340 +               return -1;
341 +       }
342 +       if ((*avail_mode & PPS_CAPTUREASSERT) == 0) {
343 +               fprintf(stderr, "cannot CAPTUREASSERT\n");
344 +               return -1;
345 +       }
346 +       if ((*avail_mode & PPS_OFFSETASSERT) == 0) {
347 +               fprintf(stderr, "cannot OFFSETASSERT\n");
348 +               return -1;
349 +       }
350 +
351 +       /* Capture assert timestamps, and compensate for a 675 nsec
352 +        * propagation delay */
353 +       ret = time_pps_getparams(*handle, &params);
354 +       if (ret < 0) {
355 +               fprintf(stderr, "cannot get parameters (%m)\n");
356 +               return -1;
357 +       }
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, &params);
362 +       if (ret < 0) {
363 +               fprintf(stderr, "cannot set parameters (%m)\n");
364 +               return -1;
365 +       }
366 +
367 +       return 0;
368 +}
369 +
370 +int fetch_source(int i, pps_handle_t *handle, int *avail_mode)
371 +{
372 +       struct timespec timeout;
373 +       pps_info_t infobuf;
374 +       int ret;
375 +
376 +       /* create a zero-valued timeout */
377 +       timeout.tv_sec = 3;
378 +       timeout.tv_nsec = 0;
379 +
380 +retry:
381 +       if (*avail_mode & PPS_CANWAIT) /* waits for the next event */
382 +               ret = time_pps_fetch(*handle, PPS_TSFMT_TSPEC, &infobuf,
383 +                                  &timeout);
384 +       else {
385 +               sleep(1);
386 +               ret = time_pps_fetch(*handle, PPS_TSFMT_TSPEC, &infobuf,
387 +                                  &timeout);
388 +       }
389 +       if (ret < 0) {
390 +               if (ret == -EINTR) {
391 +                       fprintf(stderr, "time_pps_fetch() got a signal!\n");
392 +                       goto retry;
393 +               }
394 +
395 +               fprintf(stderr, "time_pps_fetch() error %d (%m)\n", ret);
396 +               return -1;
397 +       }
398 +
399 +       printf("source %d - "
400 +              "assert %ld.%09ld, sequence: %ld - "
401 +              "clear  %ld.%09ld, sequence: %ld\n",
402 +              i,
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);
408 +
409 +       return 0;
410 +}
411 +
412 +void usage(char *name)
413 +{
414 +       fprintf(stderr, "usage: %s <ppsdev> [<ppsdev> ...]\n", name);
415 +       exit(EXIT_FAILURE);
416 +}
417 +
418 +int main(int argc, char *argv[])
419 +{
420 +       int num;
421 +       pps_handle_t handle[4];
422 +       int avail_mode[4];
423 +       int i = 0;
424 +       int ret;
425 +
426 +       /* Check the command line */
427 +       if (argc < 2)
428 +               usage(argv[0]);
429 +
430 +       for (i = 1; i < argc && i <= 4; i++) {
431 +               ret = find_source(argv[i], &handle[i - 1], &avail_mode[i - 1]);
432 +               if (ret < 0)
433 +                       exit(EXIT_FAILURE);
434 +       }
435 +
436 +       num = i - 1;
437 +       printf("ok, found %d source(s), now start fetching data...\n", num);
438 +
439 +       /* loop, printing the most recent timestamp every second or so */
440 +       while (1) {
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);
445 +               }
446 +       }
447 +
448 +       for (; i >= 0; i--)
449 +               time_pps_destroy(handle[i]);
450 +
451 +       return 0;
452 +}
453 Index: linux-2.6.23.17/Documentation/pps/timepps.h
454 ===================================================================
455 --- /dev/null
456 +++ linux-2.6.23.17/Documentation/pps/timepps.h
457 @@ -0,0 +1,193 @@
458 +/*
459 + * timepps.h -- PPS API main header
460 + *
461 + * Copyright (C) 2005-2007   Rodolfo Giometti <giometti@linux.it>
462 + *
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.
467 + *
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.
472 + *
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.
476 + */
477 +
478 +#ifndef _SYS_TIMEPPS_H_
479 +#define _SYS_TIMEPPS_H_
480 +
481 +#include <sys/syscall.h>
482 +#include <unistd.h>
483 +#include <errno.h>
484 +#include <linux/pps.h>
485 +
486 +/*
487 + * New data structures
488 + */
489 +
490 +struct ntp_fp {
491 +       unsigned int integral;
492 +       unsigned int fractional;
493 +};
494 +
495 +union pps_timeu {
496 +       struct timespec tspec;
497 +       struct ntp_fp ntpfp;
498 +       unsigned long longpad[3];
499 +};
500 +
501 +struct pps_info {
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 */
507 +};
508 +
509 +struct pps_params {
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 */
514 +};
515 +
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;
522 +
523 +#define assert_timestamp        assert_tu.tspec
524 +#define clear_timestamp         clear_tu.tspec
525 +
526 +#define assert_timestamp_ntpfp  assert_tu.ntpfp
527 +#define clear_timestamp_ntpfp   clear_tu.ntpfp
528 +
529 +#define assert_offset          assert_off_tu.tspec
530 +#define clear_offset           clear_off_tu.tspec
531 +
532 +#define assert_offset_ntpfp     assert_off_tu.ntpfp
533 +#define clear_offset_ntpfp      clear_off_tu.ntpfp
534 +
535 +/*
536 + * The PPS API
537 + */
538 +
539 +static __inline int time_pps_create(int source, pps_handle_t *handle)
540 +{
541 +       int ret;
542 +
543 +       if (!handle) {
544 +               errno = EINVAL;
545 +               return -1;
546 +       }
547 +
548 +       /* First we check if current device is a PPS valid PPS one...
549 +        */
550 +       ret = ioctl(source, PPS_CHECK);
551 +       if (ret) {
552 +               errno = EOPNOTSUPP;
553 +               return -1;
554 +       }
555 +
556 +       /* ... then since in LinuxPPS there are no differences between a
557 +        * "PPS source" and a "PPS handle", we simply return the same value.
558 +        */
559 +       *handle = source;
560 +
561 +       return 0;
562 +}
563 +
564 +static __inline int time_pps_destroy(pps_handle_t handle)
565 +{
566 +       return close(handle);
567 +}
568 +
569 +static __inline int time_pps_getparams(pps_handle_t handle,
570 +                                       pps_params_t *ppsparams)
571 +{
572 +       int ret;
573 +       struct pps_kparams __ppsparams;
574 +
575 +       ret = ioctl(handle, PPS_GETPARAMS, &__ppsparams);
576 +
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;
583 +
584 +       return ret;
585 +}
586 +
587 +static __inline int time_pps_setparams(pps_handle_t handle,
588 +                                       const pps_params_t *ppsparams)
589 +{
590 +       struct pps_kparams __ppsparams;
591 +
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;
598 +
599 +       return ioctl(handle, PPS_SETPARAMS, &__ppsparams);
600 +}
601 +
602 +/* Get capabilities for handle */
603 +static __inline int time_pps_getcap(pps_handle_t handle, int *mode)
604 +{
605 +       return ioctl(handle, PPS_GETCAP, mode);
606 +}
607 +
608 +static __inline int time_pps_fetch(pps_handle_t handle, const int tsformat,
609 +                                       pps_info_t *ppsinfobuf,
610 +                                       const struct timespec *timeout)
611 +{
612 +       struct pps_fdata __fdata;
613 +       int ret;
614 +
615 +       /* Sanity checks */
616 +       if (tsformat != PPS_TSFMT_TSPEC) {
617 +               errno = EINVAL;
618 +               return -1;
619 +       }
620 +
621 +       if (timeout) {
622 +               __fdata.timeout.sec = timeout->tv_sec;
623 +               __fdata.timeout.nsec = timeout->tv_nsec;
624 +               __fdata.timeout.flags = ~PPS_TIME_INVALID;
625 +       } else
626 +               __fdata.timeout.flags = PPS_TIME_INVALID;
627 +
628 +       ret = ioctl(handle, PPS_FETCH, &__fdata);
629 +
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;
637 +
638 +       return ret;
639 +}
640 +
641 +static __inline int time_pps_kcbind(pps_handle_t handle,
642 +                                       const int kernel_consumer,
643 +                                       const int edge, const int tsformat)
644 +{
645 +       /* LinuxPPS doesn't implement kernel consumer feature */
646 +       errno = EOPNOTSUPP;
647 +       return -1;
648 +}
649 +
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
657  S:     Maintained
658  
659 +PPS SUPPORT
660 +P:     Rodolfo Giometti
661 +M:     giometti@enneenne.com
662 +W:     http://wiki.enneenne.com/index.php/LinuxPPS_support
663 +L:     linuxpps@ml.enneenne.com
664 +S:     Maintained
665 +
666  PREEMPTIBLE KERNEL
667  P:     Robert Love
668  M:     rml@tech9.net
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"
674  
675  source "drivers/spi/Kconfig"
676  
677 +source "drivers/pps/Kconfig"
678 +
679  source "drivers/w1/Kconfig"
680  
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/
689  obj-y                          += i2c/
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 = {
699  
700  #endif /* console on line printer */
701  
702 +/* Support for PPS signal on the line printer */
703 +
704 +#ifdef CONFIG_PPS_CLIENT_LP
705 +
706 +static void lp_pps_echo(int source, int event, void *data)
707 +{
708 +       struct parport *port = data;
709 +       unsigned char status = parport_read_status(port);
710 +
711 +       /* echo event via SEL bit */
712 +       parport_write_control(port,
713 +               parport_read_control(port) | PARPORT_CONTROL_SELECT);
714 +
715 +       /* signal no event */
716 +       if ((status & PARPORT_STATUS_ACK) != 0)
717 +               parport_write_control(port,
718 +                       parport_read_control(port) & ~PARPORT_CONTROL_SELECT);
719 +}
720 +
721 +#endif
722 +
723  /* --- initialisation code ------------------------------------- */
724  
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
727         }
728  #endif
729  
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);
734 +
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);
738 +
739 +               port->pps_info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT | \
740 +                               PPS_ECHOASSERT | \
741 +                               PPS_CANWAIT | PPS_TSFMT_TSPEC;
742 +
743 +               port->pps_info.echo = lp_pps_echo;
744 +
745 +               port->pps_source = pps_register_source(&(port->pps_info),
746 +                               PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
747 +               if (port->pps_source < 0)
748 +                       dev_err(port->dev,
749 +                                       "cannot register PPS source \"%s\"\n",
750 +                                       port->pps_info.path);
751 +               else
752 +                       dev_info(port->dev, "PPS source #%d \"%s\" added\n",
753 +                                       port->pps_source, port->pps_info.path);
754 +       } else {
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);
759 +       }
760 +#endif
761 +
762         return 0;
763  }
764  
765 @@ -860,6 +913,14 @@ static void lp_detach (struct parport *p
766                 console_registered = NULL;
767         }
768  #endif /* CONFIG_LP_CONSOLE */
769 +
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);
775 +       }
776 +#endif
777  }
778  
779  static struct parport_driver lp_driver = {
780 Index: linux-2.6.23.17/drivers/pps/Kconfig
781 ===================================================================
782 --- /dev/null
783 +++ linux-2.6.23.17/drivers/pps/Kconfig
784 @@ -0,0 +1,34 @@
785 +#
786 +# PPS support configuration
787 +#
788 +
789 +menu "PPS support"
790 +
791 +config PPS
792 +       tristate "PPS support"
793 +       depends on EXPERIMENTAL
794 +       ---help---
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.
797 +
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.
801 +
802 +         Some antennae's PPS signals are connected with some special host
803 +         inputs so you have to enable the corresponding client support.
804 +
805 +         To compile this driver as a module, choose M here: the module
806 +         will be called pps_core.ko.
807 +
808 +config PPS_DEBUG
809 +       bool "PPS debugging messages"
810 +       depends on PPS 
811 +       help
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.
815 +
816 +source drivers/pps/clients/Kconfig
817 +
818 +endmenu
819 Index: linux-2.6.23.17/drivers/pps/Makefile
820 ===================================================================
821 --- /dev/null
822 +++ linux-2.6.23.17/drivers/pps/Makefile
823 @@ -0,0 +1,11 @@
824 +#
825 +# Makefile for the PPS core.
826 +#
827 +
828 +pps_core-objs                  += pps.o kapi.o sysfs.o
829 +obj-$(CONFIG_PPS)              += pps_core.o
830 +obj-y                          += clients/
831 +
832 +ifeq ($(CONFIG_PPS_DEBUG),y)
833 +EXTRA_CFLAGS += -DDEBUG
834 +endif
835 Index: linux-2.6.23.17/drivers/pps/clients/Kconfig
836 ===================================================================
837 --- /dev/null
838 +++ linux-2.6.23.17/drivers/pps/clients/Kconfig
839 @@ -0,0 +1,38 @@
840 +#
841 +# PPS clients configuration
842 +#
843 +
844 +if PPS
845 +
846 +comment "PPS clients support"
847 +
848 +config PPS_CLIENT_KTIMER
849 +       tristate "Kernel timer client (Testing client, use for debug)"
850 +       help
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.
853 +
854 +         This driver can also be built as a module.  If so, the module
855 +         will be called ktimer.ko.
856 +
857 +comment "UART serial support (forced off)"
858 +       depends on ! (SERIAL_CORE != n && !(PPS = m && SERIAL_CORE = y))
859 +
860 +config PPS_CLIENT_UART
861 +       bool "UART serial support"
862 +       depends on SERIAL_CORE != n && !(PPS = m && SERIAL_CORE = y)
863 +       help
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.
866 +
867 +comment "Parallel printer support (forced off)"
868 +       depends on !( PRINTER != n && !(PPS = m && PRINTER = y))
869 +
870 +config PPS_CLIENT_LP
871 +       bool "Parallel printer support"
872 +       depends on PRINTER != n && !(PPS = m && PRINTER = y)
873 +       help
874 +         If you say yes here you get support for a PPS source connected
875 +         with the interrupt pin of your parallel port.
876 +
877 +endif
878 Index: linux-2.6.23.17/drivers/pps/clients/Makefile
879 ===================================================================
880 --- /dev/null
881 +++ linux-2.6.23.17/drivers/pps/clients/Makefile
882 @@ -0,0 +1,9 @@
883 +#
884 +# Makefile for PPS clients.
885 +#
886 +
887 +obj-$(CONFIG_PPS_CLIENT_KTIMER)        += ktimer.o
888 +
889 +ifeq ($(CONFIG_PPS_DEBUG),y)
890 +EXTRA_CFLAGS += -DDEBUG
891 +endif
892 Index: linux-2.6.23.17/drivers/pps/clients/ktimer.c
893 ===================================================================
894 --- /dev/null
895 +++ linux-2.6.23.17/drivers/pps/clients/ktimer.c
896 @@ -0,0 +1,114 @@
897 +/*
898 + * ktimer.c -- kernel timer test client
899 + *
900 + *
901 + * Copyright (C) 2005-2006   Rodolfo Giometti <giometti@linux.it>
902 + *
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.
907 + *
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.
912 + *
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.
916 + */
917 +
918 +
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>
924 +
925 +#include <linux/pps.h>
926 +
927 +/*
928 + * Global variables
929 + */
930 +
931 +static int source;
932 +static struct timer_list ktimer;
933 +
934 +/*
935 + * The kernel timer
936 + */
937 +
938 +static void pps_ktimer_event(unsigned long ptr)
939 +{
940 +       pr_info("PPS event at %lu\n", jiffies);
941 +
942 +       pps_event(source, PPS_CAPTUREASSERT, NULL);
943 +
944 +       mod_timer(&ktimer, jiffies + HZ);
945 +}
946 +
947 +/*
948 + * The echo function
949 + */
950 +
951 +static void pps_ktimer_echo(int source, int event, void *data)
952 +{
953 +       pr_info("echo %s %s for source %d\n",
954 +               event & PPS_CAPTUREASSERT ? "assert" : "",
955 +               event & PPS_CAPTURECLEAR ? "clear" : "",
956 +               source);
957 +}
958 +
959 +/*
960 + * The PPS info struct
961 + */
962 +
963 +static struct pps_source_info pps_ktimer_info = {
964 +       name            : "ktimer",
965 +       path            : "",
966 +       mode            : PPS_CAPTUREASSERT | PPS_OFFSETASSERT | \
967 +                         PPS_ECHOASSERT | \
968 +                         PPS_CANWAIT | PPS_TSFMT_TSPEC,
969 +       echo            : pps_ktimer_echo,
970 +       owner           : THIS_MODULE,
971 +};
972 +
973 +/*
974 + * Module staff
975 + */
976 +
977 +static void __exit pps_ktimer_exit(void)
978 +{
979 +       del_timer_sync(&ktimer);
980 +       pps_unregister_source(source);
981 +
982 +       pr_info("ktimer PPS source unregistered\n");
983 +}
984 +
985 +static int __init pps_ktimer_init(void)
986 +{
987 +       int ret;
988 +
989 +       ret = pps_register_source(&pps_ktimer_info,
990 +                               PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
991 +       if (ret < 0) {
992 +               printk(KERN_ERR "cannot register ktimer source\n");
993 +               return ret;
994 +       }
995 +       source = ret;
996 +
997 +       setup_timer(&ktimer, pps_ktimer_event, 0);
998 +       mod_timer(&ktimer, jiffies + HZ);
999 +
1000 +       pr_info("ktimer PPS source registered at %d\n", source);
1001 +
1002 +       return  0;
1003 +}
1004 +
1005 +module_init(pps_ktimer_init);
1006 +module_exit(pps_ktimer_exit);
1007 +
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 ===================================================================
1013 --- /dev/null
1014 +++ linux-2.6.23.17/drivers/pps/kapi.c
1015 @@ -0,0 +1,271 @@
1016 +/*
1017 + * kapi.c -- kernel API
1018 + *
1019 + *
1020 + * Copyright (C) 2005-2007   Rodolfo Giometti <giometti@linux.it>
1021 + *
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.
1026 + *
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.
1031 + *
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.
1035 + */
1036 +
1037 +
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>
1047 +
1048 +/*
1049 + * Local variables
1050 + */
1051 +
1052 +static spinlock_t idr_lock = SPIN_LOCK_UNLOCKED;
1053 +static DEFINE_IDR(pps_idr);
1054 +
1055 +/*
1056 + * Local functions
1057 + */
1058 +
1059 +static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
1060 +{
1061 +       ts->nsec += offset->nsec;
1062 +       if (ts->nsec >= NSEC_PER_SEC) {
1063 +               ts->nsec -= NSEC_PER_SEC;
1064 +               ts->sec++;
1065 +       } else if (ts->nsec < 0) {
1066 +               ts->nsec += NSEC_PER_SEC;
1067 +               ts->sec--;
1068 +       }
1069 +       ts->sec += offset->sec;
1070 +}
1071 +
1072 +/*
1073 + * Exported functions
1074 + */
1075 +
1076 +int pps_register_source(struct pps_source_info *info, int default_params)
1077 +{
1078 +       struct pps_device *pps;
1079 +       int id;
1080 +       int err;
1081 +
1082 +       /* Sanity checks */
1083 +       if ((info->mode & default_params) != default_params) {
1084 +               printk(KERN_ERR "pps: %s: unsupported default parameters\n",
1085 +                                       info->name);
1086 +               err = -EINVAL;
1087 +               goto pps_register_source_exit;
1088 +       }
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",
1092 +                                       info->name);
1093 +               err = -EINVAL;
1094 +               goto pps_register_source_exit;
1095 +       }
1096 +       if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
1097 +               printk(KERN_ERR "pps: %s: unspecified time format\n",
1098 +                                       info->name);
1099 +               err = -EINVAL;
1100 +               goto pps_register_source_exit;
1101 +       }
1102 +
1103 +       /* Allocate memory for the new PPS source struct */
1104 +       pps = kzalloc(sizeof(struct pps_device), GFP_KERNEL);
1105 +       if (pps == NULL) {
1106 +               err = -ENOMEM;
1107 +               goto pps_register_source_exit;
1108 +       }
1109 +
1110 +       /* Get new ID for the new PPS source */
1111 +       if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) {
1112 +               err = -ENOMEM;
1113 +               goto kfree_pps;
1114 +       }
1115 +
1116 +       spin_lock_irq(&idr_lock);
1117 +       err = idr_get_new(&pps_idr, pps, &id);
1118 +       spin_unlock_irq(&idr_lock);
1119 +
1120 +       if (err < 0)
1121 +               goto kfree_pps;
1122 +
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",
1126 +                                       info->name);
1127 +               err = -EBUSY;
1128 +               goto free_idr;
1129 +       }
1130 +
1131 +       pps->id = id;
1132 +       pps->params.api_version = PPS_API_VERS;
1133 +       pps->params.mode = default_params;
1134 +       pps->info = *info;
1135 +
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);
1140 +
1141 +       /* Create the char device */
1142 +       err = pps_register_cdev(pps);
1143 +       if (err < 0) {
1144 +               printk(KERN_ERR "pps: %s: unable to create char device\n",
1145 +                                       info->name);
1146 +               goto free_idr;
1147 +       }
1148 +
1149 +       /* Create the sysfs entry */
1150 +       err = pps_sysfs_create_source_entry(pps);
1151 +       if (err < 0) {
1152 +               printk(KERN_ERR "pps: %s: unable to create sysfs entries\n",
1153 +                                       info->name);
1154 +               goto unregister_cdev;
1155 +       }
1156 +
1157 +       pr_info("new PPS source %s at ID %d\n", info->name, id);
1158 +
1159 +       return id;
1160 +
1161 +unregister_cdev:
1162 +       pps_unregister_cdev(pps);
1163 +
1164 +free_idr:
1165 +       spin_lock_irq(&idr_lock);
1166 +       idr_remove(&pps_idr, id);
1167 +       spin_unlock_irq(&idr_lock);
1168 +
1169 +kfree_pps:
1170 +       kfree(pps);
1171 +
1172 +pps_register_source_exit:
1173 +       printk(KERN_ERR "pps: %s: unable to register source\n", info->name);
1174 +
1175 +       return err;
1176 +}
1177 +EXPORT_SYMBOL(pps_register_source);
1178 +
1179 +void pps_unregister_source(int source)
1180 +{
1181 +       struct pps_device *pps;
1182 +
1183 +       spin_lock_irq(&idr_lock);
1184 +       pps = idr_find(&pps_idr, source);
1185 +
1186 +       if (!pps) {
1187 +               spin_unlock_irq(&idr_lock);
1188 +               return;
1189 +       }
1190 +
1191 +       /* This should be done first in order to deny IRQ handlers
1192 +        * to access PPS structs
1193 +        */
1194 +
1195 +       idr_remove(&pps_idr, pps->id);
1196 +       spin_unlock_irq(&idr_lock);
1197 +
1198 +       wait_event(pps->usage_queue, atomic_read(&pps->usage) == 0);
1199 +
1200 +       pps_sysfs_remove_source_entry(pps);
1201 +       pps_unregister_cdev(pps);
1202 +       kfree(pps);
1203 +}
1204 +EXPORT_SYMBOL(pps_unregister_source);
1205 +
1206 +void pps_event(int source, int event, void *data)
1207 +{
1208 +       struct pps_device *pps;
1209 +       struct timespec __ts;
1210 +       struct pps_ktime ts;
1211 +       unsigned long flags;
1212 +
1213 +       /* First of all we get the time stamp... */
1214 +       getnstimeofday(&__ts);
1215 +
1216 +       /* ... and translate it to PPS time data struct */
1217 +       ts.sec = __ts.tv_sec;
1218 +       ts.nsec = __ts.tv_nsec;
1219 +
1220 +       if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0 ) {
1221 +               printk(KERN_ERR "pps: unknown event (%x) for source %d\n",
1222 +                       event, source);
1223 +               return;
1224 +       }
1225 +
1226 +       spin_lock_irqsave(&idr_lock, flags);
1227 +       pps = idr_find(&pps_idr, source);
1228 +
1229 +       /* If we find a valid PPS source we lock it before leaving
1230 +        * the lock!
1231 +        */
1232 +       if (pps)
1233 +               atomic_inc(&pps->usage);
1234 +       spin_unlock_irqrestore(&idr_lock, flags);
1235 +
1236 +       if (!pps)
1237 +               return;
1238 +
1239 +       pr_debug("PPS event on source %d at at %llu.%06u\n",
1240 +                       pps->id, ts.sec, ts.nsec);
1241 +
1242 +       spin_lock_irqsave(&pps->lock, flags);
1243 +
1244 +       /* Must call the echo function? */
1245 +       if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
1246 +               pps->info.echo(source, event, data);
1247 +
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);
1254 +
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);
1260 +       }
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);
1265 +
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);
1271 +       }
1272 +
1273 +       pps->go = ~0;
1274 +       wake_up_interruptible(&pps->queue);
1275 +
1276 +       kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
1277 +
1278 +       spin_unlock_irqrestore(&pps->lock, flags);
1279 +
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);
1285 +}
1286 +EXPORT_SYMBOL(pps_event);
1287 Index: linux-2.6.23.17/drivers/pps/pps.c
1288 ===================================================================
1289 --- /dev/null
1290 +++ linux-2.6.23.17/drivers/pps/pps.c
1291 @@ -0,0 +1,332 @@
1292 +/*
1293 + * pps.c -- Main PPS support file
1294 + *
1295 + *
1296 + * Copyright (C) 2005-2007   Rodolfo Giometti <giometti@linux.it>
1297 + *
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.
1302 + *
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.
1307 + *
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.
1311 + */
1312 +
1313 +
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>
1323 +
1324 +/*
1325 + * Local variables
1326 + */
1327 +
1328 +static dev_t pps_devt;
1329 +static struct class *pps_class;
1330 +
1331 +/*
1332 + * Char device methods
1333 + */
1334 +
1335 +static unsigned int pps_cdev_poll(struct file *file, poll_table *wait)
1336 +{
1337 +       struct pps_device *pps = file->private_data;
1338 +
1339 +       poll_wait(file, &pps->queue, wait);
1340 +
1341 +       return POLLIN | POLLRDNORM;
1342 +}
1343 +
1344 +static int pps_cdev_fasync(int fd, struct file *file, int on)
1345 +{
1346 +       struct pps_device *pps = file->private_data;
1347 +       return fasync_helper(fd, file, on, &pps->async_queue);
1348 +}
1349 +
1350 +static int pps_cdev_ioctl(struct inode *inode, struct file *file,
1351 +               unsigned int cmd, unsigned long arg)
1352 +{
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;
1359 +       int err;
1360 +
1361 +       switch (cmd) {
1362 +       case PPS_CHECK:
1363 +
1364 +               /* This does nothing but signal we are a PPS source... */
1365 +
1366 +               return 0;
1367 +
1368 +       case PPS_GETPARAMS:
1369 +               pr_debug("PPS_GETPARAMS: source %d\n", pps->id);
1370 +
1371 +               /* Sanity checks */
1372 +               if (!uarg)
1373 +                       return -EINVAL;
1374 +
1375 +               /* Return current parameters */
1376 +               err = copy_to_user(uarg, &pps->params,
1377 +                                               sizeof(struct pps_kparams));
1378 +               if (err)
1379 +                       return -EFAULT;
1380 +
1381 +               break;
1382 +
1383 +       case PPS_SETPARAMS:
1384 +               pr_debug("PPS_SETPARAMS: source %d\n", pps->id);
1385 +
1386 +               /* Check the capabilities */
1387 +               if (!capable(CAP_SYS_TIME))
1388 +                       return -EPERM;
1389 +
1390 +               /* Sanity checks */
1391 +               if (!uarg)
1392 +                       return -EINVAL;
1393 +               err = copy_from_user(&params, uarg, sizeof(struct pps_kparams));
1394 +               if (err)
1395 +                       return -EFAULT;
1396 +               if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
1397 +                       pr_debug("capture mode unspecified (%x)\n",
1398 +                                                               params.mode);
1399 +                       return -EINVAL;
1400 +               }
1401 +
1402 +               /* Check for supported capabilities */
1403 +               if ((params.mode & ~pps->info.mode) != 0) {
1404 +                       pr_debug("unsupported capabilities (%x)\n",
1405 +                                                               params.mode);
1406 +                       return -EINVAL;
1407 +               }
1408 +
1409 +               spin_lock_irq(&pps->lock);
1410 +
1411 +               /* Save the new parameters */
1412 +               pps->params = params;
1413 +
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",
1418 +                                                               params.mode);
1419 +                       pps->params.mode |= PPS_TSFMT_TSPEC;
1420 +               }
1421 +               if (pps->info.mode & PPS_CANWAIT)
1422 +                       pps->params.mode |= PPS_CANWAIT;
1423 +               pps->params.api_version = PPS_API_VERS;
1424 +
1425 +               spin_unlock_irq(&pps->lock);
1426 +
1427 +               break;
1428 +
1429 +       case PPS_GETCAP:
1430 +               pr_debug("PPS_GETCAP: source %d\n", pps->id);
1431 +
1432 +               /* Sanity checks */
1433 +               if (!uarg)
1434 +                       return -EINVAL;
1435 +
1436 +               err = put_user(pps->info.mode, iuarg);
1437 +               if (err)
1438 +                       return -EFAULT;
1439 +
1440 +               break;
1441 +
1442 +       case PPS_FETCH:
1443 +               pr_debug("PPS_FETCH: source %d\n", pps->id);
1444 +
1445 +               if (!uarg)
1446 +                       return -EINVAL;
1447 +               err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata));
1448 +               if (err)
1449 +                       return -EFAULT;
1450 +
1451 +               pps->go = 0;
1452 +
1453 +               /* Manage the timeout */
1454 +               if (fdata.timeout.flags & PPS_TIME_INVALID)
1455 +                       err = wait_event_interruptible(pps->queue, pps->go);
1456 +               else {
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);
1461 +
1462 +                       if (ticks != 0) {
1463 +                               err = wait_event_interruptible_timeout(
1464 +                                               pps->queue, pps->go, ticks);
1465 +                               if (err == 0)
1466 +                                       return -ETIMEDOUT;
1467 +                       }
1468 +               }
1469 +
1470 +               /* Check for pending signals */
1471 +               if (err == -ERESTARTSYS) {
1472 +                       pr_debug("pending signal caught\n");
1473 +                       return -EINTR;
1474 +               }
1475 +
1476 +               /* Return the fetched timestamp */
1477 +               spin_lock_irq(&pps->lock);
1478 +
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;
1484 +
1485 +               spin_unlock_irq(&pps->lock);
1486 +
1487 +               err = copy_to_user(uarg, &fdata, sizeof(struct pps_fdata));
1488 +               if (err)
1489 +                       return -EFAULT;
1490 +
1491 +               break;
1492 +
1493 +       default:
1494 +               return -ENOTTY;
1495 +               break;
1496 +       }
1497 +
1498 +       return 0;
1499 +}
1500 +
1501 +static int pps_cdev_open(struct inode *inode, struct file *file)
1502 +{
1503 +       struct pps_device *pps = container_of(inode->i_cdev,
1504 +                                               struct pps_device, cdev);
1505 +
1506 +       /* Lock the PPS source against (possible) deregistration */
1507 +       atomic_inc(&pps->usage);
1508 +
1509 +       file->private_data = pps;
1510 +
1511 +       return 0;
1512 +}
1513 +
1514 +static int pps_cdev_release(struct inode *inode, struct file *file)
1515 +{
1516 +       struct pps_device *pps = file->private_data;
1517 +
1518 +       /* Free the PPS source and wake up (possible) deregistration */
1519 +       atomic_dec(&pps->usage);
1520 +       wake_up_all(&pps->usage_queue);
1521 +
1522 +       return 0;
1523 +}
1524 +
1525 +/*
1526 + * Char device stuff
1527 + */
1528 +
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,
1537 +};
1538 +
1539 +int pps_register_cdev(struct pps_device *pps)
1540 +{
1541 +       int err;
1542 +
1543 +       pps->devno = MKDEV(MAJOR(pps_devt), pps->id);
1544 +       cdev_init(&pps->cdev, &pps_cdev_fops);
1545 +       pps->cdev.owner = pps->info.owner;
1546 +
1547 +       err = cdev_add(&pps->cdev, pps->devno, 1);
1548 +       if (err) {
1549 +               printk(KERN_ERR "pps: %s: failed to add char device %d:%d\n",
1550 +                               pps->info.name, MAJOR(pps_devt), pps->id);
1551 +               return err;
1552 +       }
1553 +       pps->dev = device_create(pps_class, pps->info.dev, pps->devno,
1554 +                                                       "pps%d", pps->id);
1555 +       if (err)
1556 +               goto del_cdev;
1557 +       dev_set_drvdata(pps->dev, pps);
1558 +
1559 +       pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
1560 +                       MAJOR(pps_devt), pps->id);
1561 +
1562 +       return 0;
1563 +
1564 +del_cdev:
1565 +       cdev_del(&pps->cdev);
1566 +
1567 +       return err;
1568 +}
1569 +
1570 +void pps_unregister_cdev(struct pps_device *pps)
1571 +{
1572 +       device_destroy(pps_class, pps->devno);
1573 +       cdev_del(&pps->cdev);
1574 +}
1575 +
1576 +/*
1577 + * Module staff
1578 + */
1579 +
1580 +static void __exit pps_exit(void)
1581 +{
1582 +       class_destroy(pps_class);
1583 +
1584 +       if (pps_devt)
1585 +               unregister_chrdev_region(pps_devt, PPS_MAX_SOURCES);
1586 +
1587 +       pr_info("LinuxPPS API ver. %d removed\n", PPS_API_VERS);
1588 +}
1589 +
1590 +static int __init pps_init(void)
1591 +{
1592 +       int err;
1593 +
1594 +       pps_class = class_create(THIS_MODULE, "pps");
1595 +       if (!pps_class) {
1596 +               printk(KERN_ERR "pps: ailed to allocate class\n");
1597 +               return -ENOMEM;
1598 +       }
1599 +
1600 +       err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps");
1601 +       if (err < 0) {
1602 +               printk(KERN_ERR "pps: failed to allocate char device region\n");
1603 +               goto remove_class;
1604 +       }
1605 +
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);
1609 +
1610 +       return 0;
1611 +
1612 +remove_class:
1613 +       class_destroy(pps_class);
1614 +
1615 +       return err;
1616 +}
1617 +
1618 +subsys_initcall(pps_init);
1619 +module_exit(pps_exit);
1620 +
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 ===================================================================
1626 --- /dev/null
1627 +++ linux-2.6.23.17/drivers/pps/sysfs.c
1628 @@ -0,0 +1,124 @@
1629 +/*
1630 + * sysfs.c -- sysfs support
1631 + *
1632 + *
1633 + * Copyright (C) 2007   Rodolfo Giometti <giometti@linux.it>
1634 + *
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.
1639 + *
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.
1644 + *
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.
1648 + */
1649 +
1650 +
1651 +#include <linux/device.h>
1652 +#include <linux/module.h>
1653 +#include <linux/string.h>
1654 +#include <linux/pps.h>
1655 +
1656 +/*
1657 + * Attribute functions
1658 + */
1659 +
1660 +static ssize_t pps_show_assert(struct device *dev,
1661 +                               struct device_attribute *attr, char *buf)
1662 +{
1663 +       struct pps_device *pps = dev_get_drvdata(dev);
1664 +
1665 +       return sprintf(buf, "%lld.%09d#%d\n",
1666 +                       pps->assert_tu.sec, pps->assert_tu.nsec,
1667 +                       pps->assert_sequence);
1668 +}
1669 +DEVICE_ATTR(assert, S_IRUGO, pps_show_assert, NULL);
1670 +
1671 +static ssize_t pps_show_clear(struct device *dev,
1672 +                               struct device_attribute *attr, char *buf)
1673 +{
1674 +       struct pps_device *pps = dev_get_drvdata(dev);
1675 +
1676 +       return sprintf(buf, "%lld.%09d#%d\n",
1677 +                       pps->clear_tu.sec, pps->clear_tu.nsec,
1678 +                       pps->clear_sequence);
1679 +}
1680 +DEVICE_ATTR(clear, S_IRUGO, pps_show_clear, NULL);
1681 +
1682 +static ssize_t pps_show_mode(struct device *dev,
1683 +                               struct device_attribute *attr, char *buf)
1684 +{
1685 +       struct pps_device *pps = dev_get_drvdata(dev);
1686 +
1687 +       return sprintf(buf, "%4x\n", pps->info.mode);
1688 +}
1689 +DEVICE_ATTR(mode, S_IRUGO, pps_show_mode, NULL);
1690 +
1691 +static ssize_t pps_show_echo(struct device *dev,
1692 +                               struct device_attribute *attr, char *buf)
1693 +{
1694 +       struct pps_device *pps = dev_get_drvdata(dev);
1695 +
1696 +       return sprintf(buf, "%d\n", !!pps->info.echo);
1697 +}
1698 +DEVICE_ATTR(echo, S_IRUGO, pps_show_echo, NULL);
1699 +
1700 +static ssize_t pps_show_name(struct device *dev,
1701 +                               struct device_attribute *attr, char *buf)
1702 +{
1703 +       struct pps_device *pps = dev_get_drvdata(dev);
1704 +
1705 +       return sprintf(buf, "%s\n", pps->info.name);
1706 +}
1707 +DEVICE_ATTR(name, S_IRUGO, pps_show_name, NULL);
1708 +
1709 +static ssize_t pps_show_path(struct device *dev,
1710 +                               struct device_attribute *attr, char *buf)
1711 +{
1712 +       struct pps_device *pps = dev_get_drvdata(dev);
1713 +
1714 +       return sprintf(buf, "%s\n", pps->info.path);
1715 +}
1716 +DEVICE_ATTR(path, S_IRUGO, pps_show_path, NULL);
1717 +
1718 +/*
1719 + * Public functions
1720 + */
1721 +
1722 +void pps_sysfs_remove_source_entry(struct pps_device *pps)
1723 +{
1724 +       /* Delete info files */
1725 +       if (pps->info.mode & PPS_CAPTUREASSERT)
1726 +               device_remove_file(pps->dev, &dev_attr_assert);
1727 +
1728 +       if (pps->info.mode & PPS_CAPTURECLEAR)
1729 +               device_remove_file(pps->dev, &dev_attr_clear);
1730 +
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);
1735 +}
1736 +
1737 +int pps_sysfs_create_source_entry(struct pps_device *pps)
1738 +{
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);
1742 +
1743 +       if (pps->info.mode & PPS_CAPTURECLEAR)
1744 +               device_create_file(pps->dev, &dev_attr_clear);
1745 +
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);
1750 +
1751 +       return 0;
1752 +}
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 */
1763  
1764         serial_out(up, UART_IER, up->ier);
1765  
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
1770 @@ -33,6 +33,7 @@
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>
1775  
1776  #include <asm/irq.h>
1777  #include <asm/uaccess.h>
1778 @@ -633,6 +634,54 @@ static int uart_get_info(struct uart_sta
1779         return 0;
1780  }
1781  
1782 +#ifdef CONFIG_PPS_CLIENT_UART
1783 +
1784 +static int
1785 +uart_register_pps_port(struct uart_state *state, struct uart_port *port)
1786 +{
1787 +       struct tty_driver *drv = port->info->tty->driver;
1788 +       int ret;
1789 +
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);
1796 +
1797 +       state->pps_info.mode = PPS_CAPTUREBOTH | \
1798 +                       PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
1799 +                       PPS_CANWAIT | PPS_TSFMT_TSPEC;
1800 +
1801 +       ret = pps_register_source(&state->pps_info, PPS_CAPTUREBOTH | \
1802 +                               PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
1803 +       if (ret < 0) {
1804 +               dev_err(port->dev, "cannot register PPS source \"%s\"\n",
1805 +                                               state->pps_info.path);
1806 +               return ret;
1807 +       }
1808 +       port->pps_source = ret;
1809 +       dev_dbg(port->dev, "PPS source #%d \"%s\" added\n",
1810 +               port->pps_source, state->pps_info.path);
1811 +
1812 +       return 0;
1813 +}
1814 +
1815 +static void
1816 +uart_unregister_pps_port(struct uart_state *state, struct uart_port *port)
1817 +{
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);
1821 +}
1822 +
1823 +#else
1824 +
1825 +#define uart_register_pps_port(state, port)    do { } while (0)
1826 +#define uart_unregister_pps_port(state, port)  do { } while (0)
1827 +
1828 +#endif /* CONFIG_PPS_CLIENT_UART */
1829 +
1830  static int uart_set_info(struct uart_state *state,
1831                          struct serial_struct __user *newinfo)
1832  {
1833 @@ -807,11 +856,19 @@ static int uart_set_info(struct uart_sta
1834                         (port->flags & UPF_LOW_LATENCY) ? 1 : 0;
1835  
1836   check_and_exit:
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);
1841 +               else
1842 +                       uart_unregister_pps_port(state, port);
1843 +       }
1844 +
1845         retval = 0;
1846         if (port->type == PORT_UNKNOWN)
1847                 goto exit;
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) {
1852                         /*
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);
1856         }
1857  
1858 +       /*
1859 +        * Add the PPS support for the current port.
1860 +        */
1861 +       if (port->flags & UPF_HARDPPS_CD)
1862 +               uart_register_pps_port(state, port);
1863 +
1864         if (port->type != PORT_UNKNOWN) {
1865                 unsigned long flags;
1866  
1867 @@ -2359,6 +2422,12 @@ int uart_remove_one_port(struct uart_dri
1868         mutex_unlock(&state->mutex);
1869  
1870         /*
1871 +        * Remove PPS support from the current port.
1872 +        */
1873 +       if (port->flags & UPF_HARDPPS_CD)
1874 +               uart_unregister_pps_port(state, port);
1875 +
1876 +       /*
1877          * Remove the devices from the tty layer
1878          */
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
1885  unifdef-y += poll.h
1886  unifdef-y += ppp_defs.h
1887  unifdef-y += ppp-comp.h
1888 +unifdef-y += pps.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 {
1905  
1906         struct list_head full_list;
1907         struct parport *slaves[3];
1908 +
1909 +#ifdef CONFIG_PPS_CLIENT_LP
1910 +       struct pps_source_info pps_info;
1911 +       int pps_source;         /* PPS source ID */
1912 +#endif
1913  };
1914  
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)
1919  {
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);
1924 +#endif
1925 +
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 ===================================================================
1931 --- /dev/null
1932 +++ linux-2.6.23.17/include/linux/pps.h
1933 @@ -0,0 +1,196 @@
1934 +/*
1935 + * pps.h -- PPS API kernel header.
1936 + *
1937 + *
1938 + * Copyright (C) 2005-2007   Rodolfo Giometti <giometti@linux.it>
1939 + *
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.
1944 + *
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.
1949 + *
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.
1953 + */
1954 +
1955 +
1956 +#ifndef _PPS_H_
1957 +#define _PPS_H_
1958 +
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.  */
1962 +
1963 +/*
1964 + * 3.2 New data structures
1965 + */
1966 +
1967 +#ifndef __KERNEL__
1968 +#include <linux/types.h>
1969 +#include <sys/time.h>
1970 +#include <sys/ioctl.h>
1971 +#else
1972 +#include <linux/time.h>
1973 +#endif
1974 +
1975 +#define PPS_API_VERS           1
1976 +#define PPS_MAX_NAME_LEN       32
1977 +
1978 +/* 32-bit vs. 64-bit compatibility.
1979 + *
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
1984 + * alignment.
1985 + *
1986 + * The simple fix is probably to add an explicit padding.
1987 + *                                                     [David Woodhouse]
1988 + */
1989 +struct pps_ktime {
1990 +       __u64 sec;
1991 +       __u32 nsec;
1992 +       __u32 flags;
1993 +};
1994 +#define PPS_TIME_INVALID       (1<<0)  /* used to specify timeout==NULL */
1995 +
1996 +struct pps_kinfo {
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 */
2002 +};
2003 +
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 */
2009 +};
2010 +
2011 +/*
2012 + * 3.3 Mode bit definitions
2013 + */
2014 +
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 */
2019 +
2020 +#define PPS_OFFSETASSERT       0x10    /* apply compensation for assert ev. */
2021 +#define PPS_OFFSETCLEAR                0x20    /* apply compensation for clear ev. */
2022 +
2023 +#define PPS_CANWAIT            0x100   /* can we wait for an event? */
2024 +#define PPS_CANPOLL            0x200   /* bit reserved for future use */
2025 +
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 */
2029 +
2030 +/* Timestamp formats */
2031 +#define PPS_TSFMT_TSPEC                0x1000  /* select timespec format */
2032 +#define PPS_TSFMT_NTPFP                0x2000  /* select NTP format */
2033 +
2034 +/*
2035 + * 3.4.4 New functions: disciplining the kernel timebase
2036 + */
2037 +
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 */
2044 +/*
2045 + * Here begins the implementation-specific part!
2046 + */
2047 +
2048 +struct pps_fdata {
2049 +       struct pps_kinfo info;
2050 +       struct pps_ktime timeout;
2051 +};
2052 +
2053 +#include <linux/ioctl.h>
2054 +
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 *)
2060 +
2061 +#ifdef __KERNEL__
2062 +
2063 +#include <linux/cdev.h>
2064 +#include <linux/device.h>
2065 +
2066 +#define PPS_VERSION            "5.0.0-rc2"
2067 +#define PPS_MAX_SOURCES                16              /* should be enought... */
2068 +
2069 +/*
2070 + * Global defines
2071 + */
2072 +
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 */
2078 +
2079 +       void (*echo)(int source, int event, void *data); /* PPS echo function */
2080 +
2081 +       struct module *owner;
2082 +       struct device *dev;
2083 +};
2084 +
2085 +/* The main struct */
2086 +struct pps_device {
2087 +       struct pps_source_info info;            /* PSS source info */
2088 +
2089 +       struct pps_kparams params;              /* PPS's current params */
2090 +
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 */
2096 +
2097 +       int go;                                 /* PPS event is arrived? */
2098 +       wait_queue_head_t queue;                /* PPS event queue */
2099 +
2100 +       unsigned int id;                        /* PPS source unique ID */
2101 +       struct cdev cdev;
2102 +       struct device *dev;
2103 +       int devno;
2104 +       struct fasync_struct *async_queue;      /* fasync method */
2105 +       spinlock_t lock;
2106 +
2107 +       atomic_t usage;                         /* usage count */
2108 +       wait_queue_head_t usage_queue;
2109 +
2110 +       struct class_device class_dev;
2111 +};
2112 +
2113 +/*
2114 + * Exported functions
2115 + */
2116 +
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);
2123 +
2124 +extern int pps_sysfs_create_source_entry(struct pps_device *pps);
2125 +extern void pps_sysfs_remove_source_entry(struct pps_device *pps);
2126 +
2127 +#endif /* __KERNEL__ */
2128 +
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
2134 @@ -157,6 +157,7 @@
2135  #include <linux/tty.h>
2136  #include <linux/mutex.h>
2137  #include <linux/sysrq.h>
2138 +#include <linux/pps.h>
2139  
2140  struct uart_port;
2141  struct uart_info;
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 */
2148 +#endif
2149  
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))
2154  
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\
2158 +                                                       |UPF_HARDPPS_CD))
2159  
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;
2165  
2166 +#ifdef CONFIG_PPS_CLIENT_UART
2167 +       struct pps_source_info  pps_info;
2168 +#endif
2169 +
2170         struct mutex            mutex;
2171  };
2172  
2173 @@ -476,13 +485,22 @@ uart_handle_dcd_change(struct uart_port 
2174  {
2175         struct uart_info *info = port->info;
2176  
2177 -       port->icount.dcd++;
2178 -
2179 -#ifdef CONFIG_HARD_PPS
2180 -       if ((port->flags & UPF_HARDPPS_CD) && status)
2181 -               hardpps();
2182 +#ifdef CONFIG_PPS_CLIENT_UART
2183 +       if (port->flags & UPF_HARDPPS_CD) {
2184 +               if (status) {
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);
2188 +               } else {
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);
2192 +               }
2193 +       }
2194  #endif
2195  
2196 +       port->icount.dcd++;
2197 +
2198         if (info->flags & UIF_CHECK_CD) {
2199                 if (status)
2200                         wake_up_interruptible(&info->open_wait);