aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
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