summaryrefslogtreecommitdiffstats
path: root/drivers/input/serio/serio_raw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/serio/serio_raw.c')
-rw-r--r--drivers/input/serio/serio_raw.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index 64fcefb50fb..30ff9638819 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -40,6 +40,7 @@ struct serio_raw {
wait_queue_head_t wait;
struct list_head client_list;
struct list_head node;
+ bool dead;
};
struct serio_raw_client {
@@ -91,7 +92,7 @@ static int serio_raw_open(struct inode *inode, struct file *file)
goto out;
}
- if (!serio_raw->serio) {
+ if (serio_raw->dead) {
retval = -ENODEV;
goto out;
}
@@ -123,6 +124,8 @@ static void serio_raw_cleanup(struct kref *kref)
misc_deregister(&serio_raw->dev);
list_del_init(&serio_raw->node);
+
+ put_device(&serio_raw->serio->dev);
kfree(serio_raw);
}
@@ -164,19 +167,18 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer,
char uninitialized_var(c);
ssize_t retval = 0;
- if (!serio_raw->serio)
+ if (serio_raw->dead)
return -ENODEV;
if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(serio_raw->wait,
- serio_raw->head != serio_raw->tail ||
- !serio_raw->serio);
+ serio_raw->head != serio_raw->tail || serio_raw->dead);
if (retval)
return retval;
- if (!serio_raw->serio)
+ if (serio_raw->dead)
return -ENODEV;
while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) {
@@ -201,7 +203,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
if (retval)
return retval;
- if (!serio_raw->serio) {
+ if (serio_raw->dead) {
retval = -ENODEV;
goto out;
}
@@ -291,10 +293,12 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
snprintf(serio_raw->name, sizeof(serio_raw->name),
"serio_raw%d", serio_raw_no++);
kref_init(&serio_raw->kref);
- serio_raw->serio = serio;
INIT_LIST_HEAD(&serio_raw->client_list);
init_waitqueue_head(&serio_raw->wait);
+ serio_raw->serio = serio;
+ get_device(&serio->dev);
+
serio_set_drvdata(serio, serio_raw);
err = serio_open(serio, drv);
@@ -330,6 +334,7 @@ out_close:
list_del_init(&serio_raw->node);
out_free:
serio_set_drvdata(serio, NULL);
+ put_device(&serio->dev);
kfree(serio_raw);
out:
mutex_unlock(&serio_raw_mutex);
@@ -365,7 +370,7 @@ static void serio_raw_disconnect(struct serio *serio)
serio_close(serio);
serio_set_drvdata(serio, NULL);
- serio_raw->serio = NULL;
+ serio_raw->dead = true;
wake_up_interruptible(&serio_raw->wait);
kref_put(&serio_raw->kref, serio_raw_cleanup);