static DEFINE_MUTEX(serio_raw_mutex);
static LIST_HEAD(serio_raw_list);
-static unsigned int serio_raw_no;
/*********************************************************************
* Interface with userspace (file operations) *
return retval;
}
-static void serio_raw_cleanup(struct kref *kref)
+static void serio_raw_free(struct kref *kref)
{
struct serio_raw *serio_raw =
container_of(kref, struct serio_raw, kref);
- misc_deregister(&serio_raw->dev);
- list_del_init(&serio_raw->node);
-
put_device(&serio_raw->serio->dev);
kfree(serio_raw);
}
struct serio_raw_client *client = file->private_data;
struct serio_raw *serio_raw = client->serio_raw;
- mutex_lock(&serio_raw_mutex);
+ serio_pause_rx(serio_raw->serio);
+ list_del(&client->node);
+ serio_continue_rx(serio_raw->serio);
- kref_put(&serio_raw->kref, serio_raw_cleanup);
+ kfree(client);
+
+ kref_put(&serio_raw->kref, serio_raw_free);
- mutex_unlock(&serio_raw_mutex);
return 0;
}
static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
{
+ static atomic_t serio_raw_no = ATOMIC_INIT(0);
struct serio_raw *serio_raw;
int err;
return -ENOMEM;
}
- mutex_lock(&serio_raw_mutex);
-
snprintf(serio_raw->name, sizeof(serio_raw->name),
- "serio_raw%d", serio_raw_no++);
+ "serio_raw%ld", (long)atomic_inc_return(&serio_raw_no) - 1);
kref_init(&serio_raw->kref);
INIT_LIST_HEAD(&serio_raw->client_list);
init_waitqueue_head(&serio_raw->wait);
err = serio_open(serio, drv);
if (err)
- goto out_free;
+ goto err_free;
+
+ err = mutex_lock_killable(&serio_raw_mutex);
+ if (err)
+ goto err_close;
list_add_tail(&serio_raw->node, &serio_raw_list);
+ mutex_unlock(&serio_raw_mutex);
serio_raw->dev.minor = PSMOUSE_MINOR;
serio_raw->dev.name = serio_raw->name;
dev_err(&serio->dev,
"failed to register raw access device for %s\n",
serio->phys);
- goto out_close;
+ goto err_unlink;
}
dev_info(&serio->dev, "raw access enabled on %s (%s, minor %d)\n",
serio->phys, serio_raw->name, serio_raw->dev.minor);
- goto out;
+ return 0;
-out_close:
- serio_close(serio);
+err_unlink:
list_del_init(&serio_raw->node);
-out_free:
+err_close:
+ serio_close(serio);
+err_free:
serio_set_drvdata(serio, NULL);
- put_device(&serio->dev);
- kfree(serio_raw);
-out:
- mutex_unlock(&serio_raw_mutex);
+ kref_put(&serio_raw->kref, serio_raw_free);
return err;
}
{
struct serio_raw *serio_raw = serio_get_drvdata(serio);
- mutex_lock(&serio_raw_mutex);
+ misc_deregister(&serio_raw->dev);
- serio_close(serio);
+ mutex_lock(&serio_raw_mutex);
serio_raw->dead = true;
+ list_del_init(&serio_raw->node);
+ mutex_unlock(&serio_raw_mutex);
+
serio_raw_hangup(serio_raw);
- kref_put(&serio_raw->kref, serio_raw_cleanup);
- mutex_unlock(&serio_raw_mutex);
+ serio_close(serio);
+ kref_put(&serio_raw->kref, serio_raw_free);
serio_set_drvdata(serio, NULL);
}