summaryrefslogtreecommitdiffstats
path: root/drivers/hid/hidraw.c
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2012-11-16 16:59:17 +0100
committerArnd Bergmann <arnd@arndb.de>2012-11-16 16:59:17 +0100
commitdb2f95de7e6ab3d5cd7cc047bb09eb9ada07e3ba (patch)
tree46543712dbbb15075f7532621b0311f1de653e57 /drivers/hid/hidraw.c
parent1bf0bc1e050fc425cc776b10d3ce8754389aabbe (diff)
parentd6aef84a48fa54ac606ae719fcd125199939f43d (diff)
Merge tag 'imx-soc' of git://git.pengutronix.de/git/imx/linux-2.6 into next/soc
From Sascha Hauer <s.hauer@pengutronix.de>: ARM i.MX SoC updates based on imx-multiplatform branch. * tag 'imx-soc' of git://git.pengutronix.de/git/imx/linux-2.6: ARM i.MX51 babbage: Add display support ARM i.MX6: Add IPU support ARM i.MX51: Add IPU support ARM i.MX53: Add IPU support ARM i.MX5: switch IPU clk support to devicetree bindings ARM i.MX6: fix ldb_di_sel mux ARM i.MX51: setup MIPI during startup mx2_camera: Fix regression caused by clock conversion ARM: clk-imx27: Add missing clock for mx2-camera ARM i.MX27: Fix low reference clock path ARM: dts: imx27-3ds: Remove local watchdog inclusion watchdog: Support imx watchdog on SOC_IMX53 ARM: mach-imx: Support for DryIce RTC in i.MX53 ARM : i.MX27 : split code for allocation of ressources of camera and eMMA Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/hid/hidraw.c')
-rw-r--r--drivers/hid/hidraw.c69
1 files changed, 43 insertions, 26 deletions
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 17d15bb610d..7c47fc3f7b2 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -42,7 +42,6 @@ static struct cdev hidraw_cdev;
static struct class *hidraw_class;
static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
static DEFINE_MUTEX(minors_lock);
-static void drop_ref(struct hidraw *hid, int exists_bit);
static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
@@ -114,7 +113,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
__u8 *buf;
int ret = 0;
- if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
+ if (!hidraw_table[minor]) {
ret = -ENODEV;
goto out;
}
@@ -262,7 +261,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
}
mutex_lock(&minors_lock);
- if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
+ if (!hidraw_table[minor]) {
err = -ENODEV;
goto out_unlock;
}
@@ -299,12 +298,36 @@ out:
static int hidraw_release(struct inode * inode, struct file * file)
{
unsigned int minor = iminor(inode);
+ struct hidraw *dev;
struct hidraw_list *list = file->private_data;
+ int ret;
+ int i;
+
+ mutex_lock(&minors_lock);
+ if (!hidraw_table[minor]) {
+ ret = -ENODEV;
+ goto unlock;
+ }
- drop_ref(hidraw_table[minor], 0);
list_del(&list->node);
+ dev = hidraw_table[minor];
+ if (!--dev->open) {
+ if (list->hidraw->exist) {
+ hid_hw_power(dev->hid, PM_HINT_NORMAL);
+ hid_hw_close(dev->hid);
+ } else {
+ kfree(list->hidraw);
+ }
+ }
+
+ for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i)
+ kfree(list->buffer[i].value);
kfree(list);
- return 0;
+ ret = 0;
+unlock:
+ mutex_unlock(&minors_lock);
+
+ return ret;
}
static long hidraw_ioctl(struct file *file, unsigned int cmd,
@@ -506,7 +529,21 @@ EXPORT_SYMBOL_GPL(hidraw_connect);
void hidraw_disconnect(struct hid_device *hid)
{
struct hidraw *hidraw = hid->hidraw;
- drop_ref(hidraw, 1);
+
+ mutex_lock(&minors_lock);
+ hidraw->exist = 0;
+
+ device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
+
+ hidraw_table[hidraw->minor] = NULL;
+
+ if (hidraw->open) {
+ hid_hw_close(hid);
+ wake_up_interruptible(&hidraw->wait);
+ } else {
+ kfree(hidraw);
+ }
+ mutex_unlock(&minors_lock);
}
EXPORT_SYMBOL_GPL(hidraw_disconnect);
@@ -555,23 +592,3 @@ void hidraw_exit(void)
unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
}
-
-static void drop_ref(struct hidraw *hidraw, int exists_bit)
-{
- mutex_lock(&minors_lock);
- if (exists_bit) {
- hid_hw_close(hidraw->hid);
- hidraw->exist = 0;
- if (hidraw->open)
- wake_up_interruptible(&hidraw->wait);
- } else {
- --hidraw->open;
- }
-
- if (!hidraw->open && !hidraw->exist) {
- device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
- hidraw_table[hidraw->minor] = NULL;
- kfree(hidraw);
- }
- mutex_unlock(&minors_lock);
-}