diff options
-rw-r--r-- | drivers/pps/pps.c | 33 | ||||
-rw-r--r-- | include/linux/pps_kernel.h | 17 |
2 files changed, 47 insertions, 3 deletions
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 2420d5af0583..a70e384262e5 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c | |||
@@ -352,11 +352,44 @@ free_idr: | |||
352 | 352 | ||
353 | void pps_unregister_cdev(struct pps_device *pps) | 353 | void pps_unregister_cdev(struct pps_device *pps) |
354 | { | 354 | { |
355 | pps->lookup_cookie = NULL; | ||
355 | device_destroy(pps_class, pps->dev->devt); | 356 | device_destroy(pps_class, pps->dev->devt); |
356 | cdev_del(&pps->cdev); | 357 | cdev_del(&pps->cdev); |
357 | } | 358 | } |
358 | 359 | ||
359 | /* | 360 | /* |
361 | * Look up a pps device by magic cookie. | ||
362 | * The cookie is usually a pointer to some enclosing device, but this | ||
363 | * code doesn't care; you should never be dereferencing it. | ||
364 | * | ||
365 | * This is a bit of a kludge that is currently used only by the PPS | ||
366 | * serial line discipline. It may need to be tweaked when a second user | ||
367 | * is found. | ||
368 | * | ||
369 | * There is no function interface for setting the lookup_cookie field. | ||
370 | * It's initialized to NULL when the pps device is created, and if a | ||
371 | * client wants to use it, just fill it in afterward. | ||
372 | * | ||
373 | * The cookie is automatically set to NULL in pps_unregister_source() | ||
374 | * so that it will not be used again, even if the pps device cannot | ||
375 | * be removed from the idr due to pending references holding the minor | ||
376 | * number in use. | ||
377 | */ | ||
378 | struct pps_device *pps_lookup_dev(void const *cookie) | ||
379 | { | ||
380 | struct pps_device *pps; | ||
381 | unsigned id; | ||
382 | |||
383 | rcu_read_lock(); | ||
384 | idr_for_each_entry(&pps_idr, pps, id) | ||
385 | if (cookie == pps->lookup_cookie) | ||
386 | break; | ||
387 | rcu_read_unlock(); | ||
388 | return pps; | ||
389 | } | ||
390 | EXPORT_SYMBOL(pps_lookup_dev); | ||
391 | |||
392 | /* | ||
360 | * Module stuff | 393 | * Module stuff |
361 | */ | 394 | */ |
362 | 395 | ||
diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h index 0cc45ae1afd5..7db3eb93a079 100644 --- a/include/linux/pps_kernel.h +++ b/include/linux/pps_kernel.h | |||
@@ -43,7 +43,7 @@ struct pps_source_info { | |||
43 | int event, void *data); /* PPS echo function */ | 43 | int event, void *data); /* PPS echo function */ |
44 | 44 | ||
45 | struct module *owner; | 45 | struct module *owner; |
46 | struct device *dev; | 46 | struct device *dev; /* Parent device for device_create */ |
47 | }; | 47 | }; |
48 | 48 | ||
49 | struct pps_event_time { | 49 | struct pps_event_time { |
@@ -69,6 +69,7 @@ struct pps_device { | |||
69 | wait_queue_head_t queue; /* PPS event queue */ | 69 | wait_queue_head_t queue; /* PPS event queue */ |
70 | 70 | ||
71 | unsigned int id; /* PPS source unique ID */ | 71 | unsigned int id; /* PPS source unique ID */ |
72 | void const *lookup_cookie; /* pps_lookup_dev only */ | ||
72 | struct cdev cdev; | 73 | struct cdev cdev; |
73 | struct device *dev; | 74 | struct device *dev; |
74 | struct fasync_struct *async_queue; /* fasync method */ | 75 | struct fasync_struct *async_queue; /* fasync method */ |
@@ -82,16 +83,26 @@ struct pps_device { | |||
82 | extern struct device_attribute pps_attrs[]; | 83 | extern struct device_attribute pps_attrs[]; |
83 | 84 | ||
84 | /* | 85 | /* |
86 | * Internal functions. | ||
87 | * | ||
88 | * These are not actually part of the exported API, but this is a | ||
89 | * convenient header file to put them in. | ||
90 | */ | ||
91 | |||
92 | extern int pps_register_cdev(struct pps_device *pps); | ||
93 | extern void pps_unregister_cdev(struct pps_device *pps); | ||
94 | |||
95 | /* | ||
85 | * Exported functions | 96 | * Exported functions |
86 | */ | 97 | */ |
87 | 98 | ||
88 | extern struct pps_device *pps_register_source( | 99 | extern struct pps_device *pps_register_source( |
89 | struct pps_source_info *info, int default_params); | 100 | struct pps_source_info *info, int default_params); |
90 | extern void pps_unregister_source(struct pps_device *pps); | 101 | extern void pps_unregister_source(struct pps_device *pps); |
91 | extern int pps_register_cdev(struct pps_device *pps); | ||
92 | extern void pps_unregister_cdev(struct pps_device *pps); | ||
93 | extern void pps_event(struct pps_device *pps, | 102 | extern void pps_event(struct pps_device *pps, |
94 | struct pps_event_time *ts, int event, void *data); | 103 | struct pps_event_time *ts, int event, void *data); |
104 | /* Look up a pps device by magic cookie */ | ||
105 | struct pps_device *pps_lookup_dev(void const *cookie); | ||
95 | 106 | ||
96 | static inline void timespec_to_pps_ktime(struct pps_ktime *kt, | 107 | static inline void timespec_to_pps_ktime(struct pps_ktime *kt, |
97 | struct timespec ts) | 108 | struct timespec ts) |