diff options
author | Alexander Gordeev <lasaine@lvk.cs.msu.su> | 2011-01-12 20:00:51 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 11:03:19 -0500 |
commit | 5e196d34a776420278e4117b4742cd9d3f2350ed (patch) | |
tree | 86187af6a600876506261758a00c7c42e6037283 /drivers/pps/kapi.c | |
parent | 6f4229b51106cbc859e9d8209b22c8a2ec749e64 (diff) |
pps: access pps device by direct pointer
Using device index as a pointer needs some unnecessary work to be done
every time the pointer is needed (in irq handler for example). Using a
direct pointer is much more easy (and safe as well).
Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
Acked-by: Rodolfo Giometti <giometti@linux.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/pps/kapi.c')
-rw-r--r-- | drivers/pps/kapi.c | 124 |
1 files changed, 28 insertions, 96 deletions
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index b431d83b824a..98d4012ca595 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c | |||
@@ -32,11 +32,11 @@ | |||
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * Global variables | 35 | * Local variables |
36 | */ | 36 | */ |
37 | 37 | ||
38 | DEFINE_SPINLOCK(pps_idr_lock); | 38 | static DEFINE_SPINLOCK(pps_idr_lock); |
39 | DEFINE_IDR(pps_idr); | 39 | static DEFINE_IDR(pps_idr); |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * Local functions | 42 | * Local functions |
@@ -60,60 +60,6 @@ static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset) | |||
60 | * Exported functions | 60 | * Exported functions |
61 | */ | 61 | */ |
62 | 62 | ||
63 | /* pps_get_source - find a PPS source | ||
64 | * @source: the PPS source ID. | ||
65 | * | ||
66 | * This function is used to find an already registered PPS source into the | ||
67 | * system. | ||
68 | * | ||
69 | * The function returns NULL if found nothing, otherwise it returns a pointer | ||
70 | * to the PPS source data struct (the refcounter is incremented by 1). | ||
71 | */ | ||
72 | |||
73 | struct pps_device *pps_get_source(int source) | ||
74 | { | ||
75 | struct pps_device *pps; | ||
76 | unsigned long flags; | ||
77 | |||
78 | spin_lock_irqsave(&pps_idr_lock, flags); | ||
79 | |||
80 | pps = idr_find(&pps_idr, source); | ||
81 | if (pps != NULL) | ||
82 | atomic_inc(&pps->usage); | ||
83 | |||
84 | spin_unlock_irqrestore(&pps_idr_lock, flags); | ||
85 | |||
86 | return pps; | ||
87 | } | ||
88 | |||
89 | /* pps_put_source - free the PPS source data | ||
90 | * @pps: a pointer to the PPS source. | ||
91 | * | ||
92 | * This function is used to free a PPS data struct if its refcount is 0. | ||
93 | */ | ||
94 | |||
95 | void pps_put_source(struct pps_device *pps) | ||
96 | { | ||
97 | unsigned long flags; | ||
98 | |||
99 | spin_lock_irqsave(&pps_idr_lock, flags); | ||
100 | BUG_ON(atomic_read(&pps->usage) == 0); | ||
101 | |||
102 | if (!atomic_dec_and_test(&pps->usage)) { | ||
103 | pps = NULL; | ||
104 | goto exit; | ||
105 | } | ||
106 | |||
107 | /* No more reference to the PPS source. We can safely remove the | ||
108 | * PPS data struct. | ||
109 | */ | ||
110 | idr_remove(&pps_idr, pps->id); | ||
111 | |||
112 | exit: | ||
113 | spin_unlock_irqrestore(&pps_idr_lock, flags); | ||
114 | kfree(pps); | ||
115 | } | ||
116 | |||
117 | /* pps_register_source - add a PPS source in the system | 63 | /* pps_register_source - add a PPS source in the system |
118 | * @info: the PPS info struct | 64 | * @info: the PPS info struct |
119 | * @default_params: the default PPS parameters of the new source | 65 | * @default_params: the default PPS parameters of the new source |
@@ -122,10 +68,11 @@ exit: | |||
122 | * source is described by info's fields and it will have, as default PPS | 68 | * source is described by info's fields and it will have, as default PPS |
123 | * parameters, the ones specified into default_params. | 69 | * parameters, the ones specified into default_params. |
124 | * | 70 | * |
125 | * The function returns, in case of success, the PPS source ID. | 71 | * The function returns, in case of success, the PPS device. Otherwise NULL. |
126 | */ | 72 | */ |
127 | 73 | ||
128 | int pps_register_source(struct pps_source_info *info, int default_params) | 74 | struct pps_device *pps_register_source(struct pps_source_info *info, |
75 | int default_params) | ||
129 | { | 76 | { |
130 | struct pps_device *pps; | 77 | struct pps_device *pps; |
131 | int id; | 78 | int id; |
@@ -168,7 +115,6 @@ int pps_register_source(struct pps_source_info *info, int default_params) | |||
168 | 115 | ||
169 | init_waitqueue_head(&pps->queue); | 116 | init_waitqueue_head(&pps->queue); |
170 | spin_lock_init(&pps->lock); | 117 | spin_lock_init(&pps->lock); |
171 | atomic_set(&pps->usage, 1); | ||
172 | 118 | ||
173 | /* Get new ID for the new PPS source */ | 119 | /* Get new ID for the new PPS source */ |
174 | if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) { | 120 | if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) { |
@@ -211,7 +157,7 @@ int pps_register_source(struct pps_source_info *info, int default_params) | |||
211 | 157 | ||
212 | pr_info("new PPS source %s at ID %d\n", info->name, id); | 158 | pr_info("new PPS source %s at ID %d\n", info->name, id); |
213 | 159 | ||
214 | return id; | 160 | return pps; |
215 | 161 | ||
216 | free_idr: | 162 | free_idr: |
217 | spin_lock_irq(&pps_idr_lock); | 163 | spin_lock_irq(&pps_idr_lock); |
@@ -224,38 +170,33 @@ kfree_pps: | |||
224 | pps_register_source_exit: | 170 | pps_register_source_exit: |
225 | printk(KERN_ERR "pps: %s: unable to register source\n", info->name); | 171 | printk(KERN_ERR "pps: %s: unable to register source\n", info->name); |
226 | 172 | ||
227 | return err; | 173 | return NULL; |
228 | } | 174 | } |
229 | EXPORT_SYMBOL(pps_register_source); | 175 | EXPORT_SYMBOL(pps_register_source); |
230 | 176 | ||
231 | /* pps_unregister_source - remove a PPS source from the system | 177 | /* pps_unregister_source - remove a PPS source from the system |
232 | * @source: the PPS source ID | 178 | * @pps: the PPS source |
233 | * | 179 | * |
234 | * This function is used to remove a previously registered PPS source from | 180 | * This function is used to remove a previously registered PPS source from |
235 | * the system. | 181 | * the system. |
236 | */ | 182 | */ |
237 | 183 | ||
238 | void pps_unregister_source(int source) | 184 | void pps_unregister_source(struct pps_device *pps) |
239 | { | 185 | { |
240 | struct pps_device *pps; | 186 | unsigned int id = pps->id; |
241 | 187 | ||
242 | spin_lock_irq(&pps_idr_lock); | 188 | pps_unregister_cdev(pps); |
243 | pps = idr_find(&pps_idr, source); | ||
244 | 189 | ||
245 | if (!pps) { | 190 | spin_lock_irq(&pps_idr_lock); |
246 | BUG(); | 191 | idr_remove(&pps_idr, pps->id); |
247 | spin_unlock_irq(&pps_idr_lock); | ||
248 | return; | ||
249 | } | ||
250 | spin_unlock_irq(&pps_idr_lock); | 192 | spin_unlock_irq(&pps_idr_lock); |
251 | 193 | ||
252 | pps_unregister_cdev(pps); | 194 | kfree(pps); |
253 | pps_put_source(pps); | ||
254 | } | 195 | } |
255 | EXPORT_SYMBOL(pps_unregister_source); | 196 | EXPORT_SYMBOL(pps_unregister_source); |
256 | 197 | ||
257 | /* pps_event - register a PPS event into the system | 198 | /* pps_event - register a PPS event into the system |
258 | * @source: the PPS source ID | 199 | * @pps: the PPS device |
259 | * @ts: the event timestamp | 200 | * @ts: the event timestamp |
260 | * @event: the event type | 201 | * @event: the event type |
261 | * @data: userdef pointer | 202 | * @data: userdef pointer |
@@ -263,30 +204,24 @@ EXPORT_SYMBOL(pps_unregister_source); | |||
263 | * This function is used by each PPS client in order to register a new | 204 | * This function is used by each PPS client in order to register a new |
264 | * PPS event into the system (it's usually called inside an IRQ handler). | 205 | * PPS event into the system (it's usually called inside an IRQ handler). |
265 | * | 206 | * |
266 | * If an echo function is associated with the PPS source it will be called | 207 | * If an echo function is associated with the PPS device it will be called |
267 | * as: | 208 | * as: |
268 | * pps->info.echo(source, event, data); | 209 | * pps->info.echo(pps, event, data); |
269 | */ | 210 | */ |
270 | 211 | void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event, | |
271 | void pps_event(int source, struct pps_event_time *ts, int event, void *data) | 212 | void *data) |
272 | { | 213 | { |
273 | struct pps_device *pps; | ||
274 | unsigned long flags; | 214 | unsigned long flags; |
275 | int captured = 0; | 215 | int captured = 0; |
276 | struct pps_ktime ts_real; | 216 | struct pps_ktime ts_real; |
277 | 217 | ||
278 | if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) { | 218 | if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) { |
279 | printk(KERN_ERR "pps: unknown event (%x) for source %d\n", | 219 | dev_err(pps->dev, "unknown event (%x)\n", event); |
280 | event, source); | ||
281 | return; | 220 | return; |
282 | } | 221 | } |
283 | 222 | ||
284 | pps = pps_get_source(source); | 223 | dev_dbg(pps->dev, "PPS event at %ld.%09ld\n", |
285 | if (!pps) | 224 | ts->ts_real.tv_sec, ts->ts_real.tv_nsec); |
286 | return; | ||
287 | |||
288 | pr_debug("PPS event on source %d at %ld.%09ld\n", | ||
289 | pps->id, ts->ts_real.tv_sec, ts->ts_real.tv_nsec); | ||
290 | 225 | ||
291 | timespec_to_pps_ktime(&ts_real, ts->ts_real); | 226 | timespec_to_pps_ktime(&ts_real, ts->ts_real); |
292 | 227 | ||
@@ -294,7 +229,7 @@ void pps_event(int source, struct pps_event_time *ts, int event, void *data) | |||
294 | 229 | ||
295 | /* Must call the echo function? */ | 230 | /* Must call the echo function? */ |
296 | if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR))) | 231 | if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR))) |
297 | pps->info.echo(source, event, data); | 232 | pps->info.echo(pps, event, data); |
298 | 233 | ||
299 | /* Check the event */ | 234 | /* Check the event */ |
300 | pps->current_mode = pps->params.mode; | 235 | pps->current_mode = pps->params.mode; |
@@ -308,8 +243,8 @@ void pps_event(int source, struct pps_event_time *ts, int event, void *data) | |||
308 | /* Save the time stamp */ | 243 | /* Save the time stamp */ |
309 | pps->assert_tu = ts_real; | 244 | pps->assert_tu = ts_real; |
310 | pps->assert_sequence++; | 245 | pps->assert_sequence++; |
311 | pr_debug("capture assert seq #%u for source %d\n", | 246 | dev_dbg(pps->dev, "capture assert seq #%u\n", |
312 | pps->assert_sequence, source); | 247 | pps->assert_sequence); |
313 | 248 | ||
314 | captured = ~0; | 249 | captured = ~0; |
315 | } | 250 | } |
@@ -323,8 +258,8 @@ void pps_event(int source, struct pps_event_time *ts, int event, void *data) | |||
323 | /* Save the time stamp */ | 258 | /* Save the time stamp */ |
324 | pps->clear_tu = ts_real; | 259 | pps->clear_tu = ts_real; |
325 | pps->clear_sequence++; | 260 | pps->clear_sequence++; |
326 | pr_debug("capture clear seq #%u for source %d\n", | 261 | dev_dbg(pps->dev, "capture clear seq #%u\n", |
327 | pps->clear_sequence, source); | 262 | pps->clear_sequence); |
328 | 263 | ||
329 | captured = ~0; | 264 | captured = ~0; |
330 | } | 265 | } |
@@ -338,8 +273,5 @@ void pps_event(int source, struct pps_event_time *ts, int event, void *data) | |||
338 | } | 273 | } |
339 | 274 | ||
340 | spin_unlock_irqrestore(&pps->lock, flags); | 275 | spin_unlock_irqrestore(&pps->lock, flags); |
341 | |||
342 | /* Now we can release the PPS source for (possible) deregistration */ | ||
343 | pps_put_source(pps); | ||
344 | } | 276 | } |
345 | EXPORT_SYMBOL(pps_event); | 277 | EXPORT_SYMBOL(pps_event); |