diff options
Diffstat (limited to 'drivers/input/serio')
-rw-r--r-- | drivers/input/serio/serio_raw.c | 54 |
1 files changed, 29 insertions, 25 deletions
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 830e2fe70a66..4d4cd142bbbb 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c | |||
@@ -51,7 +51,6 @@ struct serio_raw_client { | |||
51 | 51 | ||
52 | static DEFINE_MUTEX(serio_raw_mutex); | 52 | static DEFINE_MUTEX(serio_raw_mutex); |
53 | static LIST_HEAD(serio_raw_list); | 53 | static LIST_HEAD(serio_raw_list); |
54 | static unsigned int serio_raw_no; | ||
55 | 54 | ||
56 | /********************************************************************* | 55 | /********************************************************************* |
57 | * Interface with userspace (file operations) * | 56 | * Interface with userspace (file operations) * |
@@ -117,14 +116,11 @@ out: | |||
117 | return retval; | 116 | return retval; |
118 | } | 117 | } |
119 | 118 | ||
120 | static void serio_raw_cleanup(struct kref *kref) | 119 | static void serio_raw_free(struct kref *kref) |
121 | { | 120 | { |
122 | struct serio_raw *serio_raw = | 121 | struct serio_raw *serio_raw = |
123 | container_of(kref, struct serio_raw, kref); | 122 | container_of(kref, struct serio_raw, kref); |
124 | 123 | ||
125 | misc_deregister(&serio_raw->dev); | ||
126 | list_del_init(&serio_raw->node); | ||
127 | |||
128 | put_device(&serio_raw->serio->dev); | 124 | put_device(&serio_raw->serio->dev); |
129 | kfree(serio_raw); | 125 | kfree(serio_raw); |
130 | } | 126 | } |
@@ -134,11 +130,14 @@ static int serio_raw_release(struct inode *inode, struct file *file) | |||
134 | struct serio_raw_client *client = file->private_data; | 130 | struct serio_raw_client *client = file->private_data; |
135 | struct serio_raw *serio_raw = client->serio_raw; | 131 | struct serio_raw *serio_raw = client->serio_raw; |
136 | 132 | ||
137 | mutex_lock(&serio_raw_mutex); | 133 | serio_pause_rx(serio_raw->serio); |
134 | list_del(&client->node); | ||
135 | serio_continue_rx(serio_raw->serio); | ||
138 | 136 | ||
139 | kref_put(&serio_raw->kref, serio_raw_cleanup); | 137 | kfree(client); |
138 | |||
139 | kref_put(&serio_raw->kref, serio_raw_free); | ||
140 | 140 | ||
141 | mutex_unlock(&serio_raw_mutex); | ||
142 | return 0; | 141 | return 0; |
143 | } | 142 | } |
144 | 143 | ||
@@ -281,6 +280,7 @@ static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, | |||
281 | 280 | ||
282 | static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) | 281 | static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) |
283 | { | 282 | { |
283 | static atomic_t serio_raw_no = ATOMIC_INIT(0); | ||
284 | struct serio_raw *serio_raw; | 284 | struct serio_raw *serio_raw; |
285 | int err; | 285 | int err; |
286 | 286 | ||
@@ -290,10 +290,8 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) | |||
290 | return -ENOMEM; | 290 | return -ENOMEM; |
291 | } | 291 | } |
292 | 292 | ||
293 | mutex_lock(&serio_raw_mutex); | ||
294 | |||
295 | snprintf(serio_raw->name, sizeof(serio_raw->name), | 293 | snprintf(serio_raw->name, sizeof(serio_raw->name), |
296 | "serio_raw%d", serio_raw_no++); | 294 | "serio_raw%ld", (long)atomic_inc_return(&serio_raw_no) - 1); |
297 | kref_init(&serio_raw->kref); | 295 | kref_init(&serio_raw->kref); |
298 | INIT_LIST_HEAD(&serio_raw->client_list); | 296 | INIT_LIST_HEAD(&serio_raw->client_list); |
299 | init_waitqueue_head(&serio_raw->wait); | 297 | init_waitqueue_head(&serio_raw->wait); |
@@ -305,9 +303,14 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) | |||
305 | 303 | ||
306 | err = serio_open(serio, drv); | 304 | err = serio_open(serio, drv); |
307 | if (err) | 305 | if (err) |
308 | goto out_free; | 306 | goto err_free; |
307 | |||
308 | err = mutex_lock_killable(&serio_raw_mutex); | ||
309 | if (err) | ||
310 | goto err_close; | ||
309 | 311 | ||
310 | list_add_tail(&serio_raw->node, &serio_raw_list); | 312 | list_add_tail(&serio_raw->node, &serio_raw_list); |
313 | mutex_unlock(&serio_raw_mutex); | ||
311 | 314 | ||
312 | serio_raw->dev.minor = PSMOUSE_MINOR; | 315 | serio_raw->dev.minor = PSMOUSE_MINOR; |
313 | serio_raw->dev.name = serio_raw->name; | 316 | serio_raw->dev.name = serio_raw->name; |
@@ -324,22 +327,20 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) | |||
324 | dev_err(&serio->dev, | 327 | dev_err(&serio->dev, |
325 | "failed to register raw access device for %s\n", | 328 | "failed to register raw access device for %s\n", |
326 | serio->phys); | 329 | serio->phys); |
327 | goto out_close; | 330 | goto err_unlink; |
328 | } | 331 | } |
329 | 332 | ||
330 | dev_info(&serio->dev, "raw access enabled on %s (%s, minor %d)\n", | 333 | dev_info(&serio->dev, "raw access enabled on %s (%s, minor %d)\n", |
331 | serio->phys, serio_raw->name, serio_raw->dev.minor); | 334 | serio->phys, serio_raw->name, serio_raw->dev.minor); |
332 | goto out; | 335 | return 0; |
333 | 336 | ||
334 | out_close: | 337 | err_unlink: |
335 | serio_close(serio); | ||
336 | list_del_init(&serio_raw->node); | 338 | list_del_init(&serio_raw->node); |
337 | out_free: | 339 | err_close: |
340 | serio_close(serio); | ||
341 | err_free: | ||
338 | serio_set_drvdata(serio, NULL); | 342 | serio_set_drvdata(serio, NULL); |
339 | put_device(&serio->dev); | 343 | kref_put(&serio_raw->kref, serio_raw_free); |
340 | kfree(serio_raw); | ||
341 | out: | ||
342 | mutex_unlock(&serio_raw_mutex); | ||
343 | return err; | 344 | return err; |
344 | } | 345 | } |
345 | 346 | ||
@@ -382,14 +383,17 @@ static void serio_raw_disconnect(struct serio *serio) | |||
382 | { | 383 | { |
383 | struct serio_raw *serio_raw = serio_get_drvdata(serio); | 384 | struct serio_raw *serio_raw = serio_get_drvdata(serio); |
384 | 385 | ||
385 | mutex_lock(&serio_raw_mutex); | 386 | misc_deregister(&serio_raw->dev); |
386 | 387 | ||
387 | serio_close(serio); | 388 | mutex_lock(&serio_raw_mutex); |
388 | serio_raw->dead = true; | 389 | serio_raw->dead = true; |
390 | list_del_init(&serio_raw->node); | ||
391 | mutex_unlock(&serio_raw_mutex); | ||
392 | |||
389 | serio_raw_hangup(serio_raw); | 393 | serio_raw_hangup(serio_raw); |
390 | kref_put(&serio_raw->kref, serio_raw_cleanup); | ||
391 | 394 | ||
392 | mutex_unlock(&serio_raw_mutex); | 395 | serio_close(serio); |
396 | kref_put(&serio_raw->kref, serio_raw_free); | ||
393 | 397 | ||
394 | serio_set_drvdata(serio, NULL); | 398 | serio_set_drvdata(serio, NULL); |
395 | } | 399 | } |