Commit 85f5b35d authored by Dmitry Torokhov's avatar Dmitry Torokhov

Input: serio_raw - explicitly mark disconnected ports as dead

Instead of relying on setting serio_raw->serio to NULL upon disconnecting
ports mark them explicitly as "dead". Also take and carry reference to
underlying serio port to make sure it does not go away until we are done
with it.
Reviewed-by: default avatarWanlong Gao <gaowanlong@cn.fujitsu.com>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 15a564d8
...@@ -40,6 +40,7 @@ struct serio_raw { ...@@ -40,6 +40,7 @@ struct serio_raw {
wait_queue_head_t wait; wait_queue_head_t wait;
struct list_head client_list; struct list_head client_list;
struct list_head node; struct list_head node;
bool dead;
}; };
struct serio_raw_client { struct serio_raw_client {
...@@ -91,7 +92,7 @@ static int serio_raw_open(struct inode *inode, struct file *file) ...@@ -91,7 +92,7 @@ static int serio_raw_open(struct inode *inode, struct file *file)
goto out; goto out;
} }
if (!serio_raw->serio) { if (serio_raw->dead) {
retval = -ENODEV; retval = -ENODEV;
goto out; goto out;
} }
...@@ -123,6 +124,8 @@ static void serio_raw_cleanup(struct kref *kref) ...@@ -123,6 +124,8 @@ static void serio_raw_cleanup(struct kref *kref)
misc_deregister(&serio_raw->dev); misc_deregister(&serio_raw->dev);
list_del_init(&serio_raw->node); list_del_init(&serio_raw->node);
put_device(&serio_raw->serio->dev);
kfree(serio_raw); kfree(serio_raw);
} }
...@@ -164,19 +167,18 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer, ...@@ -164,19 +167,18 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer,
char uninitialized_var(c); char uninitialized_var(c);
ssize_t retval = 0; ssize_t retval = 0;
if (!serio_raw->serio) if (serio_raw->dead)
return -ENODEV; return -ENODEV;
if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK)) if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
return -EAGAIN; return -EAGAIN;
retval = wait_event_interruptible(serio_raw->wait, retval = wait_event_interruptible(serio_raw->wait,
serio_raw->head != serio_raw->tail || serio_raw->head != serio_raw->tail || serio_raw->dead);
!serio_raw->serio);
if (retval) if (retval)
return retval; return retval;
if (!serio_raw->serio) if (serio_raw->dead)
return -ENODEV; return -ENODEV;
while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) { 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, ...@@ -201,7 +203,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
if (retval) if (retval)
return retval; return retval;
if (!serio_raw->serio) { if (serio_raw->dead) {
retval = -ENODEV; retval = -ENODEV;
goto out; goto out;
} }
...@@ -291,10 +293,12 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) ...@@ -291,10 +293,12 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
snprintf(serio_raw->name, sizeof(serio_raw->name), snprintf(serio_raw->name, sizeof(serio_raw->name),
"serio_raw%d", serio_raw_no++); "serio_raw%d", serio_raw_no++);
kref_init(&serio_raw->kref); kref_init(&serio_raw->kref);
serio_raw->serio = serio;
INIT_LIST_HEAD(&serio_raw->client_list); INIT_LIST_HEAD(&serio_raw->client_list);
init_waitqueue_head(&serio_raw->wait); init_waitqueue_head(&serio_raw->wait);
serio_raw->serio = serio;
get_device(&serio->dev);
serio_set_drvdata(serio, serio_raw); serio_set_drvdata(serio, serio_raw);
err = serio_open(serio, drv); err = serio_open(serio, drv);
...@@ -330,6 +334,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) ...@@ -330,6 +334,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
list_del_init(&serio_raw->node); list_del_init(&serio_raw->node);
out_free: out_free:
serio_set_drvdata(serio, NULL); serio_set_drvdata(serio, NULL);
put_device(&serio->dev);
kfree(serio_raw); kfree(serio_raw);
out: out:
mutex_unlock(&serio_raw_mutex); mutex_unlock(&serio_raw_mutex);
...@@ -365,7 +370,7 @@ static void serio_raw_disconnect(struct serio *serio) ...@@ -365,7 +370,7 @@ static void serio_raw_disconnect(struct serio *serio)
serio_close(serio); serio_close(serio);
serio_set_drvdata(serio, NULL); serio_set_drvdata(serio, NULL);
serio_raw->serio = NULL; serio_raw->dead = true;
wake_up_interruptible(&serio_raw->wait); wake_up_interruptible(&serio_raw->wait);
kref_put(&serio_raw->kref, serio_raw_cleanup); kref_put(&serio_raw->kref, serio_raw_cleanup);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment