diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pps/kapi.c | 56 | ||||
-rw-r--r-- | drivers/pps/pps.c | 50 |
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 | |||
39 | static DEFINE_SPINLOCK(pps_idr_lock); | ||
40 | static 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 | ||
163 | free_idr: | ||
164 | spin_lock_irq(&pps_idr_lock); | ||
165 | idr_remove(&pps_idr, id); | ||
166 | spin_unlock_irq(&pps_idr_lock); | ||
167 | |||
168 | kfree_pps: | 123 | kfree_pps: |
169 | kfree(pps); | 124 | kfree(pps); |
170 | 125 | ||
@@ -184,15 +139,10 @@ EXPORT_SYMBOL(pps_register_source); | |||
184 | 139 | ||
185 | void pps_unregister_source(struct pps_device *pps) | 140 | void 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 | } |
197 | EXPORT_SYMBOL(pps_unregister_source); | 147 | EXPORT_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 @@ | |||
38 | static dev_t pps_devt; | 39 | static dev_t pps_devt; |
39 | static struct class *pps_class; | 40 | static struct class *pps_class; |
40 | 41 | ||
42 | static DEFINE_SPINLOCK(pps_idr_lock); | ||
43 | static 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 | ||
236 | static 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 | |||
232 | int pps_register_cdev(struct pps_device *pps) | 250 | int 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) | |||
258 | del_cdev: | 301 | del_cdev: |
259 | cdev_del(&pps->cdev); | 302 | cdev_del(&pps->cdev); |
260 | 303 | ||
304 | free_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 | ||