refresh generic 2.6.23 patches
[openwrt/staging/wigyori.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);