aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/pps/kapi.c56
-rw-r--r--drivers/pps/pps.c50
2 files changed, 52 insertions, 54 deletions
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index e8847c118ea3..c42d3cb8baa1 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -27,19 +27,11 @@
27#include <linux/sched.h> 27#include <linux/sched.h>
28#include <linux/time.h> 28#include <linux/time.h>
29#include <linux/spinlock.h> 29#include <linux/spinlock.h>
30#include <linux/idr.h>
31#include <linux/fs.h> 30#include <linux/fs.h>
32#include <linux/pps_kernel.h> 31#include <linux/pps_kernel.h>
33#include <linux/slab.h> 32#include <linux/slab.h>
34 33
35/* 34/*
36 * Local variables
37 */
38
39static DEFINE_SPINLOCK(pps_idr_lock);
40static DEFINE_IDR(pps_idr);
41
42/*
43 * Local functions 35 * Local functions
44 */ 36 */
45 37
@@ -76,7 +68,6 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
76 int default_params) 68 int default_params)
77{ 69{
78 struct pps_device *pps; 70 struct pps_device *pps;
79 int id;
80 int err; 71 int err;
81 72
82 /* Sanity checks */ 73 /* Sanity checks */
@@ -117,54 +108,18 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
117 init_waitqueue_head(&pps->queue); 108 init_waitqueue_head(&pps->queue);
118 spin_lock_init(&pps->lock); 109 spin_lock_init(&pps->lock);
119 110
120 /* Get new ID for the new PPS source */
121 if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) {
122 err = -ENOMEM;
123 goto kfree_pps;
124 }
125
126 spin_lock_irq(&pps_idr_lock);
127
128 /* Now really allocate the PPS source.
129 * After idr_get_new() calling the new source will be freely available
130 * into the kernel.
131 */
132 err = idr_get_new(&pps_idr, pps, &id);
133 if (err < 0) {
134 spin_unlock_irq(&pps_idr_lock);
135 goto kfree_pps;
136 }
137
138 id = id & MAX_ID_MASK;
139 if (id >= PPS_MAX_SOURCES) {
140 spin_unlock_irq(&pps_idr_lock);
141
142 pr_err("%s: too many PPS sources in the system\n",
143 info->name);
144 err = -EBUSY;
145 goto free_idr;
146 }
147 pps->id = id;
148
149 spin_unlock_irq(&pps_idr_lock);
150
151 /* Create the char device */ 111 /* Create the char device */
152 err = pps_register_cdev(pps); 112 err = pps_register_cdev(pps);
153 if (err < 0) { 113 if (err < 0) {
154 pr_err("%s: unable to create char device\n", 114 pr_err("%s: unable to create char device\n",
155 info->name); 115 info->name);
156 goto free_idr; 116 goto kfree_pps;
157 } 117 }
158 118
159 dev_info(pps->dev, "new PPS source %s\n", info->name); 119 dev_info(pps->dev, "new PPS source %s\n", info->name);
160 120
161 return pps; 121 return pps;
162 122
163free_idr:
164 spin_lock_irq(&pps_idr_lock);
165 idr_remove(&pps_idr, id);
166 spin_unlock_irq(&pps_idr_lock);
167
168kfree_pps: 123kfree_pps:
169 kfree(pps); 124 kfree(pps);
170 125
@@ -184,15 +139,10 @@ EXPORT_SYMBOL(pps_register_source);
184 139
185void pps_unregister_source(struct pps_device *pps) 140void pps_unregister_source(struct pps_device *pps)
186{ 141{
187 unsigned int id = pps->id;
188
189 pps_unregister_cdev(pps); 142 pps_unregister_cdev(pps);
190 143
191 spin_lock_irq(&pps_idr_lock); 144 /* don't have to kfree(pps) here because it will be done on
192 idr_remove(&pps_idr, pps->id); 145 * device destruction */
193 spin_unlock_irq(&pps_idr_lock);
194
195 kfree(pps);
196} 146}
197EXPORT_SYMBOL(pps_unregister_source); 147EXPORT_SYMBOL(pps_unregister_source);
198 148
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