aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pps/pps.c
diff options
context:
space:
mode:
authorAlexander Gordeev <lasaine@lvk.cs.msu.su>2011-01-12 20:00:53 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 11:03:20 -0500
commit083e58666ff5b3c5750d9a5c0560018b03cfb4b2 (patch)
treee0543cd7b2e375ca29c41a560e9ce0899c0f1d4e /drivers/pps/pps.c
parent7f7cce74105adf714bdc9357da3b6f06e019958c (diff)
pps: move idr stuff to pps.c
Since now idr is only used to manage char device id's and not used in kernel API anymore it should be moved to pps.c. This also makes it possible to release id only at actual device freeing so nobody can register a pps device with the same id while our device is not freed yet. 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/pps.c')
-rw-r--r--drivers/pps/pps.c50
1 files changed, 49 insertions, 1 deletions
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index 9f7c2e858dd0..79b445578132 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -30,6 +30,7 @@
30#include <linux/cdev.h> 30#include <linux/cdev.h>
31#include <linux/poll.h> 31#include <linux/poll.h>
32#include <linux/pps_kernel.h> 32#include <linux/pps_kernel.h>
33#include <linux/slab.h>
33 34
34/* 35/*
35 * Local variables 36 * Local variables
@@ -38,6 +39,9 @@
38static dev_t pps_devt; 39static dev_t pps_devt;
39static struct class *pps_class; 40static struct class *pps_class;
40 41
42static DEFINE_SPINLOCK(pps_idr_lock);
43static DEFINE_IDR(pps_idr);
44
41/* 45/*
42 * Char device methods 46 * Char device methods
43 */ 47 */
@@ -229,11 +233,48 @@ static const struct file_operations pps_cdev_fops = {
229 .release = pps_cdev_release, 233 .release = pps_cdev_release,
230}; 234};
231 235
236static void pps_device_destruct(struct device *dev)
237{
238 struct pps_device *pps = dev_get_drvdata(dev);
239
240 /* release id here to protect others from using it while it's
241 * still in use */
242 spin_lock_irq(&pps_idr_lock);
243 idr_remove(&pps_idr, pps->id);
244 spin_unlock_irq(&pps_idr_lock);
245
246 kfree(dev);
247 kfree(pps);
248}
249
232int pps_register_cdev(struct pps_device *pps) 250int pps_register_cdev(struct pps_device *pps)
233{ 251{
234 int err; 252 int err;
235 dev_t devt; 253 dev_t devt;
236 254
255 /* Get new ID for the new PPS source */
256 if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0)
257 return -ENOMEM;
258
259 /* Now really allocate the PPS source.
260 * After idr_get_new() calling the new source will be freely available
261 * into the kernel.
262 */
263 spin_lock_irq(&pps_idr_lock);
264 err = idr_get_new(&pps_idr, pps, &pps->id);
265 spin_unlock_irq(&pps_idr_lock);
266
267 if (err < 0)
268 return err;
269
270 pps->id &= MAX_ID_MASK;
271 if (pps->id >= PPS_MAX_SOURCES) {
272 pr_err("%s: too many PPS sources in the system\n",
273 pps->info.name);
274 err = -EBUSY;
275 goto free_idr;
276 }
277
237 devt = MKDEV(MAJOR(pps_devt), pps->id); 278 devt = MKDEV(MAJOR(pps_devt), pps->id);
238 279
239 cdev_init(&pps->cdev, &pps_cdev_fops); 280 cdev_init(&pps->cdev, &pps_cdev_fops);
@@ -243,13 +284,15 @@ int pps_register_cdev(struct pps_device *pps)
243 if (err) { 284 if (err) {
244 pr_err("%s: failed to add char device %d:%d\n", 285 pr_err("%s: failed to add char device %d:%d\n",
245 pps->info.name, MAJOR(pps_devt), pps->id); 286 pps->info.name, MAJOR(pps_devt), pps->id);
246 return err; 287 goto free_idr;
247 } 288 }
248 pps->dev = device_create(pps_class, pps->info.dev, devt, pps, 289 pps->dev = device_create(pps_class, pps->info.dev, devt, pps,
249 "pps%d", pps->id); 290 "pps%d", pps->id);
250 if (IS_ERR(pps->dev)) 291 if (IS_ERR(pps->dev))
251 goto del_cdev; 292 goto del_cdev;
252 293
294 pps->dev->release = pps_device_destruct;
295
253 pr_debug("source %s got cdev (%d:%d)\n", pps->info.name, 296 pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
254 MAJOR(pps_devt), pps->id); 297 MAJOR(pps_devt), pps->id);
255 298
@@ -258,6 +301,11 @@ int pps_register_cdev(struct pps_device *pps)
258del_cdev: 301del_cdev:
259 cdev_del(&pps->cdev); 302 cdev_del(&pps->cdev);
260 303
304free_idr:
305 spin_lock_irq(&pps_idr_lock);
306 idr_remove(&pps_idr, pps->id);
307 spin_unlock_irq(&pps_idr_lock);
308
261 return err; 309 return err;
262} 310}
263 311