Blame view
drivers/pps/kapi.c
6.03 KB
eae9d2ba0 LinuxPPS: core su... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/* * kernel API * * * Copyright (C) 2005-2009 Rodolfo Giometti <giometti@linux.it> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
7f7cce741 pps: convert prin... |
21 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
eae9d2ba0 LinuxPPS: core su... |
22 23 24 25 26 27 |
#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/time.h> |
717c03366 pps: add kernel c... |
28 |
#include <linux/timex.h> |
eae9d2ba0 LinuxPPS: core su... |
29 |
#include <linux/spinlock.h> |
eae9d2ba0 LinuxPPS: core su... |
30 31 |
#include <linux/fs.h> #include <linux/pps_kernel.h> |
5a0e3ad6a include cleanup: ... |
32 |
#include <linux/slab.h> |
eae9d2ba0 LinuxPPS: core su... |
33 |
|
717c03366 pps: add kernel c... |
34 |
#include "kc.h" |
eae9d2ba0 LinuxPPS: core su... |
35 |
/* |
eae9d2ba0 LinuxPPS: core su... |
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
* Local functions */ static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset) { ts->nsec += offset->nsec; while (ts->nsec >= NSEC_PER_SEC) { ts->nsec -= NSEC_PER_SEC; ts->sec++; } while (ts->nsec < 0) { ts->nsec += NSEC_PER_SEC; ts->sec--; } ts->sec += offset->sec; } |
437c53418 pps: default echo... |
52 53 54 55 56 57 58 59 |
static void pps_echo_client_default(struct pps_device *pps, int event, void *data) { dev_info(pps->dev, "echo %s %s ", event & PPS_CAPTUREASSERT ? "assert" : "", event & PPS_CAPTURECLEAR ? "clear" : ""); } |
eae9d2ba0 LinuxPPS: core su... |
60 61 62 |
/* * Exported functions */ |
eae9d2ba0 LinuxPPS: core su... |
63 64 65 66 67 68 69 70 |
/* pps_register_source - add a PPS source in the system * @info: the PPS info struct * @default_params: the default PPS parameters of the new source * * This function is used to add a new PPS source in the system. The new * source is described by info's fields and it will have, as default PPS * parameters, the ones specified into default_params. * |
5e196d34a pps: access pps d... |
71 |
* The function returns, in case of success, the PPS device. Otherwise NULL. |
eae9d2ba0 LinuxPPS: core su... |
72 |
*/ |
5e196d34a pps: access pps d... |
73 74 |
struct pps_device *pps_register_source(struct pps_source_info *info, int default_params) |
eae9d2ba0 LinuxPPS: core su... |
75 76 |
{ struct pps_device *pps; |
eae9d2ba0 LinuxPPS: core su... |
77 78 79 80 |
int err; /* Sanity checks */ if ((info->mode & default_params) != default_params) { |
7f7cce741 pps: convert prin... |
81 82 |
pr_err("%s: unsupported default parameters ", |
eae9d2ba0 LinuxPPS: core su... |
83 84 85 86 |
info->name); err = -EINVAL; goto pps_register_source_exit; } |
eae9d2ba0 LinuxPPS: core su... |
87 |
if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) { |
7f7cce741 pps: convert prin... |
88 89 |
pr_err("%s: unspecified time format ", |
eae9d2ba0 LinuxPPS: core su... |
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
info->name); err = -EINVAL; goto pps_register_source_exit; } /* Allocate memory for the new PPS source struct */ pps = kzalloc(sizeof(struct pps_device), GFP_KERNEL); if (pps == NULL) { err = -ENOMEM; goto pps_register_source_exit; } /* These initializations must be done before calling idr_get_new() * in order to avoid reces into pps_event(). */ pps->params.api_version = PPS_API_VERS; pps->params.mode = default_params; pps->info = *info; |
437c53418 pps: default echo... |
108 109 110 111 |
/* check for default echo function */ if ((pps->info.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) && pps->info.echo == NULL) pps->info.echo = pps_echo_client_default; |
eae9d2ba0 LinuxPPS: core su... |
112 113 |
init_waitqueue_head(&pps->queue); spin_lock_init(&pps->lock); |
eae9d2ba0 LinuxPPS: core su... |
114 |
|
eae9d2ba0 LinuxPPS: core su... |
115 116 117 |
/* Create the char device */ err = pps_register_cdev(pps); if (err < 0) { |
7f7cce741 pps: convert prin... |
118 119 |
pr_err("%s: unable to create char device ", |
eae9d2ba0 LinuxPPS: core su... |
120 |
info->name); |
083e58666 pps: move idr stu... |
121 |
goto kfree_pps; |
eae9d2ba0 LinuxPPS: core su... |
122 |
} |
7f7cce741 pps: convert prin... |
123 124 |
dev_info(pps->dev, "new PPS source %s ", info->name); |
eae9d2ba0 LinuxPPS: core su... |
125 |
|
5e196d34a pps: access pps d... |
126 |
return pps; |
eae9d2ba0 LinuxPPS: core su... |
127 |
|
eae9d2ba0 LinuxPPS: core su... |
128 129 130 131 |
kfree_pps: kfree(pps); pps_register_source_exit: |
7f7cce741 pps: convert prin... |
132 133 |
pr_err("%s: unable to register source ", info->name); |
eae9d2ba0 LinuxPPS: core su... |
134 |
|
5e196d34a pps: access pps d... |
135 |
return NULL; |
eae9d2ba0 LinuxPPS: core su... |
136 137 138 139 |
} EXPORT_SYMBOL(pps_register_source); /* pps_unregister_source - remove a PPS source from the system |
5e196d34a pps: access pps d... |
140 |
* @pps: the PPS source |
eae9d2ba0 LinuxPPS: core su... |
141 142 143 144 |
* * This function is used to remove a previously registered PPS source from * the system. */ |
5e196d34a pps: access pps d... |
145 |
void pps_unregister_source(struct pps_device *pps) |
eae9d2ba0 LinuxPPS: core su... |
146 |
{ |
717c03366 pps: add kernel c... |
147 |
pps_kc_remove(pps); |
5e196d34a pps: access pps d... |
148 |
pps_unregister_cdev(pps); |
eae9d2ba0 LinuxPPS: core su... |
149 |
|
083e58666 pps: move idr stu... |
150 151 |
/* don't have to kfree(pps) here because it will be done on * device destruction */ |
eae9d2ba0 LinuxPPS: core su... |
152 153 154 155 |
} EXPORT_SYMBOL(pps_unregister_source); /* pps_event - register a PPS event into the system |
5e196d34a pps: access pps d... |
156 |
* @pps: the PPS device |
eae9d2ba0 LinuxPPS: core su... |
157 158 159 160 161 162 163 |
* @ts: the event timestamp * @event: the event type * @data: userdef pointer * * This function is used by each PPS client in order to register a new * PPS event into the system (it's usually called inside an IRQ handler). * |
5e196d34a pps: access pps d... |
164 |
* If an echo function is associated with the PPS device it will be called |
eae9d2ba0 LinuxPPS: core su... |
165 |
* as: |
5e196d34a pps: access pps d... |
166 |
* pps->info.echo(pps, event, data); |
eae9d2ba0 LinuxPPS: core su... |
167 |
*/ |
5e196d34a pps: access pps d... |
168 169 |
void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event, void *data) |
eae9d2ba0 LinuxPPS: core su... |
170 |
{ |
eae9d2ba0 LinuxPPS: core su... |
171 |
unsigned long flags; |
276b282e9 pps: events repor... |
172 |
int captured = 0; |
99b0d365e pps: initialize t... |
173 |
struct pps_ktime ts_real = { .sec = 0, .nsec = 0, .flags = 0 }; |
eae9d2ba0 LinuxPPS: core su... |
174 |
|
29f347c9f pps: use BUG_ON f... |
175 176 |
/* check event type */ BUG_ON((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0); |
eae9d2ba0 LinuxPPS: core su... |
177 |
|
5e196d34a pps: access pps d... |
178 179 180 |
dev_dbg(pps->dev, "PPS event at %ld.%09ld ", ts->ts_real.tv_sec, ts->ts_real.tv_nsec); |
6f4229b51 pps: unify timest... |
181 182 |
timespec_to_pps_ktime(&ts_real, ts->ts_real); |
eae9d2ba0 LinuxPPS: core su... |
183 184 185 186 187 |
spin_lock_irqsave(&pps->lock, flags); /* Must call the echo function? */ if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR))) |
5e196d34a pps: access pps d... |
188 |
pps->info.echo(pps, event, data); |
eae9d2ba0 LinuxPPS: core su... |
189 190 191 |
/* Check the event */ pps->current_mode = pps->params.mode; |
818b9eefe pps: simplify con... |
192 |
if (event & pps->params.mode & PPS_CAPTUREASSERT) { |
eae9d2ba0 LinuxPPS: core su... |
193 194 |
/* We have to add an offset? */ if (pps->params.mode & PPS_OFFSETASSERT) |
6f4229b51 pps: unify timest... |
195 196 |
pps_add_offset(&ts_real, &pps->params.assert_off_tu); |
eae9d2ba0 LinuxPPS: core su... |
197 198 |
/* Save the time stamp */ |
6f4229b51 pps: unify timest... |
199 |
pps->assert_tu = ts_real; |
eae9d2ba0 LinuxPPS: core su... |
200 |
pps->assert_sequence++; |
5e196d34a pps: access pps d... |
201 202 203 |
dev_dbg(pps->dev, "capture assert seq #%u ", pps->assert_sequence); |
276b282e9 pps: events repor... |
204 205 |
captured = ~0; |
eae9d2ba0 LinuxPPS: core su... |
206 |
} |
818b9eefe pps: simplify con... |
207 |
if (event & pps->params.mode & PPS_CAPTURECLEAR) { |
eae9d2ba0 LinuxPPS: core su... |
208 209 |
/* We have to add an offset? */ if (pps->params.mode & PPS_OFFSETCLEAR) |
6f4229b51 pps: unify timest... |
210 211 |
pps_add_offset(&ts_real, &pps->params.clear_off_tu); |
eae9d2ba0 LinuxPPS: core su... |
212 213 |
/* Save the time stamp */ |
6f4229b51 pps: unify timest... |
214 |
pps->clear_tu = ts_real; |
eae9d2ba0 LinuxPPS: core su... |
215 |
pps->clear_sequence++; |
5e196d34a pps: access pps d... |
216 217 218 |
dev_dbg(pps->dev, "capture clear seq #%u ", pps->clear_sequence); |
276b282e9 pps: events repor... |
219 220 |
captured = ~0; |
eae9d2ba0 LinuxPPS: core su... |
221 |
} |
717c03366 pps: add kernel c... |
222 |
pps_kc_event(pps, ts, event); |
7a21a3cc0 pps: trivial fixes |
223 |
/* Wake up if captured something */ |
276b282e9 pps: events repor... |
224 |
if (captured) { |
3003d55b5 pps: fix race in ... |
225 226 |
pps->last_ev++; wake_up_interruptible_all(&pps->queue); |
eae9d2ba0 LinuxPPS: core su... |
227 |
|
276b282e9 pps: events repor... |
228 229 |
kill_fasync(&pps->async_queue, SIGIO, POLL_IN); } |
eae9d2ba0 LinuxPPS: core su... |
230 231 |
spin_unlock_irqrestore(&pps->lock, flags); |
eae9d2ba0 LinuxPPS: core su... |
232 233 |
} EXPORT_SYMBOL(pps_event); |