Discussion:
[Linuxwacom-devel] [PATCH 01/25] backport: HID: wacom: actually report the battery level for wireless connected
Aaron Armstrong Skomra
2016-10-20 18:42:52 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

Since fd5f92b ("HID: wacom: reuse wacom_parse_and_register() in
wireless_work"), wacom->shared->type is not set.
Send the information of the battery if we have one.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (d453b87)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (ea3af31)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom_wac.c | 3 ++-
3.17/wacom_wac.c | 3 ++-
3.7/wacom_wac.c | 3 ++-
3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/2.6.38/wacom_wac.c b/2.6.38/wacom_wac.c
index 91bf137..379bfdb 100644
--- a/2.6.38/wacom_wac.c
+++ b/2.6.38/wacom_wac.c
@@ -1547,6 +1547,7 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)

static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
{
+ struct wacom *w = container_of(wacom, struct wacom, wacom_wac);
unsigned char *data = wacom->data;
int connected;

@@ -1574,7 +1575,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
wacom_schedule_work(wacom);
}

- if (wacom->shared->type)
+ if (w->battery.dev)
wacom_notify_battery(wacom, battery, charging, 1, 0);

} else if (wacom->pid != 0) {
diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 81df74e..89cbe51 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -2131,6 +2131,7 @@ static int wacom_bamboo_pad_irq(struct wacom_wac *wacom, size_t len)

static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
{
+ struct wacom *w = container_of(wacom, struct wacom, wacom_wac);
unsigned char *data = wacom->data;
int connected;

@@ -2158,7 +2159,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
wacom_schedule_work(wacom);
}

- if (wacom->shared->type)
+ if (WACOM_POWERSUPPLY_DEVICE(w->battery))
wacom_notify_battery(wacom, battery, charging, 1, 0);

} else if (wacom->pid != 0) {
diff --git a/3.7/wacom_wac.c b/3.7/wacom_wac.c
index 3aac8ea..2a9e173 100644
--- a/3.7/wacom_wac.c
+++ b/3.7/wacom_wac.c
@@ -1528,6 +1528,7 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)

static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
{
+ struct wacom *w = container_of(wacom, struct wacom, wacom_wac);
unsigned char *data = wacom->data;
int connected;

@@ -1555,7 +1556,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
wacom_schedule_work(wacom);
}

- if (wacom->shared->type)
+ if (w->battery.dev)
wacom_notify_battery(wacom, battery, charging, 1, 0);

} else if (wacom->pid != 0) {
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:42:53 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

The type is never set but we check for it in wacom_wireless_irq().
It looks like this is a big hack from the beginning, so fill in the gap
only.

Untested.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (97f9afa)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (ffd4ce9)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom_sys.c | 10 +++++++---
3.17/wacom_sys.c | 5 +++--
3.7/wacom_sys.c | 14 +++++++++-----
3 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 9e2c5dc..5051811 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1592,9 +1592,11 @@ static void wacom_wireless_work(struct work_struct *work)
goto fail;

if ((wacom_wac1->features.type == INTUOSHT ||
- wacom_wac1->features.type == INTUOSHT2) &&
- wacom_wac1->features.touch_max)
+ wacom_wac1->features.type == INTUOSHT2) &&
+ wacom_wac1->features.touch_max) {
+ wacom_wac->shared->type = wacom_wac->features.type;
wacom_wac->shared->touch_input = wacom_wac2->input;
+ }
}

error = wacom_initialize_battery(wacom);
@@ -1731,8 +1733,10 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if ((wacom_wac->features.type == INTUOSHT ||
wacom_wac->features.type == INTUOSHT2) &&
wacom_wac->features.touch_max) {
- if (wacom_wac->features.device_type == BTN_TOOL_FINGER)
+ if (wacom_wac->features.device_type == BTN_TOOL_FINGER) {
+ wacom_wac->shared->type = wacom_wac->features.type;
wacom_wac->shared->touch_input = wacom_wac->input;
+ }
}

return 0;
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 8cda3e2..2ad83f5 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1762,9 +1762,10 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
error = hid_hw_open(hdev);

if ((wacom_wac->features.type == INTUOSHT ||
- wacom_wac->features.type == INTUOSHT2) &&
+ wacom_wac->features.type == INTUOSHT2) &&
(wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)) {
- wacom_wac->shared->touch_input = wacom_wac->touch_input;
+ wacom_wac->shared->type = wacom_wac->features.type;
+ wacom_wac->shared->touch_input = wacom_wac->touch_input;
}

return 0;
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index 9ba404a..102523d 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1590,9 +1590,11 @@ static void wacom_wireless_work(struct work_struct *work)
goto fail;

if ((wacom_wac1->features.type == INTUOSHT ||
- wacom_wac1->features.type == INTUOSHT2) &&
- wacom_wac1->features.touch_max)
+ wacom_wac1->features.type == INTUOSHT2) &&
+ wacom_wac1->features.touch_max) {
+ wacom_wac->shared->type = wacom_wac->features.type;
wacom_wac->shared->touch_input = wacom_wac2->input;
+ }
}

error = wacom_initialize_battery(wacom);
@@ -1727,10 +1729,12 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
}

if ((wacom_wac->features.type == INTUOSHT ||
- wacom_wac->features.type == INTUOSHT2) &&
- wacom_wac->features.touch_max) {
- if (wacom_wac->features.device_type == BTN_TOOL_FINGER)
+ wacom_wac->features.type == INTUOSHT2) &&
+ wacom_wac->features.touch_max) {
+ if (wacom_wac->features.device_type == BTN_TOOL_FINGER) {
+ wacom_wac->shared->type = wacom_wac->features.type;
wacom_wac->shared->touch_input = wacom_wac->input;
+ }
}

return 0;
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:42:54 UTC
Permalink
wacom->remote_dir has nothing to do with inputs, so better not magically
removing it when cleaning inputs.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (b62f646)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (c424d7c)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom_sys.c | 14 +++++++-------
3.17/wacom_sys.c | 25 ++++++++++++++-----------
3.7/wacom_sys.c | 14 +++++++-------
3 files changed, 28 insertions(+), 25 deletions(-)

diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 5051811..10bd0fa 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1413,7 +1413,6 @@ static void wacom_unregister_inputs(struct wacom *wacom)
{
if (wacom->wacom_wac.input)
input_unregister_device(wacom->wacom_wac.input);
- kobject_put(wacom->remote_dir);
wacom->wacom_wac.input = NULL;
wacom_destroy_leds(wacom);
}
@@ -1456,14 +1455,8 @@ static int wacom_register_input(struct wacom *wacom)
if (error)
goto fail3;

- error = wacom_initialize_remote(wacom);
- if (error)
- goto fail_remote;
-
return 0;

-fail_remote:
- wacom_destroy_leds(wacom);
fail3:
input_unregister_device(input_dev);
input_dev = NULL;
@@ -1730,6 +1723,12 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
}
}

+ if (wacom->wacom_wac.features.type == REMOTE) {
+ error = wacom_initialize_remote(wacom);
+ if (error)
+ goto fail4;
+ }
+
if ((wacom_wac->features.type == INTUOSHT ||
wacom_wac->features.type == INTUOSHT2) &&
wacom_wac->features.touch_max) {
@@ -1757,6 +1756,7 @@ static void wacom_disconnect(struct usb_interface *intf)

usb_kill_urb(wacom->irq);
cancel_work_sync(&wacom->work);
+ kobject_put(wacom->remote_dir);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
usb_free_urb(wacom->irq);
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 2ad83f5..ca4b362 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1431,7 +1431,6 @@ static void wacom_clean_inputs(struct wacom *wacom)
else
input_free_device(wacom->wacom_wac.pad_input);
}
- kobject_put(wacom->remote_dir);
wacom->wacom_wac.pen_input = NULL;
wacom->wacom_wac.touch_input = NULL;
wacom->wacom_wac.pad_input = NULL;
@@ -1514,16 +1513,10 @@ static int wacom_register_inputs(struct wacom *wacom)
error = wacom_initialize_leds(wacom);
if (error)
goto fail_leds;
-
- error = wacom_initialize_remote(wacom);
- if (error)
- goto fail_remote;
}

return 0;

-fail_remote:
- wacom_destroy_leds(wacom);
fail_leds:
input_unregister_device(pad_input_dev);
pad_input_dev = NULL;
@@ -1724,6 +1717,12 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
if (error)
goto fail_register_inputs;

+ if (wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD) {
+ error = wacom_initialize_remote(wacom);
+ if (error)
+ goto fail_remote;
+ }
+
if (features->type == HID_GENERIC)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
hdev->claimed |= 8; /* HID_CLAIMED_DRIVER */
@@ -1747,7 +1746,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
if ((features->type == BAMBOO_TOUCH) &&
(features->device_type & WACOM_DEVICETYPE_PEN)) {
error = -ENODEV;
- goto fail_hw_start;
+ goto fail_quirks;
}

/* pen only Bamboo neither support touch nor pad */
@@ -1755,7 +1754,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
((features->device_type & WACOM_DEVICETYPE_TOUCH) ||
(features->device_type & WACOM_DEVICETYPE_PAD))) {
error = -ENODEV;
- goto fail_hw_start;
+ goto fail_quirks;
}

if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
@@ -1770,10 +1769,13 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)

return 0;

-fail_hw_start:
+fail_quirks:
hid_hw_stop(hdev);
-fail_register_inputs:
+fail_hw_start:
+ kobject_put(wacom->remote_dir);
+fail_remote:
wacom_clean_inputs(wacom);
+fail_register_inputs:
wacom_destroy_battery(wacom);
fail_battery:
wacom_remove_shared_data(wacom);
@@ -1952,6 +1954,7 @@ static void wacom_remove(struct hid_device *hdev)
hid_hw_stop(hdev);

cancel_work_sync(&wacom->work);
+ kobject_put(wacom->remote_dir);
wacom_clean_inputs(wacom);
if (hdev->bus == BUS_BLUETOOTH)
device_remove_file(&hdev->dev, &dev_attr_speed);
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index 102523d..a36a751 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1407,7 +1407,6 @@ static void wacom_unregister_inputs(struct wacom *wacom)
{
if (wacom->wacom_wac.input)
input_unregister_device(wacom->wacom_wac.input);
- kobject_put(wacom->remote_dir);
wacom->wacom_wac.input = NULL;
wacom_destroy_leds(wacom);
}
@@ -1451,14 +1450,8 @@ static int wacom_register_input(struct wacom *wacom)
if (error)
goto fail3;

- error = wacom_initialize_remote(wacom);
- if (error)
- goto fail_remote;
-
return 0;

-fail_remote:
- wacom_destroy_leds(wacom);
fail3:
input_unregister_device(input_dev);
input_dev = NULL;
@@ -1728,6 +1721,12 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
}
}

+ if (wacom->wacom_wac.features.type == REMOTE) {
+ error = wacom_initialize_remote(wacom);
+ if (error)
+ goto fail4;
+ }
+
if ((wacom_wac->features.type == INTUOSHT ||
wacom_wac->features.type == INTUOSHT2) &&
wacom_wac->features.touch_max) {
@@ -1755,6 +1754,7 @@ static void wacom_disconnect(struct usb_interface *intf)

usb_kill_urb(wacom->irq);
cancel_work_sync(&wacom->work);
+ kobject_put(wacom->remote_dir);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
usb_free_urb(wacom->irq);
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:42:58 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

Simplifying the error code paths.
We need to keep wacom_clean_inputs() around for now as the wireless
module is using it to dynamically remove the inputs on disconnect.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (3dad188)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (3bd4a8f)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom_sys.c | 34 ++++++++++++++++------------------
1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index f248979..e0ee405 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -91,7 +91,12 @@ static void wacom_close(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);

- hid_hw_close(wacom->hdev);
+ /*
+ * wacom->hdev should never be null, but surprisingly, I had the case
+ * once while unplugging the Wacom Wireless Receiver.
+ */
+ if (wacom->hdev)
+ hid_hw_close(wacom->hdev);
}

/*
@@ -1410,7 +1415,7 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom)
struct hid_device *hdev = wacom->hdev;
struct wacom_wac *wacom_wac = &(wacom->wacom_wac);

- input_dev = input_allocate_device();
+ input_dev = devm_input_allocate_device(&hdev->dev);
if (!input_dev)
return NULL;

@@ -1464,10 +1469,10 @@ static int wacom_allocate_inputs(struct wacom *wacom)
wacom_wac->pen_input = wacom_allocate_input(wacom);
wacom_wac->touch_input = wacom_allocate_input(wacom);
wacom_wac->pad_input = wacom_allocate_input(wacom);
- if (!wacom_wac->pen_input || !wacom_wac->touch_input || !wacom_wac->pad_input) {
- wacom_clean_inputs(wacom);
+ if (!wacom_wac->pen_input ||
+ !wacom_wac->touch_input ||
+ !wacom_wac->pad_input)
return -ENOMEM;
- }

wacom_wac->pen_input->name = wacom_wac->pen_name;
wacom_wac->touch_input->name = wacom_wac->touch_name;
@@ -1498,7 +1503,7 @@ static int wacom_register_inputs(struct wacom *wacom)
} else {
error = input_register_device(pen_input_dev);
if (error)
- goto fail_register_pen_input;
+ goto fail;
wacom_wac->pen_registered = true;
}

@@ -1511,7 +1516,7 @@ static int wacom_register_inputs(struct wacom *wacom)
} else {
error = input_register_device(touch_input_dev);
if (error)
- goto fail_register_touch_input;
+ goto fail;
wacom_wac->touch_registered = true;
}

@@ -1524,23 +1529,19 @@ static int wacom_register_inputs(struct wacom *wacom)
} else {
error = input_register_device(pad_input_dev);
if (error)
- goto fail_register_pad_input;
+ goto fail;
wacom_wac->pad_registered = true;
}

return 0;

-fail_register_pad_input:
- if (touch_input_dev)
- input_unregister_device(touch_input_dev);
+fail:
+ wacom_wac->pad_input = NULL;
+ wacom_wac->pad_registered = false;
wacom_wac->touch_input = NULL;
wacom_wac->touch_registered = false;
-fail_register_touch_input:
- if (pen_input_dev)
- input_unregister_device(pen_input_dev);
wacom_wac->pen_input = NULL;
wacom_wac->pen_registered = false;
-fail_register_pen_input:
return error;
}

@@ -1789,7 +1790,6 @@ fail_hw_start:
fail_remote:
wacom_destroy_leds(wacom);
fail_leds:
- wacom_clean_inputs(wacom);
fail_register_inputs:
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
wacom_destroy_battery(wacom);
@@ -1799,7 +1799,6 @@ fail_battery:
fail_shared_data:
fail_parsed:
fail_allocate_inputs:
- wacom_clean_inputs(wacom);
return error;
}

@@ -1979,7 +1978,6 @@ static void wacom_remove(struct hid_device *hdev)
cancel_work_sync(&wacom->battery_work);
kobject_put(wacom->remote_dir);
wacom_destroy_leds(wacom);
- wacom_clean_inputs(wacom);
if (hdev->bus == BUS_BLUETOOTH)
device_remove_file(&hdev->dev, &dev_attr_speed);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:42:57 UTC
Permalink
Simplifying the error code paths.
We need to keep wacom_destroy_battery() around for now as the wireless
module and the remotes are using it to dynamically remove the battery
supply on disconnect.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (b189da9)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (f1754f8)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom_sys.c | 64 +++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 43 insertions(+), 21 deletions(-)

diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index c79a854..f248979 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1094,12 +1094,16 @@ static int wacom_ac_get_property(struct power_supply *psy,
static int wacom_initialize_battery(struct wacom *wacom)
{
static atomic_t battery_no = ATOMIC_INIT(0);
+ struct device *dev = &wacom->hdev->dev;
+ int error;
+ unsigned long n;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
struct power_supply_config psy_cfg = { .drv_data = wacom, };
-#else
- int error;
+ struct power_supply_desc *bat_desc = &WACOM_POWERSUPPLY_DESC(wacom->battery);
+
+ if (!devres_open_group(dev, bat_desc, GFP_KERNEL))
+ return -ENOMEM;
#endif
- unsigned long n;

if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) {
n = atomic_inc_return(&battery_no) - 1;
@@ -1121,52 +1125,66 @@ static int wacom_initialize_battery(struct wacom *wacom)
WACOM_POWERSUPPLY_DESC(wacom->battery).use_for_apm = 0;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
- wacom->battery = power_supply_register(&wacom->hdev->dev,
- &WACOM_POWERSUPPLY_DESC(wacom->battery),
- &psy_cfg);
- if (IS_ERR(wacom->battery))
- return PTR_ERR(wacom->battery);
+ wacom->battery = devm_power_supply_register(dev,
+ &WACOM_POWERSUPPLY_DESC(wacom->battery),
+ &psy_cfg);
+ if (IS_ERR(wacom->battery)) {
+ error = PTR_ERR(wacom->battery);
+ goto err;
+ }
#else
- error = power_supply_register(&wacom->hdev->dev,
+ error = power_supply_register(dev,
&wacom->battery);

if (error)
return error;
#endif

- power_supply_powers(WACOM_POWERSUPPLY_REF(wacom->battery), &wacom->hdev->dev);
+ power_supply_powers(WACOM_POWERSUPPLY_REF(wacom->battery), dev);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
- wacom->ac = power_supply_register(&wacom->hdev->dev,
- &WACOM_POWERSUPPLY_DESC(wacom->ac),
- &psy_cfg
- );
-
+ wacom->ac = devm_power_supply_register(dev,
+ &WACOM_POWERSUPPLY_DESC(wacom->battery),
+ &psy_cfg);
if (IS_ERR(wacom->ac)) {
- power_supply_unregister(wacom->battery);
- return PTR_ERR(wacom->ac);
+ error = PTR_ERR(wacom->ac);
+ goto err;
}
#else
- error = power_supply_register(&wacom->hdev->dev, &wacom->ac);
+ error = power_supply_register(dev, &wacom->ac);

if (error) {
power_supply_unregister(&wacom->battery);
return error;
}
#endif
-
- power_supply_powers(WACOM_POWERSUPPLY_REF(wacom->ac), &wacom->hdev->dev);
+ power_supply_powers(WACOM_POWERSUPPLY_REF(wacom->ac), dev);
}

+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
+ devres_close_group(dev, bat_desc);
+#endif
+
return 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
+err:
+ devres_release_group(dev, bat_desc);
+ return error;
+#endif
}

static void wacom_destroy_battery(struct wacom *wacom)
{
if (WACOM_POWERSUPPLY_DEVICE(wacom->battery)) {
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
+ devres_release_group(&wacom->hdev->dev, WACOM_POWERSUPPLY_DEVICE(wacom->battery));
+#else
power_supply_unregister(WACOM_POWERSUPPLY_REF(wacom->battery));
- WACOM_POWERSUPPLY_DEVICE(wacom->battery) = NULL;
power_supply_unregister(WACOM_POWERSUPPLY_REF(wacom->ac));
+#endif
+ WACOM_POWERSUPPLY_DEVICE(wacom->battery) = NULL;
WACOM_POWERSUPPLY_DEVICE(wacom->ac) = NULL;
}
}
@@ -1773,7 +1791,9 @@ fail_remote:
fail_leds:
wacom_clean_inputs(wacom);
fail_register_inputs:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
wacom_destroy_battery(wacom);
+#endif
fail_battery:
wacom_remove_shared_data(wacom);
fail_shared_data:
@@ -1962,7 +1982,9 @@ static void wacom_remove(struct hid_device *hdev)
wacom_clean_inputs(wacom);
if (hdev->bus == BUS_BLUETOOTH)
device_remove_file(&hdev->dev, &dev_attr_speed);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
wacom_destroy_battery(wacom);
+#endif
wacom_remove_shared_data(wacom);

hid_set_drvdata(hdev, NULL);
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:00 UTC
Permalink
Use our own wacom_devm_sysfs_create_group() as there is currently no
generic one. It has been requested at least twice [1][2] but has been
always rejected.
However, in the Wacom case, for the wirelessly connected devices, we need
to be able to release the created sysfs files without removing the parent
kobject.

[1] https://patchwork.kernel.org/patch/7526551/
[2] https://lkml.org/lkml/2013/3/14/728

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (2df68a8)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (4b97397)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.30/wacom.h | 1 -
2.6.30/wacom_sys.c | 94 ++++++++++++++++++++++++++-------------------------
2.6.36/wacom.h | 1 -
2.6.36/wacom_sys.c | 94 ++++++++++++++++++++++++++-------------------------
2.6.38/wacom.h | 1 -
2.6.38/wacom_sys.c | 98 ++++++++++++++++++++++++++---------------------------
3.17/wacom.h | 1 -
3.17/wacom_sys.c | 95 +++++++++++++++++++++++++--------------------------
3.7/wacom.h | 1 -
3.7/wacom_sys.c | 99 ++++++++++++++++++++++++++----------------------------
10 files changed, 236 insertions(+), 249 deletions(-)

diff --git a/2.6.30/wacom.h b/2.6.30/wacom.h
index c87cc16..65ead0b 100755
--- a/2.6.30/wacom.h
+++ b/2.6.30/wacom.h
@@ -122,7 +122,6 @@ struct wacom {
u8 llv; /* status led brightness no button */
u8 hlv; /* status led brightness button pressed */
} led;
- bool led_initialized;
};

extern const struct usb_device_id wacom_ids[];
diff --git a/2.6.30/wacom_sys.c b/2.6.30/wacom_sys.c
index 3d34efe..4283976 100644
--- a/2.6.30/wacom_sys.c
+++ b/2.6.30/wacom_sys.c
@@ -652,6 +652,45 @@ static struct attribute_group intuos5_led_attr_group = {
.attrs = intuos5_led_attrs,
};

+struct wacom_sysfs_group_devres {
+ struct attribute_group *group;
+ struct kobject *root;
+};
+
+static void wacom_devm_sysfs_group_release(struct device *dev, void *res)
+{
+ struct wacom_sysfs_group_devres *devres = res;
+ struct kobject *kobj = devres->root;
+
+ dev_dbg(dev, "%s: dropping reference to %s\n",
+ __func__, devres->group->name);
+ sysfs_remove_group(kobj, devres->group);
+}
+
+static int wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct attribute_group *group)
+{
+ struct wacom_sysfs_group_devres *devres;
+ int error;
+
+ devres = devres_alloc(wacom_devm_sysfs_group_release,
+ sizeof(struct wacom_sysfs_group_devres),
+ GFP_KERNEL);
+ if (!devres)
+ return -ENOMEM;
+
+ devres->group = group;
+ devres->root = &wacom->intf->dev.kobj;
+
+ error = sysfs_create_group(devres->root, group);
+ if (error)
+ return error;
+
+ devres_add(&wacom->intf->dev, devres);
+
+ return 0;
+}
+
static int wacom_initialize_leds(struct wacom *wacom)
{
int error;
@@ -668,8 +707,9 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.select[1] = 0;
wacom->led.llv = 10;
wacom->led.hlv = 20;
- error = sysfs_create_group(&wacom->intf->dev.kobj,
- &intuos4_led_attr_group);
+
+ error = wacom_devm_sysfs_create_group(wacom,
+ &intuos4_led_attr_group);
break;

case WACOM_24HD:
@@ -678,8 +718,9 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.select[1] = 0;
wacom->led.llv = 0;
wacom->led.hlv = 0;
- error = sysfs_create_group(&wacom->intf->dev.kobj,
- &cintiq_led_attr_group);
+
+ error = wacom_devm_sysfs_create_group(wacom,
+ &cintiq_led_attr_group);
break;

case INTUOS5S:
@@ -693,8 +734,8 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.llv = 32;
wacom->led.hlv = 0;

- error = sysfs_create_group(&wacom->intf->dev.kobj,
- &intuos5_led_attr_group);
+ error = wacom_devm_sysfs_create_group(wacom,
+ &intuos5_led_attr_group);
break;

default:
@@ -707,47 +748,10 @@ static int wacom_initialize_leds(struct wacom *wacom)
return error;
}
wacom_led_control(wacom);
- wacom->led_initialized = true;

return 0;
}

-static void wacom_destroy_leds(struct wacom *wacom)
-{
- if (!wacom->led_initialized)
- return;
-
- wacom->led_initialized = false;
-
- if (wacom->wacom_wac.features.device_type != BTN_TOOL_PEN)
- return;
-
- switch (wacom->wacom_wac.features.type) {
- case INTUOS4S:
- case INTUOS4:
- case INTUOS4L:
- sysfs_remove_group(&wacom->intf->dev.kobj,
- &intuos4_led_attr_group);
- break;
-
- case WACOM_24HD:
- case WACOM_21UX2:
- sysfs_remove_group(&wacom->intf->dev.kobj,
- &cintiq_led_attr_group);
- break;
-
- case INTUOS5S:
- case INTUOS5:
- case INTUOS5L:
- case INTUOSPS:
- case INTUOSPM:
- case INTUOSPL:
- sysfs_remove_group(&wacom->intf->dev.kobj,
- &intuos5_led_attr_group);
- break;
- }
-}
-
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
@@ -852,7 +856,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i

error = input_register_device(input_dev);
if (error)
- goto fail5;
+ goto fail4;

/* Note that if query fails it is not a hard failure */
wacom_query_tablet_data(intf, features);
@@ -860,7 +864,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
usb_set_intfdata(intf, wacom);
return 0;

- fail5: wacom_destroy_leds(wacom);
fail4: wacom_remove_shared_data(wacom_wac);
fail3: usb_free_urb(wacom->irq);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
@@ -881,7 +884,6 @@ static void wacom_disconnect(struct usb_interface *intf)

usb_kill_urb(wacom->irq);
input_unregister_device(wacom->wacom_wac.input);
- wacom_destroy_leds(wacom);
usb_free_urb(wacom->irq);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
usb_buffer_free(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
diff --git a/2.6.36/wacom.h b/2.6.36/wacom.h
index e4ae477..01a9350 100644
--- a/2.6.36/wacom.h
+++ b/2.6.36/wacom.h
@@ -129,7 +129,6 @@ struct wacom {
u8 hlv; /* status led brightness button pressed */
u8 img_lum; /* OLED matrix display brightness */
} led;
- bool led_initialized;
};

extern const struct usb_device_id wacom_ids[];
diff --git a/2.6.36/wacom_sys.c b/2.6.36/wacom_sys.c
index b8294dd..b641c9f 100644
--- a/2.6.36/wacom_sys.c
+++ b/2.6.36/wacom_sys.c
@@ -738,6 +738,45 @@ static struct attribute_group intuos5_led_attr_group = {
.attrs = intuos5_led_attrs,
};

+struct wacom_sysfs_group_devres {
+ struct attribute_group *group;
+ struct kobject *root;
+};
+
+static void wacom_devm_sysfs_group_release(struct device *dev, void *res)
+{
+ struct wacom_sysfs_group_devres *devres = res;
+ struct kobject *kobj = devres->root;
+
+ dev_dbg(dev, "%s: dropping reference to %s\n",
+ __func__, devres->group->name);
+ sysfs_remove_group(kobj, devres->group);
+}
+
+static int wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct attribute_group *group)
+{
+ struct wacom_sysfs_group_devres *devres;
+ int error;
+
+ devres = devres_alloc(wacom_devm_sysfs_group_release,
+ sizeof(struct wacom_sysfs_group_devres),
+ GFP_KERNEL);
+ if (!devres)
+ return -ENOMEM;
+
+ devres->group = group;
+ devres->root = &wacom->intf->dev.kobj;
+
+ error = sysfs_create_group(devres->root, group);
+ if (error)
+ return error;
+
+ devres_add(&wacom->intf->dev, devres);
+
+ return 0;
+}
+
static int wacom_initialize_leds(struct wacom *wacom)
{
int error;
@@ -755,8 +794,9 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.llv = 10;
wacom->led.hlv = 20;
wacom->led.img_lum = 10;
- error = sysfs_create_group(&wacom->intf->dev.kobj,
- &intuos4_led_attr_group);
+
+ error = wacom_devm_sysfs_create_group(wacom,
+ &intuos4_led_attr_group);
break;

case WACOM_24HD:
@@ -766,8 +806,9 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.llv = 0;
wacom->led.hlv = 0;
wacom->led.img_lum = 0;
- error = sysfs_create_group(&wacom->intf->dev.kobj,
- &cintiq_led_attr_group);
+
+ error = wacom_devm_sysfs_create_group(wacom,
+ &cintiq_led_attr_group);
break;

case INTUOS5S:
@@ -782,8 +823,8 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.hlv = 0;
wacom->led.img_lum = 0;

- error = sysfs_create_group(&wacom->intf->dev.kobj,
- &intuos5_led_attr_group);
+ error = wacom_devm_sysfs_create_group(wacom,
+ &intuos5_led_attr_group);
break;

default:
@@ -796,47 +837,10 @@ static int wacom_initialize_leds(struct wacom *wacom)
return error;
}
wacom_led_control(wacom);
- wacom->led_initialized = true;

return 0;
}

-static void wacom_destroy_leds(struct wacom *wacom)
-{
- if (!wacom->led_initialized)
- return;
-
- wacom->led_initialized = false;
-
- if (wacom->wacom_wac.features.device_type != BTN_TOOL_PEN)
- return;
-
- switch (wacom->wacom_wac.features.type) {
- case INTUOS4S:
- case INTUOS4:
- case INTUOS4L:
- sysfs_remove_group(&wacom->intf->dev.kobj,
- &intuos4_led_attr_group);
- break;
-
- case WACOM_24HD:
- case WACOM_21UX2:
- sysfs_remove_group(&wacom->intf->dev.kobj,
- &cintiq_led_attr_group);
- break;
-
- case INTUOS5S:
- case INTUOS5:
- case INTUOS5L:
- case INTUOSPS:
- case INTUOSPM:
- case INTUOSPL:
- sysfs_remove_group(&wacom->intf->dev.kobj,
- &intuos5_led_attr_group);
- break;
- }
-}
-
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
@@ -944,7 +948,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i

error = input_register_device(input_dev);
if (error)
- goto fail5;
+ goto fail4;

/* Note that if query fails it is not a hard failure */
wacom_query_tablet_data(intf, features);
@@ -952,7 +956,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
usb_set_intfdata(intf, wacom);
return 0;

- fail5: wacom_destroy_leds(wacom);
fail4: wacom_remove_shared_data(wacom_wac);
fail3: usb_free_urb(wacom->irq);
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
@@ -969,7 +972,6 @@ static void wacom_disconnect(struct usb_interface *intf)

usb_kill_urb(wacom->irq);
input_unregister_device(wacom->wacom_wac.input);
- wacom_destroy_leds(wacom);
usb_free_urb(wacom->irq);
usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
wacom->wacom_wac.data, wacom->data_dma);
diff --git a/2.6.38/wacom.h b/2.6.38/wacom.h
index d21d786..c8941c9 100644
--- a/2.6.38/wacom.h
+++ b/2.6.38/wacom.h
@@ -134,7 +134,6 @@ struct wacom {
u8 hlv; /* status led brightness button pressed (1..127) */
u8 img_lum; /* OLED matrix display brightness */
} led;
- bool led_initialized;
struct power_supply battery;
struct kobject *remote_dir;
struct attribute_group remote_group[5];
diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 1f2a850..a41104e 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1035,6 +1035,45 @@ static struct attribute_group intuos5_led_attr_group = {
.attrs = intuos5_led_attrs,
};

+struct wacom_sysfs_group_devres {
+ struct attribute_group *group;
+ struct kobject *root;
+};
+
+static void wacom_devm_sysfs_group_release(struct device *dev, void *res)
+{
+ struct wacom_sysfs_group_devres *devres = res;
+ struct kobject *kobj = devres->root;
+
+ dev_dbg(dev, "%s: dropping reference to %s\n",
+ __func__, devres->group->name);
+ sysfs_remove_group(kobj, devres->group);
+}
+
+static int wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct attribute_group *group)
+{
+ struct wacom_sysfs_group_devres *devres;
+ int error;
+
+ devres = devres_alloc(wacom_devm_sysfs_group_release,
+ sizeof(struct wacom_sysfs_group_devres),
+ GFP_KERNEL);
+ if (!devres)
+ return -ENOMEM;
+
+ devres->group = group;
+ devres->root = &wacom->intf->dev.kobj;
+
+ error = sysfs_create_group(devres->root, group);
+ if (error)
+ return error;
+
+ devres_add(&wacom->intf->dev, devres);
+
+ return 0;
+}
+
static int wacom_initialize_leds(struct wacom *wacom)
{
int error;
@@ -1052,8 +1091,9 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.llv = 10;
wacom->led.hlv = 20;
wacom->led.img_lum = 10;
- error = sysfs_create_group(&wacom->intf->dev.kobj,
- &intuos4_led_attr_group);
+
+ error = wacom_devm_sysfs_create_group(wacom,
+ &intuos4_led_attr_group);
break;

case WACOM_24HD:
@@ -1064,8 +1104,8 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.hlv = 0;
wacom->led.img_lum = 0;

- error = sysfs_create_group(&wacom->intf->dev.kobj,
- &cintiq_led_attr_group);
+ error = wacom_devm_sysfs_create_group(wacom,
+ &cintiq_led_attr_group);
break;

case INTUOS5S:
@@ -1080,8 +1120,8 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.hlv = 0;
wacom->led.img_lum = 0;

- error = sysfs_create_group(&wacom->intf->dev.kobj,
- &intuos5_led_attr_group);
+ error = wacom_devm_sysfs_create_group(wacom,
+ &intuos5_led_attr_group);
break;

default:
@@ -1094,47 +1134,10 @@ static int wacom_initialize_leds(struct wacom *wacom)
return error;
}
wacom_led_control(wacom);
- wacom->led_initialized = true;

return 0;
}

-static void wacom_destroy_leds(struct wacom *wacom)
-{
- if (!wacom->led_initialized)
- return;
-
- wacom->led_initialized = false;
-
- if (wacom->wacom_wac.features.device_type != BTN_TOOL_PEN)
- return;
-
- switch (wacom->wacom_wac.features.type) {
- case INTUOS4S:
- case INTUOS4:
- case INTUOS4L:
- sysfs_remove_group(&wacom->intf->dev.kobj,
- &intuos4_led_attr_group);
- break;
-
- case WACOM_24HD:
- case WACOM_21UX2:
- sysfs_remove_group(&wacom->intf->dev.kobj,
- &cintiq_led_attr_group);
- break;
-
- case INTUOS5S:
- case INTUOS5:
- case INTUOS5L:
- case INTUOSPS:
- case INTUOSPM:
- case INTUOSPL:
- sysfs_remove_group(&wacom->intf->dev.kobj,
- &intuos5_led_attr_group);
- break;
- }
-}
-
static enum power_supply_property wacom_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_STATUS,
@@ -1509,13 +1512,11 @@ static void wacom_wireless_work(struct work_struct *work)
/* Stylus interface */
wacom1 = usb_get_intfdata(usbdev->config->interface[1]);
wacom_wac1 = &(wacom1->wacom_wac);
- wacom_destroy_leds(wacom1);
wacom_unregister_inputs(wacom1);

/* Touch interface */
wacom2 = usb_get_intfdata(usbdev->config->interface[2]);
wacom_wac2 = &(wacom2->wacom_wac);
- wacom_destroy_leds(wacom2);
wacom_unregister_inputs(wacom2);

if (wacom_wac->pid == 0) {
@@ -1594,9 +1595,7 @@ static void wacom_wireless_work(struct work_struct *work)
return;

fail:
- wacom_destroy_leds(wacom1);
wacom_unregister_inputs(wacom1);
- wacom_destroy_leds(wacom2);
wacom_unregister_inputs(wacom2);
return;
}
@@ -1727,7 +1726,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (wacom->wacom_wac.features.type == REMOTE) {
error = wacom_initialize_remote(wacom);
if (error)
- goto fail_remote;
+ goto fail4;
}

if ((wacom_wac->features.type == INTUOSHT ||
@@ -1740,7 +1739,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
}

return 0;
- fail_remote: wacom_destroy_leds(wacom);
+
fail4: wacom_remove_shared_data(wacom_wac);
fail3: usb_free_urb(wacom->irq);
wacom_destroy_battery(wacom);
@@ -1759,7 +1758,6 @@ static void wacom_disconnect(struct usb_interface *intf)
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
kobject_put(wacom->remote_dir);
- wacom_destroy_leds(wacom);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
usb_free_urb(wacom->irq);
diff --git a/3.17/wacom.h b/3.17/wacom.h
index 9f94378..c5162c1 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -138,7 +138,6 @@ struct wacom {
u8 hlv; /* status led brightness button pressed (1..127) */
u8 img_lum; /* OLED matrix display brightness */
} led;
- bool led_initialized;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
struct power_supply *battery;
struct power_supply *ac;
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index a5c2f44..f4e1fd9 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -913,6 +913,45 @@ static struct attribute_group intuos5_led_attr_group = {
.attrs = intuos5_led_attrs,
};

+struct wacom_sysfs_group_devres {
+ struct attribute_group *group;
+ struct kobject *root;
+};
+
+static void wacom_devm_sysfs_group_release(struct device *dev, void *res)
+{
+ struct wacom_sysfs_group_devres *devres = res;
+ struct kobject *kobj = devres->root;
+
+ dev_dbg(dev, "%s: dropping reference to %s\n",
+ __func__, devres->group->name);
+ sysfs_remove_group(kobj, devres->group);
+}
+
+static int wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct attribute_group *group)
+{
+ struct wacom_sysfs_group_devres *devres;
+ int error;
+
+ devres = devres_alloc(wacom_devm_sysfs_group_release,
+ sizeof(struct wacom_sysfs_group_devres),
+ GFP_KERNEL);
+ if (!devres)
+ return -ENOMEM;
+
+ devres->group = group;
+ devres->root = &wacom->hdev->dev.kobj;
+
+ error = sysfs_create_group(devres->root, group);
+ if (error)
+ return error;
+
+ devres_add(&wacom->hdev->dev, devres);
+
+ return 0;
+}
+
static int wacom_initialize_leds(struct wacom *wacom)
{
int error;
@@ -931,8 +970,8 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.llv = 10;
wacom->led.hlv = 20;
wacom->led.img_lum = 10;
- error = sysfs_create_group(&wacom->hdev->dev.kobj,
- &intuos4_led_attr_group);
+ error = wacom_devm_sysfs_create_group(wacom,
+ &intuos4_led_attr_group);
break;

case WACOM_24HD:
@@ -943,8 +982,8 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.hlv = 0;
wacom->led.img_lum = 0;

- error = sysfs_create_group(&wacom->hdev->dev.kobj,
- &cintiq_led_attr_group);
+ error = wacom_devm_sysfs_create_group(wacom,
+ &cintiq_led_attr_group);
break;

case INTUOS5S:
@@ -959,8 +998,8 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.hlv = 0;
wacom->led.img_lum = 0;

- error = sysfs_create_group(&wacom->hdev->dev.kobj,
- &intuos5_led_attr_group);
+ error = wacom_devm_sysfs_create_group(wacom,
+ &intuos5_led_attr_group);
break;

default:
@@ -973,48 +1012,10 @@ static int wacom_initialize_leds(struct wacom *wacom)
return error;
}
wacom_led_control(wacom);
- wacom->led_initialized = true;

return 0;
}

-static void wacom_destroy_leds(struct wacom *wacom)
-{
- if (!wacom->led_initialized)
- return;
-
- if (!(wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD))
- return;
-
- wacom->led_initialized = false;
-
- switch (wacom->wacom_wac.features.type) {
- case INTUOS4S:
- case INTUOS4:
- case INTUOS4WL:
- case INTUOS4L:
- sysfs_remove_group(&wacom->hdev->dev.kobj,
- &intuos4_led_attr_group);
- break;
-
- case WACOM_24HD:
- case WACOM_21UX2:
- sysfs_remove_group(&wacom->hdev->dev.kobj,
- &cintiq_led_attr_group);
- break;
-
- case INTUOS5S:
- case INTUOS5:
- case INTUOS5L:
- case INTUOSPS:
- case INTUOSPM:
- case INTUOSPL:
- sysfs_remove_group(&wacom->hdev->dev.kobj,
- &intuos5_led_attr_group);
- break;
- }
-}
-
static enum power_supply_property wacom_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_STATUS,
@@ -1777,7 +1778,6 @@ fail_quirks:
fail_hw_start:
kobject_put(wacom->remote_dir);
fail_remote:
- wacom_destroy_leds(wacom);
fail_leds:
fail_register_inputs:
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
@@ -1814,14 +1814,12 @@ static void wacom_wireless_work(struct work_struct *work)
hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
wacom1 = hid_get_drvdata(hdev1);
wacom_wac1 = &(wacom1->wacom_wac);
- wacom_destroy_leds(wacom1);
wacom_release_resources(wacom1);

/* Touch interface */
hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
wacom2 = hid_get_drvdata(hdev2);
wacom_wac2 = &(wacom2->wacom_wac);
- wacom_destroy_leds(wacom2);
wacom_release_resources(wacom2);

if (wacom_wac->pid == 0) {
@@ -1876,9 +1874,7 @@ static void wacom_wireless_work(struct work_struct *work)
return;

fail:
- wacom_destroy_leds(wacom1);
wacom_release_resources(wacom1);
- wacom_destroy_leds(wacom2);
wacom_release_resources(wacom2);
return;
}
@@ -1968,7 +1964,6 @@ static void wacom_remove(struct hid_device *hdev)
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
kobject_put(wacom->remote_dir);
- wacom_destroy_leds(wacom);
if (hdev->bus == BUS_BLUETOOTH)
device_remove_file(&hdev->dev, &dev_attr_speed);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
diff --git a/3.7/wacom.h b/3.7/wacom.h
index fd039dd..1666882 100644
--- a/3.7/wacom.h
+++ b/3.7/wacom.h
@@ -130,7 +130,6 @@ struct wacom {
u8 hlv; /* status led brightness button pressed (1..127) */
u8 img_lum; /* OLED matrix display brightness */
} led;
- bool led_initialized;
struct power_supply battery;
struct kobject *remote_dir;
struct attribute_group remote_group[5];
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index 33b7ee7..7948ab8 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1034,6 +1034,45 @@ static struct attribute_group intuos5_led_attr_group = {
.attrs = intuos5_led_attrs,
};

+struct wacom_sysfs_group_devres {
+ struct attribute_group *group;
+ struct kobject *root;
+};
+
+static void wacom_devm_sysfs_group_release(struct device *dev, void *res)
+{
+ struct wacom_sysfs_group_devres *devres = res;
+ struct kobject *kobj = devres->root;
+
+ dev_dbg(dev, "%s: dropping reference to %s\n",
+ __func__, devres->group->name);
+ sysfs_remove_group(kobj, devres->group);
+}
+
+static int wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct attribute_group *group)
+{
+ struct wacom_sysfs_group_devres *devres;
+ int error;
+
+ devres = devres_alloc(wacom_devm_sysfs_group_release,
+ sizeof(struct wacom_sysfs_group_devres),
+ GFP_KERNEL);
+ if (!devres)
+ return -ENOMEM;
+
+ devres->group = group;
+ devres->root = &wacom->intf->dev.kobj;
+
+ error = sysfs_create_group(devres->root, group);
+ if (error)
+ return error;
+
+ devres_add(&wacom->intf->dev, devres);
+
+ return 0;
+}
+
static int wacom_initialize_leds(struct wacom *wacom)
{
int error;
@@ -1051,8 +1090,9 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.llv = 10;
wacom->led.hlv = 20;
wacom->led.img_lum = 10;
- error = sysfs_create_group(&wacom->intf->dev.kobj,
- &intuos4_led_attr_group);
+
+ error = wacom_devm_sysfs_create_group(wacom,
+ &intuos4_led_attr_group);
break;

case WACOM_24HD:
@@ -1063,8 +1103,8 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.hlv = 0;
wacom->led.img_lum = 0;

- error = sysfs_create_group(&wacom->intf->dev.kobj,
- &cintiq_led_attr_group);
+ error = wacom_devm_sysfs_create_group(wacom,
+ &cintiq_led_attr_group);
break;

case INTUOS5S:
@@ -1079,8 +1119,8 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.hlv = 0;
wacom->led.img_lum = 0;

- error = sysfs_create_group(&wacom->intf->dev.kobj,
- &intuos5_led_attr_group);
+ error = wacom_devm_sysfs_create_group(wacom,
+ &intuos5_led_attr_group);
break;

default:
@@ -1093,48 +1133,10 @@ static int wacom_initialize_leds(struct wacom *wacom)
return error;
}
wacom_led_control(wacom);
- wacom->led_initialized = true;

return 0;
}

-static void wacom_destroy_leds(struct wacom *wacom)
-{
-
- if (!wacom->led_initialized)
- return;
-
- wacom->led_initialized = false;
-
- if (wacom->wacom_wac.features.device_type != BTN_TOOL_PEN)
- return;
-
- switch (wacom->wacom_wac.features.type) {
- case INTUOS4S:
- case INTUOS4:
- case INTUOS4L:
- sysfs_remove_group(&wacom->intf->dev.kobj,
- &intuos4_led_attr_group);
- break;
-
- case WACOM_24HD:
- case WACOM_21UX2:
- sysfs_remove_group(&wacom->intf->dev.kobj,
- &cintiq_led_attr_group);
- break;
-
- case INTUOS5S:
- case INTUOS5:
- case INTUOS5L:
- case INTUOSPS:
- case INTUOSPM:
- case INTUOSPL:
- sysfs_remove_group(&wacom->intf->dev.kobj,
- &intuos5_led_attr_group);
- break;
- }
-}
-
static enum power_supply_property wacom_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_STATUS,
@@ -1506,13 +1508,11 @@ static void wacom_wireless_work(struct work_struct *work)
/* Stylus interface */
wacom1 = usb_get_intfdata(usbdev->config->interface[1]);
wacom_wac1 = &(wacom1->wacom_wac);
- wacom_destroy_leds(wacom1);
wacom_unregister_inputs(wacom1);

/* Touch interface */
wacom2 = usb_get_intfdata(usbdev->config->interface[2]);
wacom_wac2 = &(wacom2->wacom_wac);
- wacom_destroy_leds(wacom2);
wacom_unregister_inputs(wacom2);

if (wacom_wac->pid == 0) {
@@ -1591,9 +1591,7 @@ static void wacom_wireless_work(struct work_struct *work)
return;

fail:
- wacom_destroy_leds(wacom1);
wacom_unregister_inputs(wacom1);
- wacom_destroy_leds(wacom2);
wacom_unregister_inputs(wacom2);
return;
}
@@ -1724,7 +1722,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (wacom->wacom_wac.features.type == REMOTE) {
error = wacom_initialize_remote(wacom);
if (error)
- goto fail_remote;
+ goto fail4;
}

if ((wacom_wac->features.type == INTUOSHT ||
@@ -1738,8 +1736,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i

return 0;

- fail_remote:
- wacom_destroy_leds(wacom);
fail4: wacom_remove_shared_data(wacom_wac);
fail3: usb_free_urb(wacom->irq);
wacom_destroy_battery(wacom);
@@ -1758,7 +1754,6 @@ static void wacom_disconnect(struct usb_interface *intf)
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
kobject_put(wacom->remote_dir);
- wacom_destroy_leds(wacom);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
usb_free_urb(wacom->irq);
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:04 UTC
Permalink
We need to add an action to ensure wacom->led.groups is null when
wacom_led_control() gets called after the resources has been freed.

This also prevents to send a LED command when there is no support
from the device.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (a50aac7)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (4f74881)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom.h | 8 +++--
3.17/wacom_sys.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++--------
3.17/wacom_wac.c | 2 +-
3 files changed, 90 insertions(+), 17 deletions(-)

diff --git a/3.17/wacom.h b/3.17/wacom.h
index c5162c1..e7b05da 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -124,6 +124,10 @@ enum wacom_worker {
WACOM_WORKER_BATTERY,
};

+struct wacom_group_leds {
+ u8 select; /* status led selector (0..3) */
+};
+
struct wacom {
struct usb_device *usbdev;
struct usb_interface *intf;
@@ -132,8 +136,8 @@ struct wacom {
struct mutex lock;
struct work_struct wireless_work;
struct work_struct battery_work;
- struct wacom_led {
- u8 select[5]; /* status led selector (0..3) */
+ struct wacom_leds {
+ struct wacom_group_leds *groups;
u8 llv; /* status led brightness no button (1..127) */
u8 hlv; /* status led brightness button pressed (1..127) */
u8 img_lum; /* OLED matrix display brightness */
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index c26a1b4..a899cf2 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -651,6 +651,9 @@ static int wacom_led_control(struct wacom *wacom)
unsigned char report_id = WAC_CMD_LED_CONTROL;
int buf_size = 9;

+ if (!wacom->led.groups)
+ return -ENOTSUPP;
+
if (wacom->wacom_wac.pid) { /* wireless connected */
report_id = WAC_CMD_WL_LED_CONTROL;
buf_size = 13;
@@ -666,7 +669,7 @@ static int wacom_led_control(struct wacom *wacom)
* one of four values:
* 0 = Low; 1 = Medium; 2 = High; 3 = Off
*/
- int ring_led = wacom->led.select[0] & 0x03;
+ int ring_led = wacom->led.groups[0].select & 0x03;
int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03;
int crop_lum = 0;
unsigned char led_bits = (crop_lum << 4) | (ring_lum << 2) | (ring_led);
@@ -681,11 +684,11 @@ static int wacom_led_control(struct wacom *wacom)
buf[1] = led_bits;
}
else {
- int led = wacom->led.select[0] | 0x4;
+ int led = wacom->led.groups[0].select | 0x4;

if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
wacom->wacom_wac.features.type == WACOM_24HD)
- led |= (wacom->led.select[1] << 4) | 0x40;
+ led |= (wacom->led.groups[1].select << 4) | 0x40;

buf[0] = report_id;
buf[1] = led;
@@ -757,7 +760,7 @@ static ssize_t wacom_led_select_store(struct device *dev, int set_id,

mutex_lock(&wacom->lock);

- wacom->led.select[set_id] = id & 0x3;
+ wacom->led.groups[set_id].select = id & 0x3;
err = wacom_led_control(wacom);

mutex_unlock(&wacom->lock);
@@ -777,7 +780,7 @@ static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \
struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
struct wacom *wacom = hid_get_drvdata(hdev); \
return scnprintf(buf, PAGE_SIZE, "%d\n", \
- wacom->led.select[SET_ID]); \
+ wacom->led.groups[SET_ID].select); \
} \
static DEVICE_ATTR(status_led##SET_ID##_select, DEV_ATTR_RW_PERM, \
wacom_led##SET_ID##_select_show, \
@@ -959,6 +962,47 @@ static int wacom_devm_sysfs_create_group(struct wacom *wacom,
return 0;
}

+static void wacom_led_groups_release(void *data)
+{
+ struct wacom *wacom = data;
+
+ wacom->led.groups = NULL;
+}
+
+static inline int devm_add_action_or_reset(struct device *dev,
+ void (*action)(void *), void *data)
+{
+ int ret;
+
+ ret = devm_add_action(dev, action, data);
+ if (ret)
+ action(data);
+
+ return ret;
+}
+
+static int wacom_led_groups_allocate(struct wacom *wacom, int count)
+{
+ struct wacom_group_leds *groups;
+ int error;
+
+ groups = devm_kzalloc(&wacom->hdev->dev,
+ sizeof(struct wacom_group_leds) * count,
+ GFP_KERNEL);
+ if (!groups)
+ return -ENOMEM;
+
+ error = devm_add_action_or_reset(&wacom->hdev->dev,
+ wacom_led_groups_release,
+ wacom);
+ if (error)
+ return error;
+
+ wacom->led.groups = groups;
+
+ return 0;
+}
+
static int wacom_initialize_leds(struct wacom *wacom)
{
int error;
@@ -972,23 +1016,34 @@ static int wacom_initialize_leds(struct wacom *wacom)
case INTUOS4:
case INTUOS4WL:
case INTUOS4L:
- wacom->led.select[0] = 0;
- wacom->led.select[1] = 0;
wacom->led.llv = 10;
wacom->led.hlv = 20;
wacom->led.img_lum = 10;
+
+ error = wacom_led_groups_allocate(wacom, 1);
+ if (error) {
+ hid_err(wacom->hdev,
+ "cannot create leds err: %d\n", error);
+ return error;
+ }
+
error = wacom_devm_sysfs_create_group(wacom,
&intuos4_led_attr_group);
break;

case WACOM_24HD:
case WACOM_21UX2:
- wacom->led.select[0] = 0;
- wacom->led.select[1] = 0;
wacom->led.llv = 0;
wacom->led.hlv = 0;
wacom->led.img_lum = 0;

+ error = wacom_led_groups_allocate(wacom, 2);
+ if (error) {
+ hid_err(wacom->hdev,
+ "cannot create leds err: %d\n", error);
+ return error;
+ }
+
error = wacom_devm_sysfs_create_group(wacom,
&cintiq_led_attr_group);
break;
@@ -999,16 +1054,30 @@ static int wacom_initialize_leds(struct wacom *wacom)
case INTUOSPS:
case INTUOSPM:
case INTUOSPL:
- wacom->led.select[0] = 0;
- wacom->led.select[1] = 0;
wacom->led.llv = 32;
wacom->led.hlv = 0;
wacom->led.img_lum = 0;

+ error = wacom_led_groups_allocate(wacom, 1);
+ if (error) {
+ hid_err(wacom->hdev,
+ "cannot create leds err: %d\n", error);
+ return error;
+ }
+
error = wacom_devm_sysfs_create_group(wacom,
&intuos5_led_attr_group);
break;

+ case REMOTE:
+ error = wacom_led_groups_allocate(wacom, 5);
+ if (error) {
+ hid_err(wacom->hdev,
+ "cannot create leds err: %d\n", error);
+ return error;
+ }
+ return 0;
+
default:
return 0;
}
@@ -1244,7 +1313,7 @@ static ssize_t wacom_show_remote_mode(struct kobject *kobj,
struct wacom *wacom = hid_get_drvdata(hdev);
u8 mode;

- mode = wacom->led.select[index];
+ mode = wacom->led.groups[index].select;
if (mode >= 0 && mode < 3)
return snprintf(buf, PAGE_SIZE, "%d\n", mode);
else
@@ -1312,7 +1381,7 @@ void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (wacom_wac->serial[i] == serial) {
wacom_wac->serial[i] = 0;
- wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
+ wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
if (wacom->remote_group[i].name) {
sysfs_remove_group(wacom->remote_dir,
&wacom->remote_group[i]);
@@ -1409,7 +1478,7 @@ static int wacom_initialize_remote(struct wacom *wacom)
}

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
+ wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
wacom_wac->serial[i] = 0;
}

diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index af214a3..51dec4a 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -814,7 +814,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (wacom_wac->serial[i] == serial)
- wacom->led.select[i] = touch_ring_mode;
+ wacom->led.groups[i].select = touch_ring_mode;
}

if (!WACOM_POWERSUPPLY_DEVICE(wacom->battery) &&
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:02 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

We started switching the driver to devres, so we should use it as much
as possible.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (19b6433)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (1bdda0a)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.30/wacom_sys.c | 4 +---
2.6.36/wacom_sys.c | 4 +---
2.6.38/wacom_sys.c | 5 ++---
3.17/wacom_sys.c | 4 +---
3.7/wacom_sys.c | 5 ++---
5 files changed, 7 insertions(+), 15 deletions(-)

diff --git a/2.6.30/wacom_sys.c b/2.6.30/wacom_sys.c
index 4283976..517e293 100644
--- a/2.6.30/wacom_sys.c
+++ b/2.6.30/wacom_sys.c
@@ -770,7 +770,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (intf->cur_altsetting->desc.bNumEndpoints < 1)
return -EINVAL;

- wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
+ wacom = devm_kzalloc(&dev->dev, sizeof(struct wacom), GFP_KERNEL);
input_dev = input_allocate_device();
if (!wacom || !input_dev) {
error = -ENOMEM;
@@ -872,7 +872,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
#endif
fail1: input_free_device(input_dev);
- kfree(wacom);
return error;
}

@@ -893,7 +892,6 @@ static void wacom_disconnect(struct usb_interface *intf)
wacom->wacom_wac.data, wacom->data_dma);
#endif
wacom_remove_shared_data(&wacom->wacom_wac);
- kfree(wacom);
}

static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
diff --git a/2.6.36/wacom_sys.c b/2.6.36/wacom_sys.c
index b641c9f..55e54dc 100644
--- a/2.6.36/wacom_sys.c
+++ b/2.6.36/wacom_sys.c
@@ -858,7 +858,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (intf->cur_altsetting->desc.bNumEndpoints < 1)
return -EINVAL;

- wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
+ wacom = devm_kzalloc(&dev->dev, sizeof(struct wacom), GFP_KERNEL);
input_dev = input_allocate_device();
if (!wacom || !input_dev) {
error = -ENOMEM;
@@ -960,7 +960,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
fail3: usb_free_urb(wacom->irq);
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
fail1: input_free_device(input_dev);
- kfree(wacom);
return error;
}

@@ -976,7 +975,6 @@ static void wacom_disconnect(struct usb_interface *intf)
usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
wacom->wacom_wac.data, wacom->data_dma);
wacom_remove_shared_data(&wacom->wacom_wac);
- kfree(wacom);
}

static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 0c70faf..2ef93fc 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1630,7 +1630,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (intf->cur_altsetting->desc.bNumEndpoints < 1)
return -EINVAL;

- wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
+ wacom = devm_kzalloc(&dev->dev, sizeof(struct wacom), GFP_KERNEL);
if (!wacom)
return -ENOMEM;

@@ -1743,7 +1743,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
fail3: usb_free_urb(wacom->irq);
wacom_destroy_battery(wacom);
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
- fail1: kfree(wacom);
+ fail1:
return error;
}

@@ -1771,7 +1771,6 @@ static void wacom_disconnect(struct usb_interface *intf)
wacom->wacom_wac.data, wacom->data_dma);
wacom_remove_shared_data(&wacom->wacom_wac);
kfree(wacom->wacom_wac.slots);
- kfree(wacom);
}

static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 6afa06d..070cdaf 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1895,7 +1895,7 @@ static int wacom_probe(struct hid_device *hdev,
/* hid-core sets this quirk for the boot interface */
hdev->quirks &= ~HID_QUIRK_NOGET;

- wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
+ wacom = devm_kzalloc(&hdev->dev, sizeof(struct wacom), GFP_KERNEL);
if (!wacom)
return -ENOMEM;

@@ -1943,7 +1943,6 @@ static int wacom_probe(struct hid_device *hdev,

fail_type:
fail_parse:
- kfree(wacom);
hid_set_drvdata(hdev, NULL);
return error;
}
@@ -1970,7 +1969,6 @@ static void wacom_remove(struct hid_device *hdev)
wacom_remove_shared_data(wacom);

hid_set_drvdata(hdev, NULL);
- kfree(wacom);
}

#ifdef CONFIG_PM
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index b3273f3..d264c62 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1626,7 +1626,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (intf->cur_altsetting->desc.bNumEndpoints < 1)
return -EINVAL;

- wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
+ wacom = devm_kzalloc(&dev->dev, sizeof(struct wacom), GFP_KERNEL);
if (!wacom)
return -ENOMEM;

@@ -1739,7 +1739,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
fail3: usb_free_urb(wacom->irq);
wacom_destroy_battery(wacom);
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
- fail1: kfree(wacom);
+ fail1:
return error;
}

@@ -1766,7 +1766,6 @@ static void wacom_disconnect(struct usb_interface *intf)
usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
wacom->wacom_wac.data, wacom->data_dma);
wacom_remove_shared_data(&wacom->wacom_wac);
- kfree(wacom);
}

static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:03 UTC
Permalink
wacom_release_shared_data() and wacom_remove_shared_data() are moved up
so they can be referenced in wacom_add_shared_data().

There is no point in explicitly setting wacom_wac1->shared->type to 0 in
wacom_wireless_work() (plus this would give an oops).

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (1c817c8)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (561e444)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom_sys.c | 72 ++++++++++++++++++++++++++++++--------------------------
1 file changed, 39 insertions(+), 33 deletions(-)

diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 070cdaf..c26a1b4 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -571,6 +571,38 @@ static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
return NULL;
}

+static void wacom_release_shared_data(struct kref *kref)
+{
+ struct wacom_hdev_data *data =
+ container_of(kref, struct wacom_hdev_data, kref);
+
+ mutex_lock(&wacom_udev_list_lock);
+ list_del(&data->list);
+ mutex_unlock(&wacom_udev_list_lock);
+
+ kfree(data);
+}
+
+static void wacom_remove_shared_data(void *res)
+{
+ struct wacom *wacom = res;
+ struct wacom_hdev_data *data;
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+
+ if (wacom_wac->shared) {
+ data = container_of(wacom_wac->shared, struct wacom_hdev_data,
+ shared);
+
+ if (wacom_wac->shared->touch == wacom->hdev)
+ wacom_wac->shared->touch = NULL;
+ else if (wacom_wac->shared->pen == wacom->hdev)
+ wacom_wac->shared->pen = NULL;
+
+ kref_put(&data->kref, wacom_release_shared_data);
+ wacom_wac->shared = NULL;
+ }
+}
+
static int wacom_add_shared_data(struct hid_device *hdev)
{
struct wacom *wacom = hid_get_drvdata(hdev);
@@ -595,6 +627,13 @@ static int wacom_add_shared_data(struct hid_device *hdev)

wacom_wac->shared = &data->shared;

+ retval = devm_add_action(&hdev->dev, wacom_remove_shared_data, wacom);
+ if (retval) {
+ mutex_unlock(&wacom_udev_list_lock);
+ wacom_remove_shared_data(wacom);
+ return retval;
+ }
+
if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)
wacom_wac->shared->touch = hdev;
else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN)
@@ -605,37 +644,6 @@ out:
return retval;
}

-static void wacom_release_shared_data(struct kref *kref)
-{
- struct wacom_hdev_data *data =
- container_of(kref, struct wacom_hdev_data, kref);
-
- mutex_lock(&wacom_udev_list_lock);
- list_del(&data->list);
- mutex_unlock(&wacom_udev_list_lock);
-
- kfree(data);
-}
-
-static void wacom_remove_shared_data(struct wacom *wacom)
-{
- struct wacom_hdev_data *data;
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
-
- if (wacom_wac->shared) {
- data = container_of(wacom_wac->shared, struct wacom_hdev_data,
- shared);
-
- if (wacom_wac->shared->touch == wacom->hdev)
- wacom_wac->shared->touch = NULL;
- else if (wacom_wac->shared->pen == wacom->hdev)
- wacom_wac->shared->pen = NULL;
-
- kref_put(&data->kref, wacom_release_shared_data);
- wacom_wac->shared = NULL;
- }
-}
-
static int wacom_led_control(struct wacom *wacom)
{
unsigned char *buf;
@@ -1782,7 +1790,6 @@ fail_register_inputs:
wacom_destroy_battery(wacom);
#endif
fail_battery:
- wacom_remove_shared_data(wacom);
fail_shared_data:
fail_parsed:
fail_allocate_inputs:
@@ -1822,7 +1829,6 @@ static void wacom_wireless_work(struct work_struct *work)

if (wacom_wac->pid == 0) {
hid_info(wacom->hdev, "wireless tablet disconnected\n");
- wacom_wac1->shared->type = 0;
} else {
const struct hid_device_id *id = wacom_ids;
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:01 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

The sysfs group was indeed removed by kobject_put(wacom->remote_dir) in
wacom_remove(), but the name of the group was never freed.

Also remove the misplaced kobject_put(wacom->remote_dir) in the error
path of wacom_remote_create_attr_group().

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (c1f5409)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (0f1b043)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom_sys.c | 8 +++++++-
3.17/wacom_sys.c | 14 ++++++--------
3.7/wacom_sys.c | 8 +++++++-
3 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index a41104e..0c70faf 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1291,7 +1291,6 @@ int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
if (error) {
dev_err(&wacom->intf->dev,
"cannot create sysfs group err: %d\n", error);
- kobject_put(wacom->remote_dir);
return error;
}

@@ -1751,12 +1750,19 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
static void wacom_disconnect(struct usb_interface *intf)
{
struct wacom *wacom = usb_get_intfdata(intf);
+ int i;

usb_set_intfdata(intf, NULL);

usb_kill_urb(wacom->irq);
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (wacom->remote_group[i].name) {
+ wacom_remote_destroy_attr_group(wacom,
+ wacom->wacom_wac.serial[i]);
+ }
+ }
kobject_put(wacom->remote_dir);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index f4e1fd9..6afa06d 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -25,7 +25,6 @@
#define WAC_CMD_RETRIES 10
#define WAC_CMD_DELETE_PAIRING 0x20
#define WAC_CMD_UNPAIR_ALL 0xFF
-#define WAC_REMOTE_SERIAL_MAX_STRLEN 9

#define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP)
#define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP)
@@ -1273,23 +1272,21 @@ DEVICE_EKR_ATTR_GROUP(4);
int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
{
int error = 0;
- char *buf;
struct wacom_wac *wacom_wac = &wacom->wacom_wac;

wacom_wac->serial[index] = serial;

- buf = kzalloc(WAC_REMOTE_SERIAL_MAX_STRLEN, GFP_KERNEL);
- if (!buf)
+ wacom->remote_group[index].name = devm_kasprintf(&wacom->hdev->dev,
+ GFP_KERNEL,
+ "%d", serial);
+ if (!wacom->remote_group[index].name)
return -ENOMEM;
- snprintf(buf, WAC_REMOTE_SERIAL_MAX_STRLEN, "%d", serial);
- wacom->remote_group[index].name = buf;

error = sysfs_create_group(wacom->remote_dir,
&wacom->remote_group[index]);
if (error) {
hid_err(wacom->hdev,
"cannot create sysfs group err: %d\n", error);
- kobject_put(wacom->remote_dir);
return error;
}

@@ -1311,7 +1308,8 @@ void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
if (wacom->remote_group[i].name) {
sysfs_remove_group(wacom->remote_dir,
&wacom->remote_group[i]);
- kfree(wacom->remote_group[i].name);
+ devm_kfree(&wacom->hdev->dev,
+ (char *)wacom->remote_group[i].name);
wacom->remote_group[i].name = NULL;
}
}
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index 7948ab8..b3273f3 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1284,7 +1284,6 @@ int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
if (error) {
dev_err(&wacom->intf->dev,
"cannot create sysfs group err: %d\n", error);
- kobject_put(wacom->remote_dir);
return error;
}

@@ -1747,12 +1746,19 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
static void wacom_disconnect(struct usb_interface *intf)
{
struct wacom *wacom = usb_get_intfdata(intf);
+ int i;

usb_set_intfdata(intf, NULL);

usb_kill_urb(wacom->irq);
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (wacom->remote_group[i].name) {
+ wacom_remote_destroy_attr_group(wacom,
+ wacom->wacom_wac.serial[i]);
+ }
+ }
kobject_put(wacom->remote_dir);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:42:56 UTC
Permalink
Looks like the battery hijacked the wireless worker. That's not fair so
use a work queue per task.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (d17d1f1)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (4f9aa64)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom.h | 21 ++++++++++++++++++---
2.6.38/wacom_sys.c | 10 ++++++----
2.6.38/wacom_wac.c | 13 +++++--------
3.17/wacom.h | 21 ++++++++++++++++++---
3.17/wacom_sys.c | 10 ++++++----
3.17/wacom_wac.c | 13 +++++--------
3.7/wacom.h | 21 ++++++++++++++++++---
3.7/wacom_sys.c | 10 ++++++----
3.7/wacom_wac.c | 13 +++++--------
9 files changed, 87 insertions(+), 45 deletions(-)

diff --git a/2.6.38/wacom.h b/2.6.38/wacom.h
index 36dbf8a..d21d786 100644
--- a/2.6.38/wacom.h
+++ b/2.6.38/wacom.h
@@ -112,6 +112,11 @@ MODULE_LICENSE(DRIVER_LICENSE);
#define USB_VENDOR_ID_WACOM 0x056a
#define USB_VENDOR_ID_LENOVO 0x17ef

+enum wacom_worker {
+ WACOM_WORKER_WIRELESS,
+ WACOM_WORKER_BATTERY,
+};
+
struct wacom {
dma_addr_t data_dma;
struct usb_device *usbdev;
@@ -119,7 +124,8 @@ struct wacom {
struct urb *irq;
struct wacom_wac wacom_wac;
struct mutex lock;
- struct work_struct work;
+ struct work_struct wireless_work;
+ struct work_struct battery_work;
bool open;
char phys[32];
struct wacom_led {
@@ -134,10 +140,19 @@ struct wacom {
struct attribute_group remote_group[5];
};

-static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
+static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
+ enum wacom_worker which)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- schedule_work(&wacom->work);
+
+ switch (which) {
+ case WACOM_WORKER_WIRELESS:
+ schedule_work(&wacom->wireless_work);
+ break;
+ case WACOM_WORKER_BATTERY:
+ schedule_work(&wacom->battery_work);
+ break;
+ }
}

extern const struct usb_device_id wacom_ids[];
diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 3cfe780..1f2a850 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1492,7 +1492,7 @@ static void wacom_calculate_res(struct wacom_features *features)

static void wacom_wireless_work(struct work_struct *work)
{
- struct wacom *wacom = container_of(work, struct wacom, work);
+ struct wacom *wacom = container_of(work, struct wacom, wireless_work);
struct usb_device *usbdev = wacom->usbdev;
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct wacom *wacom1, *wacom2;
@@ -1603,7 +1603,7 @@ fail:

void wacom_battery_work(struct work_struct *work)
{
- struct wacom *wacom = container_of(work, struct wacom, work);
+ struct wacom *wacom = container_of(work, struct wacom, battery_work);

if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
!wacom->battery.dev) {
@@ -1660,7 +1660,8 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
wacom->usbdev = dev;
wacom->intf = intf;
mutex_init(&wacom->lock);
- INIT_WORK(&wacom->work, wacom_wireless_work);
+ INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
+ INIT_WORK(&wacom->battery_work, wacom_battery_work);
usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));

@@ -1755,7 +1756,8 @@ static void wacom_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);

usb_kill_urb(wacom->irq);
- cancel_work_sync(&wacom->work);
+ cancel_work_sync(&wacom->wireless_work);
+ cancel_work_sync(&wacom->battery_work);
kobject_put(wacom->remote_dir);
wacom_destroy_leds(wacom);
wacom_unregister_inputs(wacom);
diff --git a/2.6.38/wacom_wac.c b/2.6.38/wacom_wac.c
index 379bfdb..b131855 100644
--- a/2.6.38/wacom_wac.c
+++ b/2.6.38/wacom_wac.c
@@ -762,8 +762,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
if (!wacom->battery.dev &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
features->quirks |= WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
}

wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1, bat_charging);
@@ -1572,7 +1571,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
charging = !!(data[5] & 0x80);
if (wacom->pid != pid) {
wacom->pid = pid;
- wacom_schedule_work(wacom);
+ wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
}

if (w->battery.dev)
@@ -1581,7 +1580,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
} else if (wacom->pid != 0) {
/* disconnected while previously connected */
wacom->pid = 0;
- wacom_schedule_work(wacom);
+ wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
wacom_notify_battery(wacom, 0, 0, 0, 0);
}

@@ -1616,15 +1615,13 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
if (!wacom->battery.dev &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
features->quirks |= WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
}
}
else if ((features->quirks & WACOM_QUIRK_BATTERY) &&
wacom->battery.dev) {
features->quirks &= ~WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
}
return 0;
diff --git a/3.17/wacom.h b/3.17/wacom.h
index 108a796..fc1eeae 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -119,13 +119,19 @@
#define WACOM_POWERSUPPLY_DESC(ps) (ps)
#endif

+enum wacom_worker {
+ WACOM_WORKER_WIRELESS,
+ WACOM_WORKER_BATTERY,
+};
+
struct wacom {
struct usb_device *usbdev;
struct usb_interface *intf;
struct wacom_wac wacom_wac;
struct hid_device *hdev;
struct mutex lock;
- struct work_struct work;
+ struct work_struct wireless_work;
+ struct work_struct battery_work;
struct wacom_led {
u8 select[5]; /* status led selector (0..3) */
u8 llv; /* status led brightness no button (1..127) */
@@ -146,10 +152,19 @@ struct wacom {
struct attribute_group remote_group[5];
};

-static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
+static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
+ enum wacom_worker which)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- schedule_work(&wacom->work);
+
+ switch (which) {
+ case WACOM_WORKER_WIRELESS:
+ schedule_work(&wacom->wireless_work);
+ break;
+ case WACOM_WORKER_BATTERY:
+ schedule_work(&wacom->battery_work);
+ break;
+ }
}

extern const struct hid_device_id wacom_ids[];
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index ad492aa..c79a854 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1561,7 +1561,7 @@ static void wacom_calculate_res(struct wacom_features *features)

void wacom_battery_work(struct work_struct *work)
{
- struct wacom *wacom = container_of(work, struct wacom, work);
+ struct wacom *wacom = container_of(work, struct wacom, battery_work);

if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
!WACOM_POWERSUPPLY_DEVICE(wacom->battery)) {
@@ -1785,7 +1785,7 @@ fail_allocate_inputs:

static void wacom_wireless_work(struct work_struct *work)
{
- struct wacom *wacom = container_of(work, struct wacom, work);
+ struct wacom *wacom = container_of(work, struct wacom, wireless_work);
struct usb_device *usbdev = wacom->usbdev;
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct hid_device *hdev1, *hdev2;
@@ -1913,7 +1913,8 @@ static int wacom_probe(struct hid_device *hdev,
wacom->usbdev = dev;
wacom->intf = intf;
mutex_init(&wacom->lock);
- INIT_WORK(&wacom->work, wacom_wireless_work);
+ INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
+ INIT_WORK(&wacom->battery_work, wacom_battery_work);

/* ask for the report descriptor to be loaded by HID */
error = hid_parse(hdev);
@@ -1954,7 +1955,8 @@ static void wacom_remove(struct hid_device *hdev)

hid_hw_stop(hdev);

- cancel_work_sync(&wacom->work);
+ cancel_work_sync(&wacom->wireless_work);
+ cancel_work_sync(&wacom->battery_work);
kobject_put(wacom->remote_dir);
wacom_destroy_leds(wacom);
wacom_clean_inputs(wacom);
diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 89cbe51..648355d 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -820,8 +820,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
if (!WACOM_POWERSUPPLY_DEVICE(wacom->battery) &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
features->quirks |= WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
}

wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1,
@@ -2156,7 +2155,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
charging = !!(data[5] & 0x80);
if (wacom->pid != pid) {
wacom->pid = pid;
- wacom_schedule_work(wacom);
+ wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
}

if (WACOM_POWERSUPPLY_DEVICE(w->battery))
@@ -2165,7 +2164,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
} else if (wacom->pid != 0) {
/* disconnected while previously connected */
wacom->pid = 0;
- wacom_schedule_work(wacom);
+ wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
wacom_notify_battery(wacom, 0, 0, 0, 0);
}

@@ -2200,15 +2199,13 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
if (!WACOM_POWERSUPPLY_DEVICE(wacom->battery) &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
features->quirks |= WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
}
}
else if ((features->quirks & WACOM_QUIRK_BATTERY) &&
WACOM_POWERSUPPLY_DEVICE(wacom->battery)) {
features->quirks &= ~WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
}
return 0;
diff --git a/3.7/wacom.h b/3.7/wacom.h
index 05ef01a..fd039dd 100644
--- a/3.7/wacom.h
+++ b/3.7/wacom.h
@@ -108,6 +108,11 @@ MODULE_LICENSE(DRIVER_LICENSE);
#define USB_VENDOR_ID_WACOM 0x056a
#define USB_VENDOR_ID_LENOVO 0x17ef

+enum wacom_worker {
+ WACOM_WORKER_WIRELESS,
+ WACOM_WORKER_BATTERY,
+};
+
struct wacom {
dma_addr_t data_dma;
struct usb_device *usbdev;
@@ -115,7 +120,8 @@ struct wacom {
struct urb *irq;
struct wacom_wac wacom_wac;
struct mutex lock;
- struct work_struct work;
+ struct work_struct wireless_work;
+ struct work_struct battery_work;
bool open;
char phys[32];
struct wacom_led {
@@ -130,10 +136,19 @@ struct wacom {
struct attribute_group remote_group[5];
};

-static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
+static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
+ enum wacom_worker which)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- schedule_work(&wacom->work);
+
+ switch (which) {
+ case WACOM_WORKER_WIRELESS:
+ schedule_work(&wacom->wireless_work);
+ break;
+ case WACOM_WORKER_BATTERY:
+ schedule_work(&wacom->battery_work);
+ break;
+ }
}

extern const struct usb_device_id wacom_ids[];
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index 6a815bd..33b7ee7 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1489,7 +1489,7 @@ static void wacom_calculate_res(struct wacom_features *features)

static void wacom_wireless_work(struct work_struct *work)
{
- struct wacom *wacom = container_of(work, struct wacom, work);
+ struct wacom *wacom = container_of(work, struct wacom, wireless_work);
struct usb_device *usbdev = wacom->usbdev;
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct wacom *wacom1, *wacom2;
@@ -1600,7 +1600,7 @@ fail:

void wacom_battery_work(struct work_struct *work)
{
- struct wacom *wacom = container_of(work, struct wacom, work);
+ struct wacom *wacom = container_of(work, struct wacom, battery_work);

if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
!wacom->battery.dev) {
@@ -1657,7 +1657,8 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
wacom->usbdev = dev;
wacom->intf = intf;
mutex_init(&wacom->lock);
- INIT_WORK(&wacom->work, wacom_wireless_work);
+ INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
+ INIT_WORK(&wacom->battery_work, wacom_battery_work);
usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));

@@ -1754,7 +1755,8 @@ static void wacom_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);

usb_kill_urb(wacom->irq);
- cancel_work_sync(&wacom->work);
+ cancel_work_sync(&wacom->wireless_work);
+ cancel_work_sync(&wacom->battery_work);
kobject_put(wacom->remote_dir);
wacom_destroy_leds(wacom);
wacom_unregister_inputs(wacom);
diff --git a/3.7/wacom_wac.c b/3.7/wacom_wac.c
index 2a9e173..5887561 100644
--- a/3.7/wacom_wac.c
+++ b/3.7/wacom_wac.c
@@ -763,8 +763,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
if (!wacom->battery.dev &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
features->quirks |= WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
}

wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1,
@@ -1553,7 +1552,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
charging = !!(data[5] & 0x80);
if (wacom->pid != pid) {
wacom->pid = pid;
- wacom_schedule_work(wacom);
+ wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
}

if (w->battery.dev)
@@ -1562,7 +1561,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
} else if (wacom->pid != 0) {
/* disconnected while previously connected */
wacom->pid = 0;
- wacom_schedule_work(wacom);
+ wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
wacom_notify_battery(wacom, 0, 0, 0, 0);
}

@@ -1597,15 +1596,13 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
if (!wacom->battery.dev &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
features->quirks |= WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
}
}
else if ((features->quirks & WACOM_QUIRK_BATTERY) &&
wacom->battery.dev) {
features->quirks &= ~WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
}
return 0;
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:42:55 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

Like remotes, LEDs should be handled by themself, not magically behind
the inputs as they have a complete different life.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (85d2c77)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (5fba033)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom_sys.c | 21 +++++++++++----------
3.17/wacom_sys.c | 20 +++++++++++---------
3.7/wacom_sys.c | 22 ++++++++++++----------
3 files changed, 34 insertions(+), 29 deletions(-)

diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 10bd0fa..3cfe780 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1414,7 +1414,6 @@ static void wacom_unregister_inputs(struct wacom *wacom)
if (wacom->wacom_wac.input)
input_unregister_device(wacom->wacom_wac.input);
wacom->wacom_wac.input = NULL;
- wacom_destroy_leds(wacom);
}

static int wacom_register_input(struct wacom *wacom)
@@ -1451,15 +1450,8 @@ static int wacom_register_input(struct wacom *wacom)
if (error)
goto fail2;

- error = wacom_initialize_leds(wacom);
- if (error)
- goto fail3;
-
return 0;

-fail3:
- input_unregister_device(input_dev);
- input_dev = NULL;
fail2:
if (input_dev)
input_free_device(input_dev);
@@ -1517,11 +1509,13 @@ static void wacom_wireless_work(struct work_struct *work)
/* Stylus interface */
wacom1 = usb_get_intfdata(usbdev->config->interface[1]);
wacom_wac1 = &(wacom1->wacom_wac);
+ wacom_destroy_leds(wacom1);
wacom_unregister_inputs(wacom1);

/* Touch interface */
wacom2 = usb_get_intfdata(usbdev->config->interface[2]);
wacom_wac2 = &(wacom2->wacom_wac);
+ wacom_destroy_leds(wacom2);
wacom_unregister_inputs(wacom2);

if (wacom_wac->pid == 0) {
@@ -1600,7 +1594,9 @@ static void wacom_wireless_work(struct work_struct *work)
return;

fail:
+ wacom_destroy_leds(wacom1);
wacom_unregister_inputs(wacom1);
+ wacom_destroy_leds(wacom2);
wacom_unregister_inputs(wacom2);
return;
}
@@ -1723,10 +1719,14 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
}
}

+ error = wacom_initialize_leds(wacom);
+ if (error)
+ goto fail4;
+
if (wacom->wacom_wac.features.type == REMOTE) {
error = wacom_initialize_remote(wacom);
if (error)
- goto fail4;
+ goto fail_remote;
}

if ((wacom_wac->features.type == INTUOSHT ||
@@ -1739,7 +1739,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
}

return 0;
-
+ fail_remote: wacom_destroy_leds(wacom);
fail4: wacom_remove_shared_data(wacom_wac);
fail3: usb_free_urb(wacom->irq);
wacom_destroy_battery(wacom);
@@ -1757,6 +1757,7 @@ static void wacom_disconnect(struct usb_interface *intf)
usb_kill_urb(wacom->irq);
cancel_work_sync(&wacom->work);
kobject_put(wacom->remote_dir);
+ wacom_destroy_leds(wacom);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
usb_free_urb(wacom->irq);
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index ca4b362..ad492aa 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1437,7 +1437,6 @@ static void wacom_clean_inputs(struct wacom *wacom)
wacom->wacom_wac.pen_registered = false;
wacom->wacom_wac.touch_registered = false;
wacom->wacom_wac.pad_registered = false;
- wacom_destroy_leds(wacom);
}

static int wacom_allocate_inputs(struct wacom *wacom)
@@ -1509,18 +1508,10 @@ static int wacom_register_inputs(struct wacom *wacom)
if (error)
goto fail_register_pad_input;
wacom_wac->pad_registered = true;
-
- error = wacom_initialize_leds(wacom);
- if (error)
- goto fail_leds;
}

return 0;

-fail_leds:
- input_unregister_device(pad_input_dev);
- pad_input_dev = NULL;
- wacom_wac->pad_registered = false;
fail_register_pad_input:
if (touch_input_dev)
input_unregister_device(touch_input_dev);
@@ -1718,6 +1709,10 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
goto fail_register_inputs;

if (wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD) {
+ error = wacom_initialize_leds(wacom);
+ if (error)
+ goto fail_leds;
+
error = wacom_initialize_remote(wacom);
if (error)
goto fail_remote;
@@ -1774,6 +1769,8 @@ fail_quirks:
fail_hw_start:
kobject_put(wacom->remote_dir);
fail_remote:
+ wacom_destroy_leds(wacom);
+fail_leds:
wacom_clean_inputs(wacom);
fail_register_inputs:
wacom_destroy_battery(wacom);
@@ -1807,12 +1804,14 @@ static void wacom_wireless_work(struct work_struct *work)
hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
wacom1 = hid_get_drvdata(hdev1);
wacom_wac1 = &(wacom1->wacom_wac);
+ wacom_destroy_leds(wacom1);
wacom_clean_inputs(wacom1);

/* Touch interface */
hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
wacom2 = hid_get_drvdata(hdev2);
wacom_wac2 = &(wacom2->wacom_wac);
+ wacom_destroy_leds(wacom2);
wacom_clean_inputs(wacom2);

if (wacom_wac->pid == 0) {
@@ -1867,7 +1866,9 @@ static void wacom_wireless_work(struct work_struct *work)
return;

fail:
+ wacom_destroy_leds(wacom1);
wacom_clean_inputs(wacom1);
+ wacom_destroy_leds(wacom2);
wacom_clean_inputs(wacom2);
return;
}
@@ -1955,6 +1956,7 @@ static void wacom_remove(struct hid_device *hdev)

cancel_work_sync(&wacom->work);
kobject_put(wacom->remote_dir);
+ wacom_destroy_leds(wacom);
wacom_clean_inputs(wacom);
if (hdev->bus == BUS_BLUETOOTH)
device_remove_file(&hdev->dev, &dev_attr_speed);
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index a36a751..6a815bd 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1408,7 +1408,6 @@ static void wacom_unregister_inputs(struct wacom *wacom)
if (wacom->wacom_wac.input)
input_unregister_device(wacom->wacom_wac.input);
wacom->wacom_wac.input = NULL;
- wacom_destroy_leds(wacom);
}

static int wacom_register_input(struct wacom *wacom)
@@ -1445,16 +1444,8 @@ static int wacom_register_input(struct wacom *wacom)
if (error)
goto fail2;

-
- error = wacom_initialize_leds(wacom);
- if (error)
- goto fail3;
-
return 0;

-fail3:
- input_unregister_device(input_dev);
- input_dev = NULL;
fail2:
if (input_dev)
input_free_device(input_dev);
@@ -1515,11 +1506,13 @@ static void wacom_wireless_work(struct work_struct *work)
/* Stylus interface */
wacom1 = usb_get_intfdata(usbdev->config->interface[1]);
wacom_wac1 = &(wacom1->wacom_wac);
+ wacom_destroy_leds(wacom1);
wacom_unregister_inputs(wacom1);

/* Touch interface */
wacom2 = usb_get_intfdata(usbdev->config->interface[2]);
wacom_wac2 = &(wacom2->wacom_wac);
+ wacom_destroy_leds(wacom2);
wacom_unregister_inputs(wacom2);

if (wacom_wac->pid == 0) {
@@ -1598,7 +1591,9 @@ static void wacom_wireless_work(struct work_struct *work)
return;

fail:
+ wacom_destroy_leds(wacom1);
wacom_unregister_inputs(wacom1);
+ wacom_destroy_leds(wacom2);
wacom_unregister_inputs(wacom2);
return;
}
@@ -1721,10 +1716,14 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
}
}

+ error = wacom_initialize_leds(wacom);
+ if (error)
+ goto fail4;
+
if (wacom->wacom_wac.features.type == REMOTE) {
error = wacom_initialize_remote(wacom);
if (error)
- goto fail4;
+ goto fail_remote;
}

if ((wacom_wac->features.type == INTUOSHT ||
@@ -1738,6 +1737,8 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i

return 0;

+ fail_remote:
+ wacom_destroy_leds(wacom);
fail4: wacom_remove_shared_data(wacom_wac);
fail3: usb_free_urb(wacom->irq);
wacom_destroy_battery(wacom);
@@ -1755,6 +1756,7 @@ static void wacom_disconnect(struct usb_interface *intf)
usb_kill_urb(wacom->irq);
cancel_work_sync(&wacom->work);
kobject_put(wacom->remote_dir);
+ wacom_destroy_leds(wacom);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
usb_free_urb(wacom->irq);
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:09 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

This will be useful when each remote will be assigned its own input device.
We won't need to unregister each input and sysfs and other elements one
at a time.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (f9036bd)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (5457b33)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom_sys.c | 49 ++++++++++++++++++++++++++++++++++---------------
3.17/wacom_sys.c | 44 ++++++++++++++++++++++++++++----------------
3.7/wacom_sys.c | 49 ++++++++++++++++++++++++++++++++++---------------
3 files changed, 96 insertions(+), 46 deletions(-)

diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 85f08f2..5ce0210 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1050,7 +1050,8 @@ static void wacom_devm_sysfs_group_release(struct device *dev, void *res)
sysfs_remove_group(kobj, devres->group);
}

-static int wacom_devm_sysfs_create_group(struct wacom *wacom,
+static int __wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct kobject *root,
struct attribute_group *group)
{
struct wacom_sysfs_group_devres *devres;
@@ -1063,7 +1064,7 @@ static int wacom_devm_sysfs_create_group(struct wacom *wacom,
return -ENOMEM;

devres->group = group;
- devres->root = &wacom->intf->dev.kobj;
+ devres->root = root;

error = sysfs_create_group(devres->root, group);
if (error)
@@ -1074,6 +1075,13 @@ static int wacom_devm_sysfs_create_group(struct wacom *wacom,
return 0;
}

+static int wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct attribute_group *group)
+{
+ return __wacom_devm_sysfs_create_group(wacom, &wacom->intf->dev.kobj,
+ group);
+}
+
static int wacom_initialize_leds(struct wacom *wacom)
{
int error;
@@ -1281,10 +1289,11 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int
if (!remote->remote_group[index].name)
return -ENOMEM;

- error = sysfs_create_group(remote->remote_dir,
- &remote->remote_group[index]);
+ error = __wacom_devm_sysfs_create_group(wacom, remote->remote_dir,
+ &remote->remote_group[index]);

if (error) {
+ remote->remote_group[index].name = NULL;
dev_err(&wacom->intf->dev,
"cannot create sysfs group err: %d\n", error);
return error;
@@ -1293,15 +1302,6 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int
return 0;
}

-static void wacom_remote_destroy_attr_group(struct wacom *wacom, int i)
-{
- struct wacom_remote *remote = wacom->remote;
-
- sysfs_remove_group(remote->remote_dir, &remote->remote_group[i]);
- kfree((char *)remote->remote_group[i].name);
- remote->remote_group[i].name = NULL;
-}
-
static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
{
const size_t buf_size = 2;
@@ -1329,11 +1329,19 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
u32 serial = remote->serial[index];
int i;

- wacom_remote_destroy_attr_group(wacom, index);
+ if (remote->remote_group[index].name)
+ devres_release_group(&wacom->usbdev->dev, &remote->serial[index]);

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (remote->serial[i] == serial) {
remote->serial[i] = 0;
+
+ /* Destroy the attribute group parts not
+ * covered by devres for this kernel.
+ */
+ kfree((char *)remote->remote_group[i].name);
+ remote->remote_group[i].name = NULL;
+
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
}
}
@@ -1343,6 +1351,7 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
unsigned int index)
{
struct wacom_remote *remote = wacom->remote;
+ struct device *dev = &wacom->usbdev->dev;
int error, k;

/* A remote can pair more than once with an EKR,
@@ -1358,13 +1367,23 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
return 0;
}

+ if (!devres_open_group(dev, &remote->serial[index], GFP_KERNEL))
+ return -ENOMEM;
+
error = wacom_remote_create_attr_group(wacom, serial, index);
if (error)
- return error;
+ goto fail;

remote->serial[index] = serial;

+ devres_close_group(dev, &remote->serial[index]);
+
return 0;
+
+fail:
+ devres_release_group(dev, &remote->serial[index]);
+ remote->serial[index] = 0;
+ return error;
}

static ssize_t wacom_store_unpair_remote(struct kobject *kobj,
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 4c5c76b..3b2c71c 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -938,8 +938,9 @@ static void wacom_devm_sysfs_group_release(struct device *dev, void *res)
sysfs_remove_group(kobj, devres->group);
}

-static int wacom_devm_sysfs_create_group(struct wacom *wacom,
- struct attribute_group *group)
+static int __wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct kobject *root,
+ struct attribute_group *group)
{
struct wacom_sysfs_group_devres *devres;
int error;
@@ -951,7 +952,7 @@ static int wacom_devm_sysfs_create_group(struct wacom *wacom,
return -ENOMEM;

devres->group = group;
- devres->root = &wacom->hdev->dev.kobj;
+ devres->root = root;

error = sysfs_create_group(devres->root, group);
if (error)
@@ -962,6 +963,13 @@ static int wacom_devm_sysfs_create_group(struct wacom *wacom,
return 0;
}

+static int wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct attribute_group *group)
+{
+ return __wacom_devm_sysfs_create_group(wacom, &wacom->hdev->dev.kobj,
+ group);
+}
+
static void wacom_led_groups_release(void *data)
{
struct wacom *wacom = data;
@@ -1358,9 +1366,10 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
if (!remote->remote_group[index].name)
return -ENOMEM;

- error = sysfs_create_group(remote->remote_dir,
- &remote->remote_group[index]);
+ error = __wacom_devm_sysfs_create_group(wacom, remote->remote_dir,
+ &remote->remote_group[index]);
if (error) {
+ remote->remote_group[index].name = NULL;
hid_err(wacom->hdev,
"cannot create sysfs group err: %d\n", error);
return error;
@@ -1369,15 +1378,6 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
return 0;
}

-static void wacom_remote_destroy_attr_group(struct wacom *wacom, unsigned int i)
-{
- struct wacom_remote *remote = wacom->remote;
-
- sysfs_remove_group(remote->remote_dir, &remote->remote_group[i]);
- devm_kfree(&wacom->hdev->dev, (char *)remote->remote_group[i].name);
- remote->remote_group[i].name = NULL;
-}
-
static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
{
const size_t buf_size = 2;
@@ -1977,11 +1977,13 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
u32 serial = remote->serial[index];
int i;

- wacom_remote_destroy_attr_group(wacom, index);
+ if (remote->remote_group[index].name)
+ devres_release_group(&wacom->hdev->dev, &remote->serial[index]);

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (remote->serial[i] == serial) {
remote->serial[i] = 0;
+ remote->remote_group[i].name = NULL;
wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
}
}
@@ -1991,6 +1993,7 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
unsigned int index)
{
struct wacom_remote *remote = wacom->remote;
+ struct device *dev = &wacom->hdev->dev;
int error, k;

/* A remote can pair more than once with an EKR,
@@ -2006,13 +2009,22 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
return 0;
}

+ if (!devres_open_group(dev, &remote->serial[index], GFP_KERNEL))
+ return -ENOMEM;
+
error = wacom_remote_create_attr_group(wacom, serial, index);
if (error)
- return error;
+ goto fail;

remote->serial[index] = serial;

+ devres_close_group(dev, &remote->serial[index]);
return 0;
+
+fail:
+ devres_release_group(dev, &remote->serial[index]);
+ remote->serial[index] = 0;
+ return error;
}

static void wacom_remote_work(struct work_struct *work)
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index 453ddaa..ef241c9 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1049,7 +1049,8 @@ static void wacom_devm_sysfs_group_release(struct device *dev, void *res)
sysfs_remove_group(kobj, devres->group);
}

-static int wacom_devm_sysfs_create_group(struct wacom *wacom,
+static int __wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct kobject *root,
struct attribute_group *group)
{
struct wacom_sysfs_group_devres *devres;
@@ -1062,7 +1063,7 @@ static int wacom_devm_sysfs_create_group(struct wacom *wacom,
return -ENOMEM;

devres->group = group;
- devres->root = &wacom->intf->dev.kobj;
+ devres->root = root;

error = sysfs_create_group(devres->root, group);
if (error)
@@ -1073,6 +1074,13 @@ static int wacom_devm_sysfs_create_group(struct wacom *wacom,
return 0;
}

+static int wacom_devm_sysfs_create_group(struct wacom *wacom,
+ struct attribute_group *group)
+{
+ return __wacom_devm_sysfs_create_group(wacom, &wacom->intf->dev.kobj,
+ group);
+}
+
static int wacom_initialize_leds(struct wacom *wacom)
{
int error;
@@ -1274,9 +1282,10 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int
if (!remote->remote_group[index].name)
return -ENOMEM;

- error = sysfs_create_group(remote->remote_dir,
- &remote->remote_group[index]);
+ error = __wacom_devm_sysfs_create_group(wacom, remote->remote_dir,
+ &remote->remote_group[index]);
if (error) {
+ remote->remote_group[index].name = NULL;
dev_err(&wacom->intf->dev,
"cannot create sysfs group err: %d\n", error);
return error;
@@ -1285,15 +1294,6 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int
return 0;
}

-static void wacom_remote_destroy_attr_group(struct wacom *wacom, int i)
-{
- struct wacom_remote *remote = wacom->remote;
-
- sysfs_remove_group(remote->remote_dir, &remote->remote_group[i]);
- kfree((char *)remote->remote_group[i].name);
- remote->remote_group[i].name = NULL;
-}
-
static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
{
const size_t buf_size = 2;
@@ -1321,11 +1321,19 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
u32 serial = remote->serial[index];
int i;

- wacom_remote_destroy_attr_group(wacom, index);
+ if (remote->remote_group[index].name)
+ devres_release_group(&wacom->usbdev->dev, &remote->serial[index]);

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (remote->serial[i] == serial) {
remote->serial[i] = 0;
+
+ /* Destroy the attribute group parts not
+ * covered by devres for this kernel.
+ */
+ kfree((char *)remote->remote_group[i].name);
+ remote->remote_group[i].name = NULL;
+
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
}
}
@@ -1335,6 +1343,7 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
unsigned int index)
{
struct wacom_remote *remote = wacom->remote;
+ struct device *dev = &wacom->usbdev->dev;
int error, k;

/* A remote can pair more than once with an EKR,
@@ -1350,13 +1359,23 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
return 0;
}

+ if (!devres_open_group(dev, &remote->serial[index], GFP_KERNEL))
+ return -ENOMEM;
+
error = wacom_remote_create_attr_group(wacom, serial, index);
if (error)
- return error;
+ goto fail;

remote->serial[index] = serial;

+ devres_close_group(dev, &remote->serial[index]);
+
return 0;
+
+fail:
+ devres_release_group(dev, &remote->serial[index]);
+ remote->serial[index] = 0;
+ return error;
}

static ssize_t wacom_store_unpair_remote(struct kobject *kobj,
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:42:59 UTC
Permalink
We currently have a complex clean_inputs() function while this can be
handled all by devres. Set a group that we can destroy in wireless_work().

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (84dfbd7)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (458c0ea)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom.h | 1 +
3.17/wacom_sys.c | 69 ++++++++++++++++++++++++--------------------------------
3.17/wacom_wac.c | 2 +-
3.17/wacom_wac.h | 3 ---
4 files changed, 32 insertions(+), 43 deletions(-)

diff --git a/3.17/wacom.h b/3.17/wacom.h
index fc1eeae..9f94378 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -150,6 +150,7 @@ struct wacom {
#endif
struct kobject *remote_dir;
struct attribute_group remote_group[5];
+ bool resources;
};

static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index e0ee405..a5c2f44 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1434,34 +1434,6 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom)
return input_dev;
}

-static void wacom_clean_inputs(struct wacom *wacom)
-{
- if (wacom->wacom_wac.pen_input) {
- if (wacom->wacom_wac.pen_registered)
- input_unregister_device(wacom->wacom_wac.pen_input);
- else
- input_free_device(wacom->wacom_wac.pen_input);
- }
- if (wacom->wacom_wac.touch_input) {
- if (wacom->wacom_wac.touch_registered)
- input_unregister_device(wacom->wacom_wac.touch_input);
- else
- input_free_device(wacom->wacom_wac.touch_input);
- }
- if (wacom->wacom_wac.pad_input) {
- if (wacom->wacom_wac.pad_registered)
- input_unregister_device(wacom->wacom_wac.pad_input);
- else
- input_free_device(wacom->wacom_wac.pad_input);
- }
- wacom->wacom_wac.pen_input = NULL;
- wacom->wacom_wac.touch_input = NULL;
- wacom->wacom_wac.pad_input = NULL;
- wacom->wacom_wac.pen_registered = false;
- wacom->wacom_wac.touch_registered = false;
- wacom->wacom_wac.pad_registered = false;
-}
-
static int wacom_allocate_inputs(struct wacom *wacom)
{
struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
@@ -1504,7 +1476,6 @@ static int wacom_register_inputs(struct wacom *wacom)
error = input_register_device(pen_input_dev);
if (error)
goto fail;
- wacom_wac->pen_registered = true;
}

error = wacom_setup_touch_input_capabilities(touch_input_dev, wacom_wac);
@@ -1517,7 +1488,6 @@ static int wacom_register_inputs(struct wacom *wacom)
error = input_register_device(touch_input_dev);
if (error)
goto fail;
- wacom_wac->touch_registered = true;
}

error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
@@ -1530,18 +1500,14 @@ static int wacom_register_inputs(struct wacom *wacom)
error = input_register_device(pad_input_dev);
if (error)
goto fail;
- wacom_wac->pad_registered = true;
}

return 0;

fail:
wacom_wac->pad_input = NULL;
- wacom_wac->pad_registered = false;
wacom_wac->touch_input = NULL;
- wacom_wac->touch_registered = false;
wacom_wac->pen_input = NULL;
- wacom_wac->pen_registered = false;
return error;
}

@@ -1656,6 +1622,22 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
"%s%s Pad", name, suffix);
}

+static void wacom_release_resources(struct wacom *wacom)
+{
+ struct hid_device *hdev = wacom->hdev;
+
+ if (!wacom->resources)
+ return;
+
+ devres_release_group(&hdev->dev, wacom);
+
+ wacom->resources = false;
+
+ wacom->wacom_wac.pen_input = NULL;
+ wacom->wacom_wac.touch_input = NULL;
+ wacom->wacom_wac.pad_input = NULL;
+}
+
static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
{
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
@@ -1668,9 +1650,14 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
if (features->pktlen > WACOM_PKGLEN_MAX)
return -EINVAL;

+ if (!devres_open_group(&hdev->dev, wacom, GFP_KERNEL))
+ return -ENOMEM;
+
+ wacom->resources = true;
+
error = wacom_allocate_inputs(wacom);
if (error)
- return error;
+ goto fail_open_group;

/*
* Bamboo Pad has a generic hid handling for the Pen, and we switch it
@@ -1781,6 +1768,8 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
wacom_wac->shared->touch_input = wacom_wac->touch_input;
}

+ devres_close_group(&hdev->dev, wacom);
+
return 0;

fail_quirks:
@@ -1799,6 +1788,8 @@ fail_battery:
fail_shared_data:
fail_parsed:
fail_allocate_inputs:
+fail_open_group:
+ wacom_release_resources(wacom);
return error;
}

@@ -1824,14 +1815,14 @@ static void wacom_wireless_work(struct work_struct *work)
wacom1 = hid_get_drvdata(hdev1);
wacom_wac1 = &(wacom1->wacom_wac);
wacom_destroy_leds(wacom1);
- wacom_clean_inputs(wacom1);
+ wacom_release_resources(wacom1);

/* Touch interface */
hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
wacom2 = hid_get_drvdata(hdev2);
wacom_wac2 = &(wacom2->wacom_wac);
wacom_destroy_leds(wacom2);
- wacom_clean_inputs(wacom2);
+ wacom_release_resources(wacom2);

if (wacom_wac->pid == 0) {
hid_info(wacom->hdev, "wireless tablet disconnected\n");
@@ -1886,9 +1877,9 @@ static void wacom_wireless_work(struct work_struct *work)

fail:
wacom_destroy_leds(wacom1);
- wacom_clean_inputs(wacom1);
+ wacom_release_resources(wacom1);
wacom_destroy_leds(wacom2);
- wacom_clean_inputs(wacom2);
+ wacom_release_resources(wacom2);
return;
}

diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 648355d..af214a3 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -1947,7 +1947,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
}

/* only update touch if we actually have a touchpad and touch data changed */
- if (wacom->touch_registered && touch_changed) {
+ if (wacom->touch_input && touch_changed) {
input_mt_sync_frame(wacom->touch_input);
wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
}
diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h
index 4e48ac6..feeb96d 100644
--- a/3.17/wacom_wac.h
+++ b/3.17/wacom_wac.h
@@ -234,9 +234,6 @@ struct wacom_wac {
struct input_dev *pen_input;
struct input_dev *touch_input;
struct input_dev *pad_input;
- bool pen_registered;
- bool touch_registered;
- bool pad_registered;
int pid;
int battery_capacity;
int num_contacts_left;
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:07 UTC
Permalink
Thanks to devres management, we don't need to remember a lot of failure
path. One or two is enough.

Note: changes to parse_and_register() have been removed from the import
of this patch to input-wacom.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (3888b0d)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (5082afb)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom_sys.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 6acf07f..2dcd873 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -2077,7 +2077,7 @@ static int wacom_probe(struct hid_device *hdev,

if (features->check_for_hid_type && features->hid_type != hdev->type) {
error = -ENODEV;
- goto fail_type;
+ goto fail;
}

wacom_wac->hid_data.inputmode = -1;
@@ -2094,12 +2094,12 @@ static int wacom_probe(struct hid_device *hdev,
error = hid_parse(hdev);
if (error) {
hid_err(hdev, "parse failed\n");
- goto fail_parse;
+ goto fail;
}

error = wacom_parse_and_register(wacom, false);
if (error)
- goto fail_parse;
+ goto fail;

if (hdev->bus == BUS_BLUETOOTH) {
error = device_create_file(&hdev->dev, &dev_attr_speed);
@@ -2111,8 +2111,7 @@ static int wacom_probe(struct hid_device *hdev,

return 0;

-fail_parse:
-fail_type:
+fail:
hid_set_drvdata(hdev, NULL);
return error;
}
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:05 UTC
Permalink
wacom_remote_status_irq() sends information of addition/removal of EKR.
We want to allocate one input node per remote, so better having this
in a separate worker, not handled in the IRQ directly.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (e6f2813)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (0cf7522)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom.h | 11 ++++++--
2.6.38/wacom_sys.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++--
2.6.38/wacom_wac.c | 54 +++++++++++++++---------------------
2.6.38/wacom_wac.h | 7 +++++
3.17/wacom.h | 11 ++++++--
3.17/wacom_sys.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
3.17/wacom_wac.c | 53 ++++++++++++++----------------------
3.17/wacom_wac.h | 7 +++++
3.7/wacom.h | 11 ++++++--
3.7/wacom_sys.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++--
3.7/wacom_wac.c | 54 +++++++++++++++---------------------
3.7/wacom_wac.h | 7 +++++
12 files changed, 341 insertions(+), 112 deletions(-)

diff --git a/2.6.38/wacom.h b/2.6.38/wacom.h
index c8941c9..b4470b3 100644
--- a/2.6.38/wacom.h
+++ b/2.6.38/wacom.h
@@ -87,6 +87,7 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/init.h>
+#include <linux/kfifo.h>
#include <linux/usb/input.h>
#include <linux/power_supply.h>
#include <asm/unaligned.h>
@@ -115,6 +116,7 @@ MODULE_LICENSE(DRIVER_LICENSE);
enum wacom_worker {
WACOM_WORKER_WIRELESS,
WACOM_WORKER_BATTERY,
+ WACOM_WORKER_REMOTE,
};

struct wacom {
@@ -126,6 +128,9 @@ struct wacom {
struct mutex lock;
struct work_struct wireless_work;
struct work_struct battery_work;
+ struct work_struct remote_work;
+ spinlock_t remote_lock;
+ struct kfifo remote_fifo;
bool open;
char phys[32];
struct wacom_led {
@@ -151,6 +156,9 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
case WACOM_WORKER_BATTERY:
schedule_work(&wacom->battery_work);
break;
+ case WACOM_WORKER_REMOTE:
+ schedule_work(&wacom->remote_work);
+ break;
}
}

@@ -161,7 +169,4 @@ void wacom_setup_device_quirks(struct wacom *wacom);
int wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac);
void wacom_battery_work(struct work_struct *work);
-int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
- int index);
-void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial);
#endif
diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 2ef93fc..12a3c66 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1272,7 +1272,7 @@ DEVICE_EKR_ATTR_GROUP(2);
DEVICE_EKR_ATTR_GROUP(3);
DEVICE_EKR_ATTR_GROUP(4);

-int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
+static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
{
int error = 0;
char *buf;
@@ -1297,7 +1297,7 @@ int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
return 0;
}

-void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
+static void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
{
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
int i;
@@ -1613,6 +1613,66 @@ void wacom_battery_work(struct work_struct *work)
}
}

+static void wacom_remote_work(struct work_struct *work)
+{
+ struct wacom *wacom = container_of(work, struct wacom, remote_work);
+ struct device *dev = &wacom->intf->dev;
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote_data data;
+ unsigned long flags;
+ unsigned int count;
+ u32 serial;
+ int i, k;
+
+ spin_lock_irqsave(&wacom->remote_lock, flags);
+
+ count = kfifo_out(&wacom->remote_fifo, &data, sizeof(data));
+
+ if (count != sizeof(data)) {
+ dev_err(dev,
+ "workitem triggered without status available\n");
+ spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ return;
+ }
+
+ if (!kfifo_is_empty(&wacom->remote_fifo))
+ wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_REMOTE);
+
+ spin_unlock_irqrestore(&wacom->remote_lock, flags);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ serial = data.remote[i].serial;
+ if (data.remote[i].connected) {
+
+ if (wacom_wac->serial[i] == serial)
+ continue;
+
+ if (wacom_wac->serial[i]) {
+ wacom_remote_destroy_attr_group(wacom,
+ wacom_wac->serial[i]);
+ }
+
+ /* A remote can pair more than once with an EKR,
+ * check to make sure this serial isn't already paired.
+ */
+ for (k = 0; k < WACOM_MAX_REMOTES; k++) {
+ if (wacom_wac->serial[k] == serial)
+ break;
+ }
+
+ if (k < WACOM_MAX_REMOTES) {
+ wacom_wac->serial[i] = serial;
+ continue;
+ }
+ wacom_remote_create_attr_group(wacom, serial, i);
+
+ } else if (wacom_wac->serial[i]) {
+ wacom_remote_destroy_attr_group(wacom,
+ wacom_wac->serial[i]);
+ }
+ }
+}
+
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
@@ -1660,6 +1720,18 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
mutex_init(&wacom->lock);
INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
INIT_WORK(&wacom->battery_work, wacom_battery_work);
+ INIT_WORK(&wacom->remote_work, wacom_remote_work);
+ spin_lock_init(&wacom->remote_lock);
+
+ if (kfifo_alloc(&wacom->remote_fifo,
+ 5 * sizeof(struct wacom_remote_data),
+ GFP_KERNEL)) {
+ dev_err(&wacom->intf->dev,
+ "%s:failed allocating remote_fifo\n", __func__);
+ error = -ENOMEM;
+ goto fail2;
+ }
+
usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));

@@ -1742,6 +1814,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
fail4: wacom_remove_shared_data(wacom_wac);
fail3: usb_free_urb(wacom->irq);
wacom_destroy_battery(wacom);
+ kfifo_free(&wacom->remote_fifo);
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
fail1:
return error;
@@ -1757,6 +1830,8 @@ static void wacom_disconnect(struct usb_interface *intf)
usb_kill_urb(wacom->irq);
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
+ cancel_work_sync(&wacom->remote_work);
+ kfifo_free(&wacom->remote_fifo);
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (wacom->remote_group[i].name) {
wacom_remote_destroy_attr_group(wacom,
diff --git a/2.6.38/wacom_wac.c b/2.6.38/wacom_wac.c
index b131855..4361d55 100644
--- a/2.6.38/wacom_wac.c
+++ b/2.6.38/wacom_wac.c
@@ -770,52 +770,41 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
return 1;
}

-static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
+static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+ struct device *dev = &wacom->intf->dev;
unsigned char *data = wacom_wac->data;
- int i;
+ struct wacom_remote_data remote_data;
+ unsigned long flags;
+ int i, ret;

if (data[0] != WACOM_REPORT_DEVICE_LIST)
- return 0;
+ return;
+
+ memset(&remote_data, 0, sizeof(struct wacom_remote_data));

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
int j = i * 6;
int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
bool connected = data[j+2];

- if (connected) {
- int k;
-
- if (wacom_wac->serial[i] == serial)
- continue;
-
- if (wacom_wac->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
- }
-
- /* A remote can pair more than once with an EKR,
- * check to make sure this serial isn't already paired.
- */
- for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (wacom_wac->serial[k] == serial)
- break;
- }
+ remote_data.remote[i].serial = serial;
+ remote_data.remote[i].connected = connected;
+ }

- if (k < WACOM_MAX_REMOTES) {
- wacom_wac->serial[i] = serial;
- continue;
- }
- wacom_remote_create_attr_group(wacom, serial, i);
+ spin_lock_irqsave(&wacom->remote_lock, flags);

- } else if (wacom_wac->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
- }
+ ret = kfifo_in(&wacom->remote_fifo, &remote_data, sizeof(remote_data));
+ if (ret != sizeof(remote_data)) {
+ spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ dev_err(dev, "Can't queue Remote status event.\n");
+ return;
}

- return 0;
+ spin_unlock_irqrestore(&wacom->remote_lock, flags);
+
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
}

static int wacom_intuos_general(struct wacom_wac *wacom)
@@ -1721,8 +1710,9 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
break;

case REMOTE:
+ sync = false;
if (wacom_wac->data[0] == WACOM_REPORT_DEVICE_LIST)
- sync = wacom_remote_status_irq(wacom_wac, len);
+ wacom_remote_status_irq(wacom_wac, len);
else
sync = wacom_remote_irq(wacom_wac, len);
break;
diff --git a/2.6.38/wacom_wac.h b/2.6.38/wacom_wac.h
index f8c2fe2..17ca409 100644
--- a/2.6.38/wacom_wac.h
+++ b/2.6.38/wacom_wac.h
@@ -165,6 +165,13 @@ struct wacom_shared {
struct input_dev *touch_input;
};

+struct wacom_remote_data {
+ struct {
+ u32 serial;
+ bool connected;
+ } remote[WACOM_MAX_REMOTES];
+};
+
struct wacom_wac {
char name[WACOM_NAME_MAX];
char bat_name[WACOM_NAME_MAX];
diff --git a/3.17/wacom.h b/3.17/wacom.h
index e7b05da..6b7032f 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -90,6 +90,7 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/hid.h>
+#include <linux/kfifo.h>
#include <linux/usb/input.h>
#include <linux/power_supply.h>
#include <asm/unaligned.h>
@@ -122,6 +123,7 @@
enum wacom_worker {
WACOM_WORKER_WIRELESS,
WACOM_WORKER_BATTERY,
+ WACOM_WORKER_REMOTE,
};

struct wacom_group_leds {
@@ -136,6 +138,9 @@ struct wacom {
struct mutex lock;
struct work_struct wireless_work;
struct work_struct battery_work;
+ struct work_struct remote_work;
+ spinlock_t remote_lock;
+ struct kfifo remote_fifo;
struct wacom_leds {
struct wacom_group_leds *groups;
u8 llv; /* status led brightness no button (1..127) */
@@ -168,6 +173,9 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
case WACOM_WORKER_BATTERY:
schedule_work(&wacom->battery_work);
break;
+ case WACOM_WORKER_REMOTE:
+ schedule_work(&wacom->remote_work);
+ break;
}
}

@@ -187,9 +195,6 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value);
void wacom_wac_report(struct hid_device *hdev, struct hid_report *report);
void wacom_battery_work(struct work_struct *work);
-int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
- int index);
-void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial);

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
static int wacom_hid_report_len(struct hid_report *report)
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index a899cf2..696efa5 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1346,7 +1346,8 @@ DEVICE_EKR_ATTR_GROUP(2);
DEVICE_EKR_ATTR_GROUP(3);
DEVICE_EKR_ATTR_GROUP(4);

-int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
+static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
+ int index)
{
int error = 0;
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
@@ -1370,7 +1371,7 @@ int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
return 0;
}

-void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
+static void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
{
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
int i;
@@ -1952,6 +1953,65 @@ fail:
return;
}

+static void wacom_remote_work(struct work_struct *work)
+{
+ struct wacom *wacom = container_of(work, struct wacom, remote_work);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote_data data;
+ unsigned long flags;
+ unsigned int count;
+ u32 serial;
+ int i, k;
+
+ spin_lock_irqsave(&wacom->remote_lock, flags);
+
+ count = kfifo_out(&wacom->remote_fifo, &data, sizeof(data));
+
+ if (count != sizeof(data)) {
+ hid_err(wacom->hdev,
+ "workitem triggered without status available\n");
+ spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ return;
+ }
+
+ if (!kfifo_is_empty(&wacom->remote_fifo))
+ wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_REMOTE);
+
+ spin_unlock_irqrestore(&wacom->remote_lock, flags);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ serial = data.remote[i].serial;
+ if (data.remote[i].connected) {
+
+ if (wacom_wac->serial[i] == serial)
+ continue;
+
+ if (wacom_wac->serial[i]) {
+ wacom_remote_destroy_attr_group(wacom,
+ wacom_wac->serial[i]);
+ }
+
+ /* A remote can pair more than once with an EKR,
+ * check to make sure this serial isn't already paired.
+ */
+ for (k = 0; k < WACOM_MAX_REMOTES; k++) {
+ if (wacom_wac->serial[k] == serial)
+ break;
+ }
+
+ if (k < WACOM_MAX_REMOTES) {
+ wacom_wac->serial[i] = serial;
+ continue;
+ }
+ wacom_remote_create_attr_group(wacom, serial, i);
+
+ } else if (wacom_wac->serial[i]) {
+ wacom_remote_destroy_attr_group(wacom,
+ wacom_wac->serial[i]);
+ }
+ }
+}
+
static int wacom_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
@@ -1994,6 +2054,17 @@ static int wacom_probe(struct hid_device *hdev,
mutex_init(&wacom->lock);
INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
INIT_WORK(&wacom->battery_work, wacom_battery_work);
+ INIT_WORK(&wacom->remote_work, wacom_remote_work);
+ spin_lock_init(&wacom->remote_lock);
+
+ if (kfifo_alloc(&wacom->remote_fifo,
+ 5 * sizeof(struct wacom_remote_data),
+ GFP_KERNEL)) {
+ dev_err(&hdev->dev,
+ "%s:failed allocating remote_fifo\n", __func__);
+ error = -ENOMEM;
+ goto fail_type;
+ }

/* ask for the report descriptor to be loaded by HID */
error = hid_parse(hdev);
@@ -2016,8 +2087,9 @@ static int wacom_probe(struct hid_device *hdev,

return 0;

-fail_type:
fail_parse:
+ kfifo_free(&wacom->remote_fifo);
+fail_type:
hid_set_drvdata(hdev, NULL);
return error;
}
@@ -2035,6 +2107,8 @@ static void wacom_remove(struct hid_device *hdev)

cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
+ cancel_work_sync(&wacom->remote_work);
+ kfifo_free(&wacom->remote_fifo);
kobject_put(wacom->remote_dir);
if (hdev->bus == BUS_BLUETOOTH)
device_remove_file(&hdev->dev, &dev_attr_speed);
diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 51dec4a..298d5b3 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -829,52 +829,40 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
return 1;
}

-static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
+static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
unsigned char *data = wacom_wac->data;
- int i;
+ struct wacom_remote_data remote_data;
+ unsigned long flags;
+ int i, ret;

if (data[0] != WACOM_REPORT_DEVICE_LIST)
- return 0;
+ return;
+
+ memset(&remote_data, 0, sizeof(struct wacom_remote_data));

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
int j = i * 6;
int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
bool connected = data[j+2];

- if (connected) {
- int k;
-
- if (wacom_wac->serial[i] == serial)
- continue;
-
- if (wacom_wac->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
- }
-
- /* A remote can pair more than once with an EKR,
- * check to make sure this serial isn't already paired.
- */
- for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (wacom_wac->serial[k] == serial)
- break;
- }
+ remote_data.remote[i].serial = serial;
+ remote_data.remote[i].connected = connected;
+ }

- if (k < WACOM_MAX_REMOTES) {
- wacom_wac->serial[i] = serial;
- continue;
- }
- wacom_remote_create_attr_group(wacom, serial, i);
+ spin_lock_irqsave(&wacom->remote_lock, flags);

- } else if (wacom_wac->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
- }
+ ret = kfifo_in(&wacom->remote_fifo, &remote_data, sizeof(remote_data));
+ if (ret != sizeof(remote_data)) {
+ spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ hid_err(wacom->hdev, "Can't queue Remote status event.\n");
+ return;
}

- return 0;
+ spin_unlock_irqrestore(&wacom->remote_lock, flags);
+
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
}

static int wacom_intuos_general(struct wacom_wac *wacom)
@@ -2316,8 +2304,9 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
break;

case REMOTE:
+ sync = false;
if (wacom_wac->data[0] == WACOM_REPORT_DEVICE_LIST)
- sync = wacom_remote_status_irq(wacom_wac, len);
+ wacom_remote_status_irq(wacom_wac, len);
else
sync = wacom_remote_irq(wacom_wac, len);
break;
diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h
index feeb96d..d05daed 100644
--- a/3.17/wacom_wac.h
+++ b/3.17/wacom_wac.h
@@ -218,6 +218,13 @@ struct hid_data {
int num_received;
};

+struct wacom_remote_data {
+ struct {
+ u32 serial;
+ bool connected;
+ } remote[WACOM_MAX_REMOTES];
+};
+
struct wacom_wac {
char pen_name[WACOM_NAME_MAX];
char touch_name[WACOM_NAME_MAX];
diff --git a/3.7/wacom.h b/3.7/wacom.h
index 1666882..5d4361c 100644
--- a/3.7/wacom.h
+++ b/3.7/wacom.h
@@ -86,6 +86,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
+#include <linux/kfifo.h>
#include <linux/usb/input.h>
#include <linux/power_supply.h>
#include <asm/unaligned.h>
@@ -111,6 +112,7 @@ MODULE_LICENSE(DRIVER_LICENSE);
enum wacom_worker {
WACOM_WORKER_WIRELESS,
WACOM_WORKER_BATTERY,
+ WACOM_WORKER_REMOTE,
};

struct wacom {
@@ -122,6 +124,9 @@ struct wacom {
struct mutex lock;
struct work_struct wireless_work;
struct work_struct battery_work;
+ struct work_struct remote_work;
+ spinlock_t remote_lock;
+ struct kfifo remote_fifo;
bool open;
char phys[32];
struct wacom_led {
@@ -147,6 +152,9 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
case WACOM_WORKER_BATTERY:
schedule_work(&wacom->battery_work);
break;
+ case WACOM_WORKER_REMOTE:
+ schedule_work(&wacom->remote_work);
+ break;
}
}

@@ -157,7 +165,4 @@ void wacom_setup_device_quirks(struct wacom *wacom);
int wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac);
void wacom_battery_work(struct work_struct *work);
-int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
- int index);
-void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial);
#endif
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index d264c62..7afa189 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1265,7 +1265,7 @@ DEVICE_EKR_ATTR_GROUP(2);
DEVICE_EKR_ATTR_GROUP(3);
DEVICE_EKR_ATTR_GROUP(4);

-int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
+static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
{
int error = 0;
char *buf;
@@ -1290,7 +1290,7 @@ int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
return 0;
}

-void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
+static void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
{
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
int i;
@@ -1609,6 +1609,66 @@ void wacom_battery_work(struct work_struct *work)
}
}

+static void wacom_remote_work(struct work_struct *work)
+{
+ struct wacom *wacom = container_of(work, struct wacom, remote_work);
+ struct device *dev = &wacom->intf->dev;
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote_data data;
+ unsigned long flags;
+ unsigned int count;
+ u32 serial;
+ int i, k;
+
+ spin_lock_irqsave(&wacom->remote_lock, flags);
+
+ count = kfifo_out(&wacom->remote_fifo, &data, sizeof(data));
+
+ if (count != sizeof(data)) {
+ dev_err(dev,
+ "workitem triggered without status available\n");
+ spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ return;
+ }
+
+ if (!kfifo_is_empty(&wacom->remote_fifo))
+ wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_REMOTE);
+
+ spin_unlock_irqrestore(&wacom->remote_lock, flags);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ serial = data.remote[i].serial;
+ if (data.remote[i].connected) {
+
+ if (wacom_wac->serial[i] == serial)
+ continue;
+
+ if (wacom_wac->serial[i]) {
+ wacom_remote_destroy_attr_group(wacom,
+ wacom_wac->serial[i]);
+ }
+
+ /* A remote can pair more than once with an EKR,
+ * check to make sure this serial isn't already paired.
+ */
+ for (k = 0; k < WACOM_MAX_REMOTES; k++) {
+ if (wacom_wac->serial[k] == serial)
+ break;
+ }
+
+ if (k < WACOM_MAX_REMOTES) {
+ wacom_wac->serial[i] = serial;
+ continue;
+ }
+ wacom_remote_create_attr_group(wacom, serial, i);
+
+ } else if (wacom_wac->serial[i]) {
+ wacom_remote_destroy_attr_group(wacom,
+ wacom_wac->serial[i]);
+ }
+ }
+}
+
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
@@ -1656,6 +1716,18 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
mutex_init(&wacom->lock);
INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
INIT_WORK(&wacom->battery_work, wacom_battery_work);
+ INIT_WORK(&wacom->remote_work, wacom_remote_work);
+ spin_lock_init(&wacom->remote_lock);
+
+ if (kfifo_alloc(&wacom->remote_fifo,
+ 5 * sizeof(struct wacom_remote_data),
+ GFP_KERNEL)) {
+ dev_err(&wacom->intf->dev,
+ "%s:failed allocating remote_fifo\n", __func__);
+ error = -ENOMEM;
+ goto fail2;
+ }
+
usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));

@@ -1738,6 +1810,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
fail4: wacom_remove_shared_data(wacom_wac);
fail3: usb_free_urb(wacom->irq);
wacom_destroy_battery(wacom);
+ kfifo_free(&wacom->remote_fifo);
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
fail1:
return error;
@@ -1753,6 +1826,8 @@ static void wacom_disconnect(struct usb_interface *intf)
usb_kill_urb(wacom->irq);
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
+ cancel_work_sync(&wacom->remote_work);
+ kfifo_free(&wacom->remote_fifo);
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (wacom->remote_group[i].name) {
wacom_remote_destroy_attr_group(wacom,
diff --git a/3.7/wacom_wac.c b/3.7/wacom_wac.c
index 5887561..214e0e2 100644
--- a/3.7/wacom_wac.c
+++ b/3.7/wacom_wac.c
@@ -772,52 +772,41 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
return 1;
}

-static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
+static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+ struct device *dev = &wacom->intf->dev;
unsigned char *data = wacom_wac->data;
- int i;
+ struct wacom_remote_data remote_data;
+ unsigned long flags;
+ int i, ret;

if (data[0] != WACOM_REPORT_DEVICE_LIST)
- return 0;
+ return;
+
+ memset(&remote_data, 0, sizeof(struct wacom_remote_data));

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
int j = i * 6;
int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
bool connected = data[j+2];

- if (connected) {
- int k;
-
- if (wacom_wac->serial[i] == serial)
- continue;
-
- if (wacom_wac->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
- }
-
- /* A remote can pair more than once with an EKR,
- * check to make sure this serial isn't already paired.
- */
- for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (wacom_wac->serial[k] == serial)
- break;
- }
+ remote_data.remote[i].serial = serial;
+ remote_data.remote[i].connected = connected;
+ }

- if (k < WACOM_MAX_REMOTES) {
- wacom_wac->serial[i] = serial;
- continue;
- }
- wacom_remote_create_attr_group(wacom, serial, i);
+ spin_lock_irqsave(&wacom->remote_lock, flags);

- } else if (wacom_wac->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
- }
+ ret = kfifo_in(&wacom->remote_fifo, &remote_data, sizeof(remote_data));
+ if (ret != sizeof(remote_data)) {
+ spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ dev_err(dev, "Can't queue Remote status event.\n");
+ return;
}

- return 0;
+ spin_unlock_irqrestore(&wacom->remote_lock, flags);
+
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
}

static int wacom_intuos_general(struct wacom_wac *wacom)
@@ -1702,8 +1691,9 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
break;

case REMOTE:
+ sync = false;
if (wacom_wac->data[0] == WACOM_REPORT_DEVICE_LIST)
- sync = wacom_remote_status_irq(wacom_wac, len);
+ wacom_remote_status_irq(wacom_wac, len);
else
sync = wacom_remote_irq(wacom_wac, len);
break;
diff --git a/3.7/wacom_wac.h b/3.7/wacom_wac.h
index 4c47d10..0ade39c 100644
--- a/3.7/wacom_wac.h
+++ b/3.7/wacom_wac.h
@@ -165,6 +165,13 @@ struct wacom_shared {
struct input_dev *touch_input;
};

+struct wacom_remote_data {
+ struct {
+ u32 serial;
+ bool connected;
+ } remote[WACOM_MAX_REMOTES];
+};
+
struct wacom_wac {
char name[WACOM_NAME_MAX];
char bat_name[WACOM_NAME_MAX];
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:08 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

The wacom_remote_create_attr_group() and wacom_remote_destroy_attr_group()
functions were both allocating/destroying the sysfs groups but also
initializing the parameters for the remotes. Have proper functions
that can be called and extended.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (04bfa27)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (d1be8d4)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom_sys.c | 96 ++++++++++++++++++++++++++++++------------------------
3.17/wacom_sys.c | 93 +++++++++++++++++++++++++++++-----------------------
3.7/wacom_sys.c | 96 ++++++++++++++++++++++++++++++------------------------
3 files changed, 161 insertions(+), 124 deletions(-)

diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 303814b..85f08f2 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1277,8 +1277,6 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int
int error = 0;
struct wacom_remote *remote = wacom->remote;

- remote->serial[index] = serial;
-
remote->remote_group[index].name = kasprintf(GFP_KERNEL, "%d", serial);
if (!remote->remote_group[index].name)
return -ENOMEM;
@@ -1295,26 +1293,13 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int
return 0;
}

-static void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
+static void wacom_remote_destroy_attr_group(struct wacom *wacom, int i)
{
struct wacom_remote *remote = wacom->remote;
- int i;

- if (!serial)
- return;
-
- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (remote->serial[i] == serial) {
- remote->serial[i] = 0;
- wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
- if (remote->remote_group[i].name) {
- sysfs_remove_group(remote->remote_dir,
- &remote->remote_group[i]);
- kfree((char *)remote->remote_group[i].name);
- remote->remote_group[i].name = NULL;
- }
- }
- }
+ sysfs_remove_group(remote->remote_dir, &remote->remote_group[i]);
+ kfree((char *)remote->remote_group[i].name);
+ remote->remote_group[i].name = NULL;
}

static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
@@ -1338,6 +1323,50 @@ static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
return retval;
}

+static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ u32 serial = remote->serial[index];
+ int i;
+
+ wacom_remote_destroy_attr_group(wacom, index);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (remote->serial[i] == serial) {
+ remote->serial[i] = 0;
+ wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
+ }
+ }
+}
+
+static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
+ unsigned int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ int error, k;
+
+ /* A remote can pair more than once with an EKR,
+ * check to make sure this serial isn't already paired.
+ */
+ for (k = 0; k < WACOM_MAX_REMOTES; k++) {
+ if (remote->serial[k] == serial)
+ break;
+ }
+
+ if (k < WACOM_MAX_REMOTES) {
+ remote->serial[index] = serial;
+ return 0;
+ }
+
+ error = wacom_remote_create_attr_group(wacom, serial, index);
+ if (error)
+ return error;
+
+ remote->serial[index] = serial;
+
+ return 0;
+}
+
static ssize_t wacom_store_unpair_remote(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
@@ -1384,8 +1413,7 @@ static void wacom_remotes_destroy(void *data)

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (wacom->remote->remote_group[i].name) {
- wacom_remote_destroy_attr_group(wacom,
- wacom->wacom_wac.serial[i]);
+ wacom_remote_destroy_one(wacom, i);
}
}
kobject_put(remote->remote_dir);
@@ -1658,7 +1686,7 @@ static void wacom_remote_work(struct work_struct *work)
unsigned long flags;
unsigned int count;
u32 serial;
- int i, k;
+ int i;

spin_lock_irqsave(&remote->remote_lock, flags);

@@ -1683,28 +1711,13 @@ static void wacom_remote_work(struct work_struct *work)
if (remote->serial[i] == serial)
continue;

- if (remote->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- remote->serial[i]);
- }
-
- /* A remote can pair more than once with an EKR,
- * check to make sure this serial isn't already paired.
- */
- for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (remote->serial[k] == serial)
- break;
- }
+ if (remote->serial[i])
+ wacom_remote_destroy_one(wacom, i);

- if (k < WACOM_MAX_REMOTES) {
- remote->serial[i] = serial;
- continue;
- }
- wacom_remote_create_attr_group(wacom, serial, i);
+ wacom_remote_create_one(wacom, serial, i);

} else if (remote->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- remote->serial[i]);
+ wacom_remote_destroy_one(wacom, i);
}
}
}
@@ -1855,7 +1868,6 @@ static void wacom_disconnect(struct usb_interface *intf)
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
cancel_work_sync(&wacom->remote_work);
-
wacom_remotes_destroy(wacom);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 2dcd873..4c5c76b 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1352,8 +1352,6 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
int error = 0;
struct wacom_remote *remote = wacom->remote;

- remote->serial[index] = serial;
-
remote->remote_group[index].name = devm_kasprintf(&wacom->hdev->dev,
GFP_KERNEL,
"%d", serial);
@@ -1371,27 +1369,13 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
return 0;
}

-static void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
+static void wacom_remote_destroy_attr_group(struct wacom *wacom, unsigned int i)
{
struct wacom_remote *remote = wacom->remote;
- int i;

- if (!serial)
- return;
-
- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (remote->serial[i] == serial) {
- remote->serial[i] = 0;
- wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
- if (remote->remote_group[i].name) {
- sysfs_remove_group(remote->remote_dir,
- &remote->remote_group[i]);
- devm_kfree(&wacom->hdev->dev,
- (char *)remote->remote_group[i].name);
- remote->remote_group[i].name = NULL;
- }
- }
- }
+ sysfs_remove_group(remote->remote_dir, &remote->remote_group[i]);
+ devm_kfree(&wacom->hdev->dev, (char *)remote->remote_group[i].name);
+ remote->remote_group[i].name = NULL;
}

static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
@@ -1987,6 +1971,50 @@ fail:
return;
}

+static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ u32 serial = remote->serial[index];
+ int i;
+
+ wacom_remote_destroy_attr_group(wacom, index);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (remote->serial[i] == serial) {
+ remote->serial[i] = 0;
+ wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
+ }
+ }
+}
+
+static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
+ unsigned int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ int error, k;
+
+ /* A remote can pair more than once with an EKR,
+ * check to make sure this serial isn't already paired.
+ */
+ for (k = 0; k < WACOM_MAX_REMOTES; k++) {
+ if (remote->serial[k] == serial)
+ break;
+ }
+
+ if (k < WACOM_MAX_REMOTES) {
+ remote->serial[index] = serial;
+ return 0;
+ }
+
+ error = wacom_remote_create_attr_group(wacom, serial, index);
+ if (error)
+ return error;
+
+ remote->serial[index] = serial;
+
+ return 0;
+}
+
static void wacom_remote_work(struct work_struct *work)
{
struct wacom *wacom = container_of(work, struct wacom, remote_work);
@@ -1995,7 +2023,7 @@ static void wacom_remote_work(struct work_struct *work)
unsigned long flags;
unsigned int count;
u32 serial;
- int i, k;
+ int i;

spin_lock_irqsave(&remote->remote_lock, flags);

@@ -2020,28 +2048,13 @@ static void wacom_remote_work(struct work_struct *work)
if (remote->serial[i] == serial)
continue;

- if (remote->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- remote->serial[i]);
- }
-
- /* A remote can pair more than once with an EKR,
- * check to make sure this serial isn't already paired.
- */
- for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (remote->serial[k] == serial)
- break;
- }
+ if (remote->serial[i])
+ wacom_remote_destroy_one(wacom, i);

- if (k < WACOM_MAX_REMOTES) {
- remote->serial[i] = serial;
- continue;
- }
- wacom_remote_create_attr_group(wacom, serial, i);
+ wacom_remote_create_one(wacom, serial, i);

} else if (remote->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- remote->serial[i]);
+ wacom_remote_destroy_one(wacom, i);
}
}
}
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index 9755952..453ddaa 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1270,8 +1270,6 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int
int error = 0;
struct wacom_remote *remote = wacom->remote;

- remote->serial[index] = serial;
-
remote->remote_group[index].name = kasprintf(GFP_KERNEL, "%d", serial);
if (!remote->remote_group[index].name)
return -ENOMEM;
@@ -1287,26 +1285,13 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int
return 0;
}

-static void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
+static void wacom_remote_destroy_attr_group(struct wacom *wacom, int i)
{
struct wacom_remote *remote = wacom->remote;
- int i;

- if (!serial)
- return;
-
- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (remote->serial[i] == serial) {
- remote->serial[i] = 0;
- wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
- if (remote->remote_group[i].name) {
- sysfs_remove_group(remote->remote_dir,
- &remote->remote_group[i]);
- kfree((char *)remote->remote_group[i].name);
- remote->remote_group[i].name = NULL;
- }
- }
- }
+ sysfs_remove_group(remote->remote_dir, &remote->remote_group[i]);
+ kfree((char *)remote->remote_group[i].name);
+ remote->remote_group[i].name = NULL;
}

static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
@@ -1330,6 +1315,50 @@ static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
return retval;
}

+static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ u32 serial = remote->serial[index];
+ int i;
+
+ wacom_remote_destroy_attr_group(wacom, index);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (remote->serial[i] == serial) {
+ remote->serial[i] = 0;
+ wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
+ }
+ }
+}
+
+static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
+ unsigned int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ int error, k;
+
+ /* A remote can pair more than once with an EKR,
+ * check to make sure this serial isn't already paired.
+ */
+ for (k = 0; k < WACOM_MAX_REMOTES; k++) {
+ if (remote->serial[k] == serial)
+ break;
+ }
+
+ if (k < WACOM_MAX_REMOTES) {
+ remote->serial[index] = serial;
+ return 0;
+ }
+
+ error = wacom_remote_create_attr_group(wacom, serial, index);
+ if (error)
+ return error;
+
+ remote->serial[index] = serial;
+
+ return 0;
+}
+
static ssize_t wacom_store_unpair_remote(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
@@ -1375,8 +1404,7 @@ static void wacom_remotes_destroy(struct wacom *wacom)

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (wacom->remote->remote_group[i].name) {
- wacom_remote_destroy_attr_group(wacom,
- wacom->wacom_wac.serial[i]);
+ wacom_remote_destroy_one(wacom, i);
}
}
kobject_put(remote->remote_dir);
@@ -1652,7 +1680,7 @@ static void wacom_remote_work(struct work_struct *work)
unsigned long flags;
unsigned int count;
u32 serial;
- int i, k;
+ int i;

spin_lock_irqsave(&remote->remote_lock, flags);

@@ -1677,28 +1705,13 @@ static void wacom_remote_work(struct work_struct *work)
if (remote->serial[i] == serial)
continue;

- if (remote->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- remote->serial[i]);
- }
-
- /* A remote can pair more than once with an EKR,
- * check to make sure this serial isn't already paired.
- */
- for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (remote->serial[k] == serial)
- break;
- }
+ if (remote->serial[i])
+ wacom_remote_destroy_one(wacom, i);

- if (k < WACOM_MAX_REMOTES) {
- remote->serial[i] = serial;
- continue;
- }
- wacom_remote_create_attr_group(wacom, serial, i);
+ wacom_remote_create_one(wacom, serial, i);

} else if (remote->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- remote->serial[i]);
+ wacom_remote_destroy_one(wacom, i);
}
}
}
@@ -1849,7 +1862,6 @@ static void wacom_disconnect(struct usb_interface *intf)
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
cancel_work_sync(&wacom->remote_work);
-
wacom_remotes_destroy(wacom);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:06 UTC
Permalink
If we want to have one input device per remote, it's better to have our
own struct wacom_remote which is dynamically allocated.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (83e6b40)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (3c055ea)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom.h | 13 +++--
2.6.38/wacom_sys.c | 144 ++++++++++++++++++++++++++++++-----------------------
2.6.38/wacom_wac.c | 12 +++--
2.6.38/wacom_wac.h | 2 +-
3.17/wacom.h | 13 +++--
3.17/wacom_sys.c | 133 ++++++++++++++++++++++++++++---------------------
3.17/wacom_wac.c | 12 +++--
3.17/wacom_wac.h | 2 +-
3.7/wacom.h | 13 +++--
3.7/wacom_sys.c | 142 +++++++++++++++++++++++++++++-----------------------
3.7/wacom_wac.c | 12 +++--
3.7/wacom_wac.h | 2 +-
12 files changed, 288 insertions(+), 212 deletions(-)

diff --git a/2.6.38/wacom.h b/2.6.38/wacom.h
index b4470b3..e0c7be1 100644
--- a/2.6.38/wacom.h
+++ b/2.6.38/wacom.h
@@ -119,6 +119,14 @@ enum wacom_worker {
WACOM_WORKER_REMOTE,
};

+struct wacom_remote {
+ spinlock_t remote_lock;
+ struct kfifo remote_fifo;
+ struct kobject *remote_dir;
+ struct attribute_group remote_group[WACOM_MAX_REMOTES];
+ __u32 serial[WACOM_MAX_REMOTES];
+};
+
struct wacom {
dma_addr_t data_dma;
struct usb_device *usbdev;
@@ -129,8 +137,7 @@ struct wacom {
struct work_struct wireless_work;
struct work_struct battery_work;
struct work_struct remote_work;
- spinlock_t remote_lock;
- struct kfifo remote_fifo;
+ struct wacom_remote *remote;
bool open;
char phys[32];
struct wacom_led {
@@ -140,8 +147,6 @@ struct wacom {
u8 img_lum; /* OLED matrix display brightness */
} led;
struct power_supply battery;
- struct kobject *remote_dir;
- struct attribute_group remote_group[5];
};

static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 12a3c66..303814b 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1275,19 +1275,17 @@ DEVICE_EKR_ATTR_GROUP(4);
static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
{
int error = 0;
- char *buf;
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote *remote = wacom->remote;

- wacom_wac->serial[index] = serial;
+ remote->serial[index] = serial;

- buf = kzalloc(WAC_REMOTE_SERIAL_MAX_STRLEN, GFP_KERNEL);
- if (!buf)
+ remote->remote_group[index].name = kasprintf(GFP_KERNEL, "%d", serial);
+ if (!remote->remote_group[index].name)
return -ENOMEM;
- snprintf(buf, WAC_REMOTE_SERIAL_MAX_STRLEN, "%d", serial);
- wacom->remote_group[index].name = buf;

- error = sysfs_create_group(wacom->remote_dir,
- &wacom->remote_group[index]);
+ error = sysfs_create_group(remote->remote_dir,
+ &remote->remote_group[index]);
+
if (error) {
dev_err(&wacom->intf->dev,
"cannot create sysfs group err: %d\n", error);
@@ -1299,21 +1297,21 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int

static void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
{
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote *remote = wacom->remote;
int i;

if (!serial)
return;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom_wac->serial[i] == serial) {
- wacom_wac->serial[i] = 0;
+ if (remote->serial[i] == serial) {
+ remote->serial[i] = 0;
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
- if (wacom->remote_group[i].name) {
- sysfs_remove_group(wacom->remote_dir,
- &wacom->remote_group[i]);
- kfree(wacom->remote_group[i].name);
- wacom->remote_group[i].name = NULL;
+ if (remote->remote_group[i].name) {
+ sysfs_remove_group(remote->remote_dir,
+ &remote->remote_group[i]);
+ kfree((char *)remote->remote_group[i].name);
+ remote->remote_group[i].name = NULL;
}
}
}
@@ -1375,27 +1373,65 @@ static const struct attribute *remote_unpair_attrs[] = {
NULL
};

-static int wacom_initialize_remote(struct wacom *wacom)
+static void wacom_remotes_destroy(void *data)
+{
+ struct wacom *wacom = data;
+ struct wacom_remote *remote = wacom->remote;
+ int i;
+
+ if (!remote)
+ return;
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (wacom->remote->remote_group[i].name) {
+ wacom_remote_destroy_attr_group(wacom,
+ wacom->wacom_wac.serial[i]);
+ }
+ }
+ kobject_put(remote->remote_dir);
+ kfifo_free(&remote->remote_fifo);
+ wacom->remote = NULL;
+}
+
+static int wacom_initialize_remotes(struct wacom *wacom)
{
int error = 0;
- struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+ struct wacom_remote *remote;
int i;

if (wacom->wacom_wac.features.type != REMOTE)
return 0;

- wacom->remote_group[0] = remote0_serial_group;
- wacom->remote_group[1] = remote1_serial_group;
- wacom->remote_group[2] = remote2_serial_group;
- wacom->remote_group[3] = remote3_serial_group;
- wacom->remote_group[4] = remote4_serial_group;
+ remote = devm_kzalloc(&wacom->usbdev->dev, sizeof(*wacom->remote),
+ GFP_KERNEL);
+ if (!remote)
+ return -ENOMEM;
+
+ wacom->remote = remote;
+
+ spin_lock_init(&remote->remote_lock);

- wacom->remote_dir = kobject_create_and_add("wacom_remote",
- &wacom->intf->dev.kobj);
- if (!wacom->remote_dir)
+ error = kfifo_alloc(&remote->remote_fifo,
+ 5 * sizeof(struct wacom_remote_data),
+ GFP_KERNEL);
+ if (error) {
+ dev_err(&wacom->intf->dev, "failed allocating remote_fifo\n");
return -ENOMEM;
+ }

- error = sysfs_create_files(wacom->remote_dir, remote_unpair_attrs);
+ remote->remote_group[0] = remote0_serial_group;
+ remote->remote_group[1] = remote1_serial_group;
+ remote->remote_group[2] = remote2_serial_group;
+ remote->remote_group[3] = remote3_serial_group;
+ remote->remote_group[4] = remote4_serial_group;
+
+ remote->remote_dir = kobject_create_and_add("wacom_remote",
+ &wacom->intf->dev.kobj);
+
+ if (!remote->remote_dir)
+ return -ENOMEM;
+
+ error = sysfs_create_files(remote->remote_dir, remote_unpair_attrs);

if (error) {
dev_err(&wacom->intf->dev,
@@ -1405,7 +1441,7 @@ static int wacom_initialize_remote(struct wacom *wacom)

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
- wacom_wac->serial[i] = 0;
+ remote->serial[i] = 0;
}

return 0;
@@ -1617,58 +1653,58 @@ static void wacom_remote_work(struct work_struct *work)
{
struct wacom *wacom = container_of(work, struct wacom, remote_work);
struct device *dev = &wacom->intf->dev;
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote *remote = wacom->remote;
struct wacom_remote_data data;
unsigned long flags;
unsigned int count;
u32 serial;
int i, k;

- spin_lock_irqsave(&wacom->remote_lock, flags);
+ spin_lock_irqsave(&remote->remote_lock, flags);

- count = kfifo_out(&wacom->remote_fifo, &data, sizeof(data));
+ count = kfifo_out(&remote->remote_fifo, &data, sizeof(data));

if (count != sizeof(data)) {
dev_err(dev,
"workitem triggered without status available\n");
- spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
return;
}

- if (!kfifo_is_empty(&wacom->remote_fifo))
+ if (!kfifo_is_empty(&remote->remote_fifo))
wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_REMOTE);

- spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ spin_unlock_irqrestore(&remote->remote_lock, flags);

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
serial = data.remote[i].serial;
if (data.remote[i].connected) {

- if (wacom_wac->serial[i] == serial)
+ if (remote->serial[i] == serial)
continue;

- if (wacom_wac->serial[i]) {
+ if (remote->serial[i]) {
wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
+ remote->serial[i]);
}

/* A remote can pair more than once with an EKR,
* check to make sure this serial isn't already paired.
*/
for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (wacom_wac->serial[k] == serial)
+ if (remote->serial[k] == serial)
break;
}

if (k < WACOM_MAX_REMOTES) {
- wacom_wac->serial[i] = serial;
+ remote->serial[i] = serial;
continue;
}
wacom_remote_create_attr_group(wacom, serial, i);

- } else if (wacom_wac->serial[i]) {
+ } else if (remote->serial[i]) {
wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
+ remote->serial[i]);
}
}
}
@@ -1721,16 +1757,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
INIT_WORK(&wacom->battery_work, wacom_battery_work);
INIT_WORK(&wacom->remote_work, wacom_remote_work);
- spin_lock_init(&wacom->remote_lock);
-
- if (kfifo_alloc(&wacom->remote_fifo,
- 5 * sizeof(struct wacom_remote_data),
- GFP_KERNEL)) {
- dev_err(&wacom->intf->dev,
- "%s:failed allocating remote_fifo\n", __func__);
- error = -ENOMEM;
- goto fail2;
- }

usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
@@ -1795,7 +1821,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
goto fail4;

if (wacom->wacom_wac.features.type == REMOTE) {
- error = wacom_initialize_remote(wacom);
+ error = wacom_initialize_remotes(wacom);
if (error)
goto fail4;
}
@@ -1814,7 +1840,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
fail4: wacom_remove_shared_data(wacom_wac);
fail3: usb_free_urb(wacom->irq);
wacom_destroy_battery(wacom);
- kfifo_free(&wacom->remote_fifo);
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
fail1:
return error;
@@ -1823,7 +1848,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
static void wacom_disconnect(struct usb_interface *intf)
{
struct wacom *wacom = usb_get_intfdata(intf);
- int i;

usb_set_intfdata(intf, NULL);

@@ -1831,14 +1855,8 @@ static void wacom_disconnect(struct usb_interface *intf)
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
cancel_work_sync(&wacom->remote_work);
- kfifo_free(&wacom->remote_fifo);
- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom->remote_group[i].name) {
- wacom_remote_destroy_attr_group(wacom,
- wacom->wacom_wac.serial[i]);
- }
- }
- kobject_put(wacom->remote_dir);
+
+ wacom_remotes_destroy(wacom);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
usb_free_urb(wacom->irq);
diff --git a/2.6.38/wacom_wac.c b/2.6.38/wacom_wac.c
index 4361d55..7ccd5bc 100644
--- a/2.6.38/wacom_wac.c
+++ b/2.6.38/wacom_wac.c
@@ -703,6 +703,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
struct input_dev *input = wacom_wac->input;
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
struct wacom_features *features = &wacom_wac->features;
+ struct wacom_remote *remote = wacom->remote;
int bat_charging, bat_percent, touch_ring_mode;
__u32 serial;
int i;
@@ -755,7 +756,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
touch_ring_mode = (data[11] & 0xC0) >> 6;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom_wac->serial[i] == serial)
+ if (remote->serial[i] == serial)
wacom->led.select[i] = touch_ring_mode;
}

@@ -775,6 +776,7 @@ static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
struct device *dev = &wacom->intf->dev;
unsigned char *data = wacom_wac->data;
+ struct wacom_remote *remote = wacom->remote;
struct wacom_remote_data remote_data;
unsigned long flags;
int i, ret;
@@ -793,16 +795,16 @@ static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
remote_data.remote[i].connected = connected;
}

- spin_lock_irqsave(&wacom->remote_lock, flags);
+ spin_lock_irqsave(&remote->remote_lock, flags);

- ret = kfifo_in(&wacom->remote_fifo, &remote_data, sizeof(remote_data));
+ ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
if (ret != sizeof(remote_data)) {
- spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
dev_err(dev, "Can't queue Remote status event.\n");
return;
}

- spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ spin_unlock_irqrestore(&remote->remote_lock, flags);

wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
}
diff --git a/2.6.38/wacom_wac.h b/2.6.38/wacom_wac.h
index 17ca409..abe52fb 100644
--- a/2.6.38/wacom_wac.h
+++ b/2.6.38/wacom_wac.h
@@ -178,7 +178,7 @@ struct wacom_wac {
unsigned char *data;
int tool[2];
int id[2];
- __u32 serial[5];
+ __u32 serial[2];
bool reporting_data;
struct wacom_features features;
struct wacom_shared *shared;
diff --git a/3.17/wacom.h b/3.17/wacom.h
index 6b7032f..d2c9548 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -130,6 +130,14 @@ struct wacom_group_leds {
u8 select; /* status led selector (0..3) */
};

+struct wacom_remote {
+ spinlock_t remote_lock;
+ struct kfifo remote_fifo;
+ struct kobject *remote_dir;
+ struct attribute_group remote_group[WACOM_MAX_REMOTES];
+ __u32 serial[WACOM_MAX_REMOTES];
+};
+
struct wacom {
struct usb_device *usbdev;
struct usb_interface *intf;
@@ -139,8 +147,7 @@ struct wacom {
struct work_struct wireless_work;
struct work_struct battery_work;
struct work_struct remote_work;
- spinlock_t remote_lock;
- struct kfifo remote_fifo;
+ struct wacom_remote *remote;
struct wacom_leds {
struct wacom_group_leds *groups;
u8 llv; /* status led brightness no button (1..127) */
@@ -156,8 +163,6 @@ struct wacom {
struct power_supply battery;
struct power_supply ac;
#endif
- struct kobject *remote_dir;
- struct attribute_group remote_group[5];
bool resources;
};

diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 696efa5..6acf07f 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1350,18 +1350,18 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
int index)
{
int error = 0;
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote *remote = wacom->remote;

- wacom_wac->serial[index] = serial;
+ remote->serial[index] = serial;

- wacom->remote_group[index].name = devm_kasprintf(&wacom->hdev->dev,
- GFP_KERNEL,
- "%d", serial);
- if (!wacom->remote_group[index].name)
+ remote->remote_group[index].name = devm_kasprintf(&wacom->hdev->dev,
+ GFP_KERNEL,
+ "%d", serial);
+ if (!remote->remote_group[index].name)
return -ENOMEM;

- error = sysfs_create_group(wacom->remote_dir,
- &wacom->remote_group[index]);
+ error = sysfs_create_group(remote->remote_dir,
+ &remote->remote_group[index]);
if (error) {
hid_err(wacom->hdev,
"cannot create sysfs group err: %d\n", error);
@@ -1373,22 +1373,22 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,

static void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
{
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote *remote = wacom->remote;
int i;

if (!serial)
return;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom_wac->serial[i] == serial) {
- wacom_wac->serial[i] = 0;
+ if (remote->serial[i] == serial) {
+ remote->serial[i] = 0;
wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
- if (wacom->remote_group[i].name) {
- sysfs_remove_group(wacom->remote_dir,
- &wacom->remote_group[i]);
+ if (remote->remote_group[i].name) {
+ sysfs_remove_group(remote->remote_dir,
+ &remote->remote_group[i]);
devm_kfree(&wacom->hdev->dev,
- (char *)wacom->remote_group[i].name);
- wacom->remote_group[i].name = NULL;
+ (char *)remote->remote_group[i].name);
+ remote->remote_group[i].name = NULL;
}
}
}
@@ -1450,27 +1450,57 @@ static const struct attribute *remote_unpair_attrs[] = {
NULL
};

-static int wacom_initialize_remote(struct wacom *wacom)
+static void wacom_remotes_destroy(void *data)
+{
+ struct wacom *wacom = data;
+ struct wacom_remote *remote = wacom->remote;
+
+ if (!remote)
+ return;
+
+ kobject_put(remote->remote_dir);
+ kfifo_free(&remote->remote_fifo);
+ wacom->remote = NULL;
+}
+
+static int wacom_initialize_remotes(struct wacom *wacom)
{
int error = 0;
- struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+ struct wacom_remote *remote;
int i;

if (wacom->wacom_wac.features.type != REMOTE)
return 0;

- wacom->remote_group[0] = remote0_serial_group;
- wacom->remote_group[1] = remote1_serial_group;
- wacom->remote_group[2] = remote2_serial_group;
- wacom->remote_group[3] = remote3_serial_group;
- wacom->remote_group[4] = remote4_serial_group;
+ remote = devm_kzalloc(&wacom->hdev->dev, sizeof(*wacom->remote),
+ GFP_KERNEL);
+ if (!remote)
+ return -ENOMEM;

- wacom->remote_dir = kobject_create_and_add("wacom_remote",
- &wacom->hdev->dev.kobj);
- if (!wacom->remote_dir)
+ wacom->remote = remote;
+
+ spin_lock_init(&remote->remote_lock);
+
+ error = kfifo_alloc(&remote->remote_fifo,
+ 5 * sizeof(struct wacom_remote_data),
+ GFP_KERNEL);
+ if (error) {
+ hid_err(wacom->hdev, "failed allocating remote_fifo\n");
return -ENOMEM;
+ }

- error = sysfs_create_files(wacom->remote_dir, remote_unpair_attrs);
+ remote->remote_group[0] = remote0_serial_group;
+ remote->remote_group[1] = remote1_serial_group;
+ remote->remote_group[2] = remote2_serial_group;
+ remote->remote_group[3] = remote3_serial_group;
+ remote->remote_group[4] = remote4_serial_group;
+
+ remote->remote_dir = kobject_create_and_add("wacom_remote",
+ &wacom->hdev->dev.kobj);
+ if (!remote->remote_dir)
+ return -ENOMEM;
+
+ error = sysfs_create_files(remote->remote_dir, remote_unpair_attrs);

if (error) {
hid_err(wacom->hdev,
@@ -1480,9 +1510,14 @@ static int wacom_initialize_remote(struct wacom *wacom)

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
- wacom_wac->serial[i] = 0;
+ remote->serial[i] = 0;
}

+ error = devm_add_action_or_reset(&wacom->hdev->dev,
+ wacom_remotes_destroy, wacom);
+ if (error)
+ return error;
+
return 0;
}

@@ -1796,7 +1831,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
if (error)
goto fail_leds;

- error = wacom_initialize_remote(wacom);
+ error = wacom_initialize_remotes(wacom);
if (error)
goto fail_remote;
}
@@ -1852,7 +1887,6 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
fail_quirks:
hid_hw_stop(hdev);
fail_hw_start:
- kobject_put(wacom->remote_dir);
fail_remote:
fail_leds:
fail_register_inputs:
@@ -1956,58 +1990,58 @@ fail:
static void wacom_remote_work(struct work_struct *work)
{
struct wacom *wacom = container_of(work, struct wacom, remote_work);
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote *remote = wacom->remote;
struct wacom_remote_data data;
unsigned long flags;
unsigned int count;
u32 serial;
int i, k;

- spin_lock_irqsave(&wacom->remote_lock, flags);
+ spin_lock_irqsave(&remote->remote_lock, flags);

- count = kfifo_out(&wacom->remote_fifo, &data, sizeof(data));
+ count = kfifo_out(&remote->remote_fifo, &data, sizeof(data));

if (count != sizeof(data)) {
hid_err(wacom->hdev,
"workitem triggered without status available\n");
- spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
return;
}

- if (!kfifo_is_empty(&wacom->remote_fifo))
+ if (!kfifo_is_empty(&remote->remote_fifo))
wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_REMOTE);

- spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ spin_unlock_irqrestore(&remote->remote_lock, flags);

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
serial = data.remote[i].serial;
if (data.remote[i].connected) {

- if (wacom_wac->serial[i] == serial)
+ if (remote->serial[i] == serial)
continue;

- if (wacom_wac->serial[i]) {
+ if (remote->serial[i]) {
wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
+ remote->serial[i]);
}

/* A remote can pair more than once with an EKR,
* check to make sure this serial isn't already paired.
*/
for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (wacom_wac->serial[k] == serial)
+ if (remote->serial[k] == serial)
break;
}

if (k < WACOM_MAX_REMOTES) {
- wacom_wac->serial[i] = serial;
+ remote->serial[i] = serial;
continue;
}
wacom_remote_create_attr_group(wacom, serial, i);

- } else if (wacom_wac->serial[i]) {
+ } else if (remote->serial[i]) {
wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
+ remote->serial[i]);
}
}
}
@@ -2055,16 +2089,6 @@ static int wacom_probe(struct hid_device *hdev,
INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
INIT_WORK(&wacom->battery_work, wacom_battery_work);
INIT_WORK(&wacom->remote_work, wacom_remote_work);
- spin_lock_init(&wacom->remote_lock);
-
- if (kfifo_alloc(&wacom->remote_fifo,
- 5 * sizeof(struct wacom_remote_data),
- GFP_KERNEL)) {
- dev_err(&hdev->dev,
- "%s:failed allocating remote_fifo\n", __func__);
- error = -ENOMEM;
- goto fail_type;
- }

/* ask for the report descriptor to be loaded by HID */
error = hid_parse(hdev);
@@ -2088,7 +2112,6 @@ static int wacom_probe(struct hid_device *hdev,
return 0;

fail_parse:
- kfifo_free(&wacom->remote_fifo);
fail_type:
hid_set_drvdata(hdev, NULL);
return error;
@@ -2108,8 +2131,6 @@ static void wacom_remove(struct hid_device *hdev)
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
cancel_work_sync(&wacom->remote_work);
- kfifo_free(&wacom->remote_fifo);
- kobject_put(wacom->remote_dir);
if (hdev->bus == BUS_BLUETOOTH)
device_remove_file(&hdev->dev, &dev_attr_speed);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 298d5b3..7ab1553 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -759,6 +759,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
unsigned char *data = wacom_wac->data;
struct input_dev *input = wacom_wac->pad_input;
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+ struct wacom_remote *remote = wacom->remote;
struct wacom_features *features = &wacom_wac->features;
int bat_charging, bat_percent, touch_ring_mode;
__u32 serial;
@@ -813,7 +814,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
touch_ring_mode = (data[11] & 0xC0) >> 6;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom_wac->serial[i] == serial)
+ if (remote->serial[i] == serial)
wacom->led.groups[i].select = touch_ring_mode;
}

@@ -833,6 +834,7 @@ static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
unsigned char *data = wacom_wac->data;
+ struct wacom_remote *remote = wacom->remote;
struct wacom_remote_data remote_data;
unsigned long flags;
int i, ret;
@@ -851,16 +853,16 @@ static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
remote_data.remote[i].connected = connected;
}

- spin_lock_irqsave(&wacom->remote_lock, flags);
+ spin_lock_irqsave(&remote->remote_lock, flags);

- ret = kfifo_in(&wacom->remote_fifo, &remote_data, sizeof(remote_data));
+ ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
if (ret != sizeof(remote_data)) {
- spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
hid_err(wacom->hdev, "Can't queue Remote status event.\n");
return;
}

- spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ spin_unlock_irqrestore(&remote->remote_lock, flags);

wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
}
diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h
index d05daed..b3c1a09 100644
--- a/3.17/wacom_wac.h
+++ b/3.17/wacom_wac.h
@@ -234,7 +234,7 @@ struct wacom_wac {
unsigned char data[WACOM_PKGLEN_MAX];
int tool[2];
int id[2];
- __u32 serial[5];
+ __u32 serial[2];
bool reporting_data;
struct wacom_features features;
struct wacom_shared *shared;
diff --git a/3.7/wacom.h b/3.7/wacom.h
index 5d4361c..2067a5c 100644
--- a/3.7/wacom.h
+++ b/3.7/wacom.h
@@ -115,6 +115,14 @@ enum wacom_worker {
WACOM_WORKER_REMOTE,
};

+struct wacom_remote {
+ spinlock_t remote_lock;
+ struct kfifo remote_fifo;
+ struct kobject *remote_dir;
+ struct attribute_group remote_group[WACOM_MAX_REMOTES];
+ __u32 serial[WACOM_MAX_REMOTES];
+};
+
struct wacom {
dma_addr_t data_dma;
struct usb_device *usbdev;
@@ -125,8 +133,7 @@ struct wacom {
struct work_struct wireless_work;
struct work_struct battery_work;
struct work_struct remote_work;
- spinlock_t remote_lock;
- struct kfifo remote_fifo;
+ struct wacom_remote *remote;
bool open;
char phys[32];
struct wacom_led {
@@ -136,8 +143,6 @@ struct wacom {
u8 img_lum; /* OLED matrix display brightness */
} led;
struct power_supply battery;
- struct kobject *remote_dir;
- struct attribute_group remote_group[5];
};

static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index 7afa189..9755952 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1268,19 +1268,16 @@ DEVICE_EKR_ATTR_GROUP(4);
static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
{
int error = 0;
- char *buf;
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote *remote = wacom->remote;

- wacom_wac->serial[index] = serial;
+ remote->serial[index] = serial;

- buf = kzalloc(WAC_REMOTE_SERIAL_MAX_STRLEN, GFP_KERNEL);
- if (!buf)
+ remote->remote_group[index].name = kasprintf(GFP_KERNEL, "%d", serial);
+ if (!remote->remote_group[index].name)
return -ENOMEM;
- snprintf(buf, WAC_REMOTE_SERIAL_MAX_STRLEN, "%d", serial);
- wacom->remote_group[index].name = buf;

- error = sysfs_create_group(wacom->remote_dir,
- &wacom->remote_group[index]);
+ error = sysfs_create_group(remote->remote_dir,
+ &remote->remote_group[index]);
if (error) {
dev_err(&wacom->intf->dev,
"cannot create sysfs group err: %d\n", error);
@@ -1292,21 +1289,21 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int

static void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
{
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote *remote = wacom->remote;
int i;

if (!serial)
return;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom_wac->serial[i] == serial) {
- wacom_wac->serial[i] = 0;
+ if (remote->serial[i] == serial) {
+ remote->serial[i] = 0;
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
- if (wacom->remote_group[i].name) {
- sysfs_remove_group(wacom->remote_dir,
- &wacom->remote_group[i]);
- kfree(wacom->remote_group[i].name);
- wacom->remote_group[i].name = NULL;
+ if (remote->remote_group[i].name) {
+ sysfs_remove_group(remote->remote_dir,
+ &remote->remote_group[i]);
+ kfree((char *)remote->remote_group[i].name);
+ remote->remote_group[i].name = NULL;
}
}
}
@@ -1368,27 +1365,64 @@ static const struct attribute *remote_unpair_attrs[] = {
NULL
};

-static int wacom_initialize_remote(struct wacom *wacom)
+static void wacom_remotes_destroy(struct wacom *wacom)
+{
+ struct wacom_remote *remote = wacom->remote;
+ int i;
+
+ if (!remote)
+ return;
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (wacom->remote->remote_group[i].name) {
+ wacom_remote_destroy_attr_group(wacom,
+ wacom->wacom_wac.serial[i]);
+ }
+ }
+ kobject_put(remote->remote_dir);
+ kfifo_free(&remote->remote_fifo);
+ wacom->remote = NULL;
+}
+
+static int wacom_initialize_remotes(struct wacom *wacom)
{
int error = 0;
- struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+ struct wacom_remote *remote;
int i;

if (wacom->wacom_wac.features.type != REMOTE)
return 0;

- wacom->remote_group[0] = remote0_serial_group;
- wacom->remote_group[1] = remote1_serial_group;
- wacom->remote_group[2] = remote2_serial_group;
- wacom->remote_group[3] = remote3_serial_group;
- wacom->remote_group[4] = remote4_serial_group;
+ remote = devm_kzalloc(&wacom->usbdev->dev, sizeof(*wacom->remote),
+ GFP_KERNEL);
+ if (!remote)
+ return -ENOMEM;
+
+ wacom->remote = remote;

- wacom->remote_dir = kobject_create_and_add("wacom_remote",
- &wacom->intf->dev.kobj);
- if (!wacom->remote_dir)
+ spin_lock_init(&remote->remote_lock);
+
+ error = kfifo_alloc(&remote->remote_fifo,
+ 5 * sizeof(struct wacom_remote_data),
+ GFP_KERNEL);
+ if (error) {
+ dev_err(&wacom->intf->dev, "failed allocating remote_fifo\n");
+ return -ENOMEM;
+ }
+
+ remote->remote_group[0] = remote0_serial_group;
+ remote->remote_group[1] = remote1_serial_group;
+ remote->remote_group[2] = remote2_serial_group;
+ remote->remote_group[3] = remote3_serial_group;
+ remote->remote_group[4] = remote4_serial_group;
+
+ remote->remote_dir = kobject_create_and_add("wacom_remote",
+ &wacom->intf->dev.kobj);
+
+ if (!remote->remote_dir)
return -ENOMEM;

- error = sysfs_create_files(wacom->remote_dir, remote_unpair_attrs);
+ error = sysfs_create_files(remote->remote_dir, remote_unpair_attrs);

if (error) {
dev_err(&wacom->intf->dev,
@@ -1398,7 +1432,7 @@ static int wacom_initialize_remote(struct wacom *wacom)

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
- wacom_wac->serial[i] = 0;
+ remote->serial[i] = 0;
}

return 0;
@@ -1613,58 +1647,58 @@ static void wacom_remote_work(struct work_struct *work)
{
struct wacom *wacom = container_of(work, struct wacom, remote_work);
struct device *dev = &wacom->intf->dev;
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_remote *remote = wacom->remote;
struct wacom_remote_data data;
unsigned long flags;
unsigned int count;
u32 serial;
int i, k;

- spin_lock_irqsave(&wacom->remote_lock, flags);
+ spin_lock_irqsave(&remote->remote_lock, flags);

- count = kfifo_out(&wacom->remote_fifo, &data, sizeof(data));
+ count = kfifo_out(&remote->remote_fifo, &data, sizeof(data));

if (count != sizeof(data)) {
dev_err(dev,
"workitem triggered without status available\n");
- spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
return;
}

- if (!kfifo_is_empty(&wacom->remote_fifo))
+ if (!kfifo_is_empty(&remote->remote_fifo))
wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_REMOTE);

- spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ spin_unlock_irqrestore(&remote->remote_lock, flags);

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
serial = data.remote[i].serial;
if (data.remote[i].connected) {

- if (wacom_wac->serial[i] == serial)
+ if (remote->serial[i] == serial)
continue;

- if (wacom_wac->serial[i]) {
+ if (remote->serial[i]) {
wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
+ remote->serial[i]);
}

/* A remote can pair more than once with an EKR,
* check to make sure this serial isn't already paired.
*/
for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (wacom_wac->serial[k] == serial)
+ if (remote->serial[k] == serial)
break;
}

if (k < WACOM_MAX_REMOTES) {
- wacom_wac->serial[i] = serial;
+ remote->serial[i] = serial;
continue;
}
wacom_remote_create_attr_group(wacom, serial, i);

- } else if (wacom_wac->serial[i]) {
+ } else if (remote->serial[i]) {
wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
+ remote->serial[i]);
}
}
}
@@ -1717,16 +1751,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
INIT_WORK(&wacom->battery_work, wacom_battery_work);
INIT_WORK(&wacom->remote_work, wacom_remote_work);
- spin_lock_init(&wacom->remote_lock);
-
- if (kfifo_alloc(&wacom->remote_fifo,
- 5 * sizeof(struct wacom_remote_data),
- GFP_KERNEL)) {
- dev_err(&wacom->intf->dev,
- "%s:failed allocating remote_fifo\n", __func__);
- error = -ENOMEM;
- goto fail2;
- }

usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
@@ -1791,7 +1815,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
goto fail4;

if (wacom->wacom_wac.features.type == REMOTE) {
- error = wacom_initialize_remote(wacom);
+ error = wacom_initialize_remotes(wacom);
if (error)
goto fail4;
}
@@ -1810,7 +1834,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
fail4: wacom_remove_shared_data(wacom_wac);
fail3: usb_free_urb(wacom->irq);
wacom_destroy_battery(wacom);
- kfifo_free(&wacom->remote_fifo);
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
fail1:
return error;
@@ -1819,7 +1842,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
static void wacom_disconnect(struct usb_interface *intf)
{
struct wacom *wacom = usb_get_intfdata(intf);
- int i;

usb_set_intfdata(intf, NULL);

@@ -1827,14 +1849,8 @@ static void wacom_disconnect(struct usb_interface *intf)
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
cancel_work_sync(&wacom->remote_work);
- kfifo_free(&wacom->remote_fifo);
- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom->remote_group[i].name) {
- wacom_remote_destroy_attr_group(wacom,
- wacom->wacom_wac.serial[i]);
- }
- }
- kobject_put(wacom->remote_dir);
+
+ wacom_remotes_destroy(wacom);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
usb_free_urb(wacom->irq);
diff --git a/3.7/wacom_wac.c b/3.7/wacom_wac.c
index 214e0e2..bd6c32a 100644
--- a/3.7/wacom_wac.c
+++ b/3.7/wacom_wac.c
@@ -703,6 +703,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
struct input_dev *input = wacom_wac->input;
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
struct wacom_features *features = &wacom_wac->features;
+ struct wacom_remote *remote = wacom->remote;
int bat_charging, bat_percent, touch_ring_mode;
__u32 serial;
int i;
@@ -756,7 +757,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
touch_ring_mode = (data[11] & 0xC0) >> 6;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom_wac->serial[i] == serial)
+ if (remote->serial[i] == serial)
wacom->led.select[i] = touch_ring_mode;
}

@@ -777,6 +778,7 @@ static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
struct device *dev = &wacom->intf->dev;
unsigned char *data = wacom_wac->data;
+ struct wacom_remote *remote = wacom->remote;
struct wacom_remote_data remote_data;
unsigned long flags;
int i, ret;
@@ -795,16 +797,16 @@ static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
remote_data.remote[i].connected = connected;
}

- spin_lock_irqsave(&wacom->remote_lock, flags);
+ spin_lock_irqsave(&remote->remote_lock, flags);

- ret = kfifo_in(&wacom->remote_fifo, &remote_data, sizeof(remote_data));
+ ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
if (ret != sizeof(remote_data)) {
- spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
dev_err(dev, "Can't queue Remote status event.\n");
return;
}

- spin_unlock_irqrestore(&wacom->remote_lock, flags);
+ spin_unlock_irqrestore(&remote->remote_lock, flags);

wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
}
diff --git a/3.7/wacom_wac.h b/3.7/wacom_wac.h
index 0ade39c..7e12b8b 100644
--- a/3.7/wacom_wac.h
+++ b/3.7/wacom_wac.h
@@ -178,7 +178,7 @@ struct wacom_wac {
unsigned char *data;
int tool[2];
int id[2];
- __u32 serial[5];
+ __u32 serial[2];
bool reporting_data;
struct wacom_features features;
struct wacom_shared *shared;
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:11 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

Thanks to devres, we can now afford to create more than one input node
without having to overload the remove/failure paths. Having one input
node per remote is something which should have been implemented from start
but the probability of having users with several remotes is quite low.
Anyway, still, better looking at the future and implement things properly.

Remote input nodes will be freed/unregistered magically as they are
created in the devres group &remote->remotes[index].

We need to open the hid node now that the remotes are dynamically
allocated.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (7c35dc3)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (9447bd6)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom.h | 2 +
2.6.38/wacom_sys.c | 155 ++++++++++++++++++++++++++++++++++++++--------------
2.6.38/wacom_wac.c | 35 ++++++++++--
3.17/wacom.h | 2 +
3.17/wacom_sys.c | 30 +++++++++++
3.17/wacom_wac.c | 35 ++++++++++--
3.7/wacom.h | 2 +
3.7/wacom_sys.c | 156 +++++++++++++++++++++++++++++++++++++++--------------
3.7/wacom_wac.c | 33 ++++++++++--
9 files changed, 358 insertions(+), 92 deletions(-)

diff --git a/2.6.38/wacom.h b/2.6.38/wacom.h
index 5ecd3b8..e501fae 100644
--- a/2.6.38/wacom.h
+++ b/2.6.38/wacom.h
@@ -126,6 +126,8 @@ struct wacom_remote {
struct {
struct attribute_group group;
u32 serial;
+ struct input_dev *input;
+ bool registered;
} remotes[WACOM_MAX_REMOTES];
};

diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 41f8b9a..b8dbcc4 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1328,11 +1328,19 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
struct wacom_remote *remote = wacom->remote;
u32 serial = remote->remotes[index].serial;
int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&remote->remote_lock, flags);
+ remote->remotes[index].registered = false;
+ spin_unlock_irqrestore(&remote->remote_lock, flags);

if (remote->remotes[index].group.name)
devres_release_group(&wacom->usbdev->dev,
&remote->remotes[index]);

+ if (remote->remotes[index].input)
+ input_unregister_device(remote->remotes[index].input);
+
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (remote->remotes[i].serial == serial) {
remote->remotes[i].serial = 0;
@@ -1343,50 +1351,12 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
kfree((char *)remote->remotes[i].group.name);
remote->remotes[i].group.name = NULL;

+ remote->remotes[i].registered = false;
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
}
}
}

-static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
- unsigned int index)
-{
- struct wacom_remote *remote = wacom->remote;
- struct device *dev = &wacom->usbdev->dev;
- int error, k;
-
- /* A remote can pair more than once with an EKR,
- * check to make sure this serial isn't already paired.
- */
- for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (remote->remotes[k].serial == serial)
- break;
- }
-
- if (k < WACOM_MAX_REMOTES) {
- remote->remotes[index].serial = serial;
- return 0;
- }
-
- if (!devres_open_group(dev, &remote->remotes[index], GFP_KERNEL))
- return -ENOMEM;
-
- error = wacom_remote_create_attr_group(wacom, serial, index);
- if (error)
- goto fail;
-
- remote->remotes[index].serial = serial;
-
- devres_close_group(dev, &remote->remotes[index]);
-
- return 0;
-
-fail:
- devres_release_group(dev, &remote->remotes[index]);
- remote->remotes[index].serial = 0;
- return error;
-}
-
static ssize_t wacom_store_unpair_remote(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
@@ -1502,14 +1472,50 @@ static void wacom_unregister_inputs(struct wacom *wacom)
wacom->wacom_wac.input = NULL;
}

+static int wacom_register_remote_input(struct wacom *wacom, int index)
+{
+ struct input_dev *input_dev;
+ struct wacom_remote *remote = wacom->remote;
+ struct usb_interface *intf = wacom->intf;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+ int error;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ error = -ENOMEM;
+ goto fail1;
+ }
+
+ input_dev->name = wacom_wac->name;
+ input_dev->dev.parent = &intf->dev;
+ usb_to_input_id(dev, &input_dev->id);
+ if (wacom_wac->pid != 0) {
+ /* copy PID of wireless device */
+ input_dev->id.product = wacom_wac->pid;
+ }
+ input_set_drvdata(input_dev, wacom);
+
+ remote->remotes[index].input = input_dev;
+
+ return 0;
+
+fail1:
+ return error;
+}
+
static int wacom_register_input(struct wacom *wacom)
{
struct input_dev *input_dev;
struct usb_interface *intf = wacom->intf;
struct usb_device *dev = interface_to_usbdev(intf);
struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+ struct wacom_features *features = &wacom_wac->features;
int error;

+ if (features->type == REMOTE)
+ return 0;
+
input_dev = input_allocate_device();
if (!input_dev) {
error = -ENOMEM;
@@ -1547,6 +1553,77 @@ fail1:
return error;
}

+static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
+ unsigned int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct device *dev = &wacom->usbdev->dev;
+ int error, k;
+
+ /* A remote can pair more than once with an EKR,
+ * check to make sure this serial isn't already paired.
+ */
+ for (k = 0; k < WACOM_MAX_REMOTES; k++) {
+ if (remote->remotes[k].serial == serial)
+ break;
+ }
+
+ if (k < WACOM_MAX_REMOTES) {
+ remote->remotes[index].serial = serial;
+ return 0;
+ }
+
+ if (!devres_open_group(dev, &remote->remotes[index], GFP_KERNEL))
+ return -ENOMEM;
+
+ error = wacom_remote_create_attr_group(wacom, serial, index);
+ if (error)
+ goto fail;
+
+ error = wacom_register_remote_input(wacom, index);
+ if (error)
+ goto fail;
+
+ if (!remote->remotes[index].input) {
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ remote->remotes[index].input->uniq = remote->remotes[index].group.name;
+ remote->remotes[index].input->name = wacom_wac->name;
+
+ if (!remote->remotes[index].input->name) {
+ error = -EINVAL;
+ goto fail;
+ }
+
+ error = wacom_setup_input_capabilities(remote->remotes[index].input,
+ wacom_wac);
+ if (error)
+ goto fail;
+
+ remote->remotes[index].serial = serial;
+
+ error = input_register_device(remote->remotes[index].input);
+ if (error)
+ goto fail2;
+
+ remote->remotes[index].registered = true;
+
+ devres_close_group(dev, &remote->remotes[index]);
+
+ return 0;
+fail2:
+ if (remote->remotes[index].input)
+ input_free_device(remote->remotes[index].input);
+ remote->remotes[index].input = NULL;
+fail:
+ devres_release_group(dev, &remote->remotes[index]);
+ remote->remotes[index].serial = 0;
+ return error;
+}
+
/*
* Not all devices report physical dimensions from HID.
* Compute the default from hardcoded logical dimension
diff --git a/2.6.38/wacom_wac.c b/2.6.38/wacom_wac.c
index 4f369e8..4e246d0 100644
--- a/2.6.38/wacom_wac.c
+++ b/2.6.38/wacom_wac.c
@@ -700,22 +700,38 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
{
unsigned char *data = wacom_wac->data;
- struct input_dev *input = wacom_wac->input;
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
struct wacom_features *features = &wacom_wac->features;
struct wacom_remote *remote = wacom->remote;
+ struct input_dev *input;
int bat_charging, bat_percent, touch_ring_mode;
__u32 serial;
- int i;
+ int i, index = -1;
+ unsigned long flags;

if (data[0] != WACOM_REPORT_REMOTE) {
- dev_dbg(input->dev.parent,
+ dev_dbg(&wacom->intf->dev,
"%s: received unknown report #%d", __func__, data[0]);
return 0;
}

serial = data[3] + (data[4] << 8) + (data[5] << 16);
wacom_wac->id[0] = PAD_DEVICE_ID;
+
+ spin_lock_irqsave(&remote->remote_lock, flags);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (remote->remotes[i].serial == serial) {
+ index = i;
+ break;
+ }
+ }
+
+ input = remote->remotes[index].input;
+
+ if (index < 0 || !remote->remotes[index].registered)
+ goto out;
+
input_report_key(input, BTN_0, (data[9] & 0x01));
input_report_key(input, BTN_1, (data[9] & 0x02));
input_report_key(input, BTN_2, (data[9] & 0x04));
@@ -752,6 +768,8 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)

input_event(input, EV_MSC, MSC_SERIAL, serial);

+ input_sync(input);
+
/*Which mode select (LED light) is currently on?*/
touch_ring_mode = (data[11] & 0xC0) >> 6;

@@ -768,7 +786,9 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)

wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1, bat_charging);

- return 1;
+out:
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+ return 0;
}

static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
@@ -1835,6 +1855,10 @@ void wacom_setup_device_quirks(struct wacom *wacom)
features->quirks |= WACOM_QUIRK_BATTERY;
}
}
+
+ if (features->type == REMOTE) {
+ features->quirks |= WACOM_QUIRK_MONITOR;
+ }
}

static void wacom_abs_set_axis(struct input_dev *input_dev,
@@ -1899,6 +1923,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_features *features = &wacom_wac->features;
int numbered_buttons = features->numbered_buttons;

+ if (features->type == REMOTE && input_dev == wacom_wac->input)
+ return -ENODEV;
+
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);

__set_bit(BTN_TOUCH, input_dev->keybit);
diff --git a/3.17/wacom.h b/3.17/wacom.h
index 1dd9cce..c299a83 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -137,6 +137,8 @@ struct wacom_remote {
struct {
struct attribute_group group;
u32 serial;
+ struct input_dev *input;
+ bool registered;
} remotes[WACOM_MAX_REMOTES];
};

diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 4c5b075..efa03fb 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1976,6 +1976,11 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
struct wacom_remote *remote = wacom->remote;
u32 serial = remote->remotes[index].serial;
int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&remote->remote_lock, flags);
+ remote->remotes[index].registered = false;
+ spin_unlock_irqrestore(&remote->remote_lock, flags);

if (remote->remotes[index].group.name)
devres_release_group(&wacom->hdev->dev,
@@ -1985,6 +1990,7 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
if (remote->remotes[i].serial == serial) {
remote->remotes[i].serial = 0;
remote->remotes[i].group.name = NULL;
+ remote->remotes[i].registered = false;
wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
}
}
@@ -2017,8 +2023,32 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
if (error)
goto fail;

+ remote->remotes[index].input = wacom_allocate_input(wacom);
+ if (!remote->remotes[index].input) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ remote->remotes[index].input->uniq = remote->remotes[index].group.name;
+ remote->remotes[index].input->name = wacom->wacom_wac.pad_name;
+
+ if (!remote->remotes[index].input->name) {
+ error = -EINVAL;
+ goto fail;
+ }
+
+ error = wacom_setup_pad_input_capabilities(remote->remotes[index].input,
+ &wacom->wacom_wac);
+ if (error)
+ goto fail;
+
remote->remotes[index].serial = serial;

+ error = input_register_device(remote->remotes[index].input);
+ if (error)
+ goto fail;
+
+ remote->remotes[index].registered = true;
+
devres_close_group(dev, &remote->remotes[index]);
return 0;

diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 96ced4e..4cfd4dd 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -757,23 +757,38 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
{
unsigned char *data = wacom_wac->data;
- struct input_dev *input = wacom_wac->pad_input;
+ struct input_dev *input;
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
struct wacom_remote *remote = wacom->remote;
struct wacom_features *features = &wacom_wac->features;
int bat_charging, bat_percent, touch_ring_mode;
__u32 serial;
- int i;
+ int i, index = -1;
+ unsigned long flags;

if (data[0] != WACOM_REPORT_REMOTE) {
- dev_dbg(input->dev.parent,
- "%s: received unknown report #%d", __func__, data[0]);
+ hid_dbg(wacom->hdev, "%s: received unknown report #%d",
+ __func__, data[0]);
return 0;
}

serial = data[3] + (data[4] << 8) + (data[5] << 16);
wacom_wac->id[0] = PAD_DEVICE_ID;

+ spin_lock_irqsave(&remote->remote_lock, flags);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (remote->remotes[i].serial == serial) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index < 0 || !remote->remotes[index].registered)
+ goto out;
+
+ input = remote->remotes[index].input;
+
input_report_key(input, BTN_0, (data[9] & 0x01));
input_report_key(input, BTN_1, (data[9] & 0x02));
input_report_key(input, BTN_2, (data[9] & 0x04));
@@ -810,6 +825,8 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)

input_event(input, EV_MSC, MSC_SERIAL, serial);

+ input_sync(input);
+
/*Which mode select (LED light) is currently on?*/
touch_ring_mode = (data[11] & 0xC0) >> 6;

@@ -827,7 +844,9 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1,
bat_charging);

- return 1;
+out:
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+ return 0;
}

static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
@@ -2467,6 +2486,9 @@ void wacom_setup_device_quirks(struct wacom *wacom)
features->quirks |= WACOM_QUIRK_BATTERY;
}
}
+
+ if (features->type == REMOTE)
+ features->device_type |= WACOM_DEVICETYPE_WL_MONITOR;
}

int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
@@ -2774,6 +2796,9 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
if (!(features->device_type & WACOM_DEVICETYPE_PAD))
return -ENODEV;

+ if (features->type == REMOTE && input_dev == wacom_wac->pad_input)
+ return -ENODEV;
+
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);

/* kept for making legacy xf86-input-wacom working with the wheels */
diff --git a/3.7/wacom.h b/3.7/wacom.h
index 492b09a..1183cbb 100644
--- a/3.7/wacom.h
+++ b/3.7/wacom.h
@@ -122,6 +122,8 @@ struct wacom_remote {
struct {
struct attribute_group group;
u32 serial;
+ struct input_dev *input;
+ bool registered;
} remotes[WACOM_MAX_REMOTES];
};

diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index e899cb2..3801468 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1320,11 +1320,19 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
struct wacom_remote *remote = wacom->remote;
u32 serial = remote->remotes[index].serial;
int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&remote->remote_lock, flags);
+ remote->remotes[index].registered = false;
+ spin_unlock_irqrestore(&remote->remote_lock, flags);

if (remote->remotes[index].group.name)
devres_release_group(&wacom->usbdev->dev,
&remote->remotes[index]);

+ if (remote->remotes[index].input)
+ input_unregister_device(remote->remotes[index].input);
+
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (remote->remotes[i].serial == serial) {
remote->remotes[i].serial = 0;
@@ -1334,51 +1342,12 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
*/
kfree((char *)remote->remotes[i].group.name);
remote->remotes[i].group.name = NULL;
-
+ remote->remotes[i].registered = false;
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
}
}
}

-static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
- unsigned int index)
-{
- struct wacom_remote *remote = wacom->remote;
- struct device *dev = &wacom->usbdev->dev;
- int error, k;
-
- /* A remote can pair more than once with an EKR,
- * check to make sure this serial isn't already paired.
- */
- for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (remote->remotes[k].serial == serial)
- break;
- }
-
- if (k < WACOM_MAX_REMOTES) {
- remote->remotes[index].serial = serial;
- return 0;
- }
-
- if (!devres_open_group(dev, &remote->remotes[index], GFP_KERNEL))
- return -ENOMEM;
-
- error = wacom_remote_create_attr_group(wacom, serial, index);
- if (error)
- goto fail;
-
- remote->remotes[index].serial = serial;
-
- devres_close_group(dev, &remote->remotes[index]);
-
- return 0;
-
-fail:
- devres_release_group(dev, &remote->remotes[index]);
- remote->remotes[index].serial = 0;
- return error;
-}
-
static ssize_t wacom_store_unpair_remote(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
@@ -1493,14 +1462,50 @@ static void wacom_unregister_inputs(struct wacom *wacom)
wacom->wacom_wac.input = NULL;
}

+static int wacom_register_remote_input(struct wacom *wacom, int index)
+{
+ struct input_dev *input_dev;
+ struct wacom_remote *remote = wacom->remote;
+ struct usb_interface *intf = wacom->intf;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+ int error;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ error = -ENOMEM;
+ goto fail1;
+ }
+
+ input_dev->name = wacom_wac->name;
+ input_dev->dev.parent = &intf->dev;
+ usb_to_input_id(dev, &input_dev->id);
+ if (wacom_wac->pid != 0) {
+ /* copy PID of wireless device */
+ input_dev->id.product = wacom_wac->pid;
+ }
+ input_set_drvdata(input_dev, wacom);
+
+ remote->remotes[index].input = input_dev;
+
+ return 0;
+
+fail1:
+ return error;
+}
+
static int wacom_register_input(struct wacom *wacom)
{
struct input_dev *input_dev;
struct usb_interface *intf = wacom->intf;
struct usb_device *dev = interface_to_usbdev(intf);
struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+ struct wacom_features *features = &wacom_wac->features;
int error;

+ if (features->type == REMOTE)
+ return 0;
+
input_dev = input_allocate_device();
if (!input_dev) {
error = -ENOMEM;
@@ -1537,6 +1542,77 @@ fail1:
return error;
}

+static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
+ unsigned int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct device *dev = &wacom->usbdev->dev;
+ int error, k;
+
+ /* A remote can pair more than once with an EKR,
+ * check to make sure this serial isn't already paired.
+ */
+ for (k = 0; k < WACOM_MAX_REMOTES; k++) {
+ if (remote->remotes[k].serial == serial)
+ break;
+ }
+
+ if (k < WACOM_MAX_REMOTES) {
+ remote->remotes[index].serial = serial;
+ return 0;
+ }
+
+ if (!devres_open_group(dev, &remote->remotes[index], GFP_KERNEL))
+ return -ENOMEM;
+
+ error = wacom_remote_create_attr_group(wacom, serial, index);
+ if (error)
+ goto fail;
+
+ error = wacom_register_remote_input(wacom, index);
+ if (error)
+ goto fail;
+
+ if (!remote->remotes[index].input) {
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ remote->remotes[index].input->uniq = remote->remotes[index].group.name;
+ remote->remotes[index].input->name = wacom_wac->name;
+
+ if (!remote->remotes[index].input->name) {
+ error = -EINVAL;
+ goto fail;
+ }
+
+ error = wacom_setup_input_capabilities(remote->remotes[index].input,
+ wacom_wac);
+ if (error)
+ goto fail;
+
+ remote->remotes[index].serial = serial;
+
+ error = input_register_device(remote->remotes[index].input);
+ if (error)
+ goto fail2;
+
+ remote->remotes[index].registered = true;
+
+ devres_close_group(dev, &remote->remotes[index]);
+
+ return 0;
+fail2:
+ if (remote->remotes[index].input)
+ input_free_device(remote->remotes[index].input);
+ remote->remotes[index].input = NULL;
+fail:
+ devres_release_group(dev, &remote->remotes[index]);
+ remote->remotes[index].serial = 0;
+ return error;
+}
+
/*
* Not all devices report physical dimensions from HID.
* Compute the default from hardcoded logical dimension
diff --git a/3.7/wacom_wac.c b/3.7/wacom_wac.c
index 8aa77c8..252e871 100644
--- a/3.7/wacom_wac.c
+++ b/3.7/wacom_wac.c
@@ -700,16 +700,17 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
{
unsigned char *data = wacom_wac->data;
- struct input_dev *input = wacom_wac->input;
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
struct wacom_features *features = &wacom_wac->features;
struct wacom_remote *remote = wacom->remote;
+ struct input_dev *input;
int bat_charging, bat_percent, touch_ring_mode;
__u32 serial;
- int i;
+ int i, index = -1;
+ unsigned long flags;

if (data[0] != WACOM_REPORT_REMOTE) {
- dev_dbg(input->dev.parent,
+ dev_dbg(&wacom->intf->dev,
"%s: received unknown report #%d", __func__, data[0]);
return 0;
}
@@ -717,6 +718,20 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
serial = data[3] + (data[4] << 8) + (data[5] << 16);
wacom_wac->id[0] = PAD_DEVICE_ID;

+ spin_lock_irqsave(&remote->remote_lock, flags);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (remote->remotes[i].serial == serial) {
+ index = i;
+ break;
+ }
+ }
+
+ input = remote->remotes[index].input;
+
+ if (index < 0 || !remote->remotes[index].registered)
+ goto out;
+
input_report_key(input, BTN_0, (data[9] & 0x01));
input_report_key(input, BTN_1, (data[9] & 0x02));
input_report_key(input, BTN_2, (data[9] & 0x04));
@@ -753,6 +768,8 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)

input_event(input, EV_MSC, MSC_SERIAL, serial);

+ input_sync(input);
+
/*Which mode select (LED light) is currently on?*/
touch_ring_mode = (data[11] & 0xC0) >> 6;

@@ -770,7 +787,9 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1,
bat_charging);

- return 1;
+out:
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+ return 0;
}

static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
@@ -1815,6 +1834,10 @@ void wacom_setup_device_quirks(struct wacom *wacom)
features->quirks |= WACOM_QUIRK_BATTERY;
}
}
+
+ if (features->type == REMOTE) {
+ features->quirks |= WACOM_QUIRK_MONITOR;
+ }
}

static void wacom_abs_set_axis(struct input_dev *input_dev,
@@ -1889,6 +1912,8 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
{
struct wacom_features *features = &wacom_wac->features;
int numbered_buttons = features->numbered_buttons;
+ if (features->type == REMOTE && input_dev == wacom_wac->input)
+ return -ENODEV;

input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:15 UTC
Permalink
Looks like upowerd is ignoring this since October 2013, so there is
no need to keep this around in the kernel.
And as mentioned in 8aaa592 (linux: Ignore ACs coming from devices) in
the upower tree, "We already have enough information on the device
battery".

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (136ae5e)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (d35475c)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom.h | 4 ----
3.17/wacom_sys.c | 72 +-------------------------------------------------------
2 files changed, 1 insertion(+), 75 deletions(-)

diff --git a/3.17/wacom.h b/3.17/wacom.h
index d3fb8b9..cb93199 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -133,15 +133,11 @@ struct wacom_group_leds {
struct wacom_battery {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
struct power_supply_desc bat_desc;
- struct power_supply_desc ac_desc;
struct power_supply *battery;
- struct power_supply *ac;
#else
struct power_supply battery;
- struct power_supply ac;
#endif
char bat_name[WACOM_NAME_MAX];
- char ac_name[WACOM_NAME_MAX];
int battery_capacity;
int bat_charging;
int bat_connected;
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 7357037..3330450 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1107,12 +1107,6 @@ static enum power_supply_property wacom_battery_props[] = {
POWER_SUPPLY_PROP_CAPACITY
};

-static enum power_supply_property wacom_ac_props[] = {
- POWER_SUPPLY_PROP_PRESENT,
- POWER_SUPPLY_PROP_ONLINE,
- POWER_SUPPLY_PROP_SCOPE,
-};
-
static int wacom_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -1153,33 +1147,6 @@ static int wacom_battery_get_property(struct power_supply *psy,
return ret;
}

-static int wacom_ac_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
- struct wacom_battery *battery = power_supply_get_drvdata(psy);
-#else
- struct wacom_battery *battery = container_of(psy, struct wacom_battery, battery);
-#endif
- int ret = 0;
-
- switch (psp) {
- case POWER_SUPPLY_PROP_PRESENT:
- /* fall through */
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = battery->ps_connected;
- break;
- case POWER_SUPPLY_PROP_SCOPE:
- val->intval = POWER_SUPPLY_SCOPE_DEVICE;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
static int __wacom_initialize_battery(struct wacom *wacom,
struct wacom_battery *battery)
@@ -1199,14 +1166,6 @@ static int __wacom_initialize_battery(struct wacom *wacom,
battery->battery.type = POWER_SUPPLY_TYPE_USB;
battery->battery.use_for_apm = 0;

- battery->ac.properties = wacom_ac_props;
- battery->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
- battery->ac.get_property = wacom_ac_get_property;
- sprintf(wacom->battery.ac_name, "wacom_ac_%ld", n);
- battery->ac.name = wacom->battery.ac_name;
- battery->ac.type = POWER_SUPPLY_TYPE_MAINS;
- battery->ac.use_for_apm = 0;
-
error = power_supply_register(dev, &battery->battery);

if (error)
@@ -1214,15 +1173,6 @@ static int __wacom_initialize_battery(struct wacom *wacom,

power_supply_powers(WACOM_POWERSUPPLY_REF(battery->battery), dev);

- error = power_supply_register(dev, &battery->ac);
-
- if (error) {
- power_supply_unregister(&battery->battery);
- return error;
- }
-
- power_supply_powers(WACOM_POWERSUPPLY_REF(battery->ac), dev);
-
return 0;
}

@@ -1233,9 +1183,8 @@ static int __wacom_initialize_battery(struct wacom *wacom,
static atomic_t battery_no = ATOMIC_INIT(0);
struct device *dev = &wacom->hdev->dev;
struct power_supply_config psy_cfg = { .drv_data = battery, };
- struct power_supply *ps_bat, *ps_ac;
+ struct power_supply *ps_bat;
struct power_supply_desc *bat_desc = &battery->bat_desc;
- struct power_supply_desc *ac_desc = &battery->ac_desc;
unsigned long n;
int error;

@@ -1252,31 +1201,15 @@ static int __wacom_initialize_battery(struct wacom *wacom,
bat_desc->type = POWER_SUPPLY_TYPE_USB;
bat_desc->use_for_apm = 0;

- ac_desc->properties = wacom_ac_props;
- ac_desc->num_properties = ARRAY_SIZE(wacom_ac_props);
- ac_desc->get_property = wacom_ac_get_property;
- sprintf(battery->ac_name, "wacom_ac_%ld", n);
- ac_desc->name = battery->ac_name;
- ac_desc->type = POWER_SUPPLY_TYPE_MAINS;
- ac_desc->use_for_apm = 0;
-
ps_bat = devm_power_supply_register(dev, bat_desc, &psy_cfg);
if (IS_ERR(ps_bat)) {
error = PTR_ERR(ps_bat);
goto err;
}

- ps_ac = devm_power_supply_register(dev, ac_desc, &psy_cfg);
- if (IS_ERR(ps_ac)) {
- error = PTR_ERR(ps_ac);
- goto err;
- }
-
power_supply_powers(ps_bat, &wacom->hdev->dev);
- power_supply_powers(ps_ac, &wacom->hdev->dev);

battery->battery = ps_bat;
- battery->ac = ps_ac;

devres_close_group(dev, bat_desc);
return 0;
@@ -1302,10 +1235,8 @@ static void wacom_destroy_battery(struct wacom *wacom)
devres_release_group(&wacom->hdev->dev, wacom->battery.battery);
#else
power_supply_unregister(&wacom->battery.battery);
- power_supply_unregister(&wacom->battery.ac);
#endif
WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery) = NULL;
- WACOM_POWERSUPPLY_DEVICE(wacom->battery.ac) = NULL;
}
}

@@ -1486,7 +1417,6 @@ static void wacom_remotes_destroy(void *data)

if (WACOM_POWERSUPPLY_DEVICE(remote->remotes[i].battery.battery)) {
power_supply_unregister(&remote->remotes[i].battery.battery);
- power_supply_unregister(&remote->remotes[i].battery.ac);
}
}
}
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:13 UTC
Permalink
Or Gnome complains about an empty battery.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (9f1015d)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (4cbb4d9)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom_sys.c | 28 ++++++++++++++++++++++------
3.17/wacom_sys.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------
3.7/wacom_sys.c | 28 ++++++++++++++++++++++------
3 files changed, 88 insertions(+), 18 deletions(-)

diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 5683cd8..481942a 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1372,6 +1372,7 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
remote->remotes[i].group.name = NULL;

remote->remotes[i].registered = false;
+ remote->remotes[i].battery.battery.dev = NULL;
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
}
}
@@ -1631,11 +1632,6 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,

remote->remotes[index].registered = true;

- error = __wacom_initialize_battery(wacom,
- &remote->remotes[index].battery);
- if (error)
- goto fail;
-
devres_close_group(dev, &remote->remotes[index]);

return 0;
@@ -1649,6 +1645,24 @@ fail:
return error;
}

+static int wacom_remote_attach_battery(struct wacom *wacom, int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ int error;
+ if (!remote->remotes[index].registered)
+ return 0;
+
+ if (remote->remotes[index].battery.battery.dev)
+ return 0;
+
+ error = __wacom_initialize_battery(wacom,
+ &wacom->remote->remotes[index].battery);
+ if (error)
+ return error;
+
+ return 0;
+}
+
/*
* Not all devices report physical dimensions from HID.
* Compute the default from hardcoded logical dimension
@@ -1830,8 +1844,10 @@ static void wacom_remote_work(struct work_struct *work)
serial = data.remote[i].serial;
if (data.remote[i].connected) {

- if (remote->remotes[i].serial == serial)
+ if (remote->remotes[i].serial == serial) {
+ wacom_remote_attach_battery(wacom, i);
continue;
+ }

if (remote->remotes[i].serial)
wacom_remote_destroy_one(wacom, i);
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 793cb72..29a5396 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -2020,6 +2020,16 @@ fail:
return;
}

+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
+static void wacom_destroy_remote_battery(struct wacom_battery *battery)
+{
+ if (battery->battery.dev) {
+ power_supply_unregister(&battery->battery);
+ battery->battery.dev = NULL;
+ }
+}
+#endif
+
static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
{
struct wacom_remote *remote = wacom->remote;
@@ -2031,6 +2041,15 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
remote->remotes[index].registered = false;
spin_unlock_irqrestore(&remote->remote_lock, flags);

+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
+ if (WACOM_POWERSUPPLY_DEVICE(remote->remotes[index].battery.battery))
+ devres_release_group(&wacom->hdev->dev,
+ &remote->remotes[index].battery.bat_desc);
+#else
+ if (remote->remotes[index].battery.battery.dev)
+ wacom_destroy_remote_battery(&remote->remotes[index].battery);
+#endif
+
if (remote->remotes[index].group.name)
devres_release_group(&wacom->hdev->dev,
&remote->remotes[index]);
@@ -2040,6 +2059,7 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
remote->remotes[i].serial = 0;
remote->remotes[i].group.name = NULL;
remote->remotes[i].registered = false;
+ WACOM_POWERSUPPLY_DEVICE(remote->remotes[i].battery.battery) = NULL;
wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
}
}
@@ -2096,11 +2116,6 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
if (error)
goto fail;

- error = __wacom_initialize_battery(wacom,
- &remote->remotes[index].battery);
- if (error)
- goto fail;
-
remote->remotes[index].registered = true;

devres_close_group(dev, &remote->remotes[index]);
@@ -2112,6 +2127,27 @@ fail:
return error;
}

+static int wacom_remote_attach_battery(struct wacom *wacom, int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ int error;
+ if (!remote->remotes[index].registered)
+ return 0;
+
+ if (WACOM_POWERSUPPLY_DEVICE(remote->remotes[index].battery.battery))
+ return 0;
+
+ if (wacom->led.groups[index].select == WACOM_STATUS_UNKNOWN)
+ return 0;
+
+ error = __wacom_initialize_battery(wacom,
+ &wacom->remote->remotes[index].battery);
+ if (error)
+ return error;
+
+ return 0;
+}
+
static void wacom_remote_work(struct work_struct *work)
{
struct wacom *wacom = container_of(work, struct wacom, remote_work);
@@ -2142,8 +2178,10 @@ static void wacom_remote_work(struct work_struct *work)
serial = data.remote[i].serial;
if (data.remote[i].connected) {

- if (remote->remotes[i].serial == serial)
+ if (remote->remotes[i].serial == serial) {
+ wacom_remote_attach_battery(wacom, i);
continue;
+ }

if (remote->remotes[i].serial)
wacom_remote_destroy_one(wacom, i);
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index 0094ff5..37e1700 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1365,6 +1365,7 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
kfree((char *)remote->remotes[i].group.name);
remote->remotes[i].group.name = NULL;
remote->remotes[i].registered = false;
+ remote->remotes[i].battery.battery.dev = NULL;
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
}
}
@@ -1622,11 +1623,6 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,

remote->remotes[index].registered = true;

- error = __wacom_initialize_battery(wacom,
- &remote->remotes[index].battery);
- if (error)
- goto fail;
-
devres_close_group(dev, &remote->remotes[index]);

return 0;
@@ -1640,6 +1636,24 @@ fail:
return error;
}

+static int wacom_remote_attach_battery(struct wacom *wacom, int index)
+{
+ struct wacom_remote *remote = wacom->remote;
+ int error;
+ if (!remote->remotes[index].registered)
+ return 0;
+
+ if (remote->remotes[index].battery.battery.dev)
+ return 0;
+
+ error = __wacom_initialize_battery(wacom,
+ &wacom->remote->remotes[index].battery);
+ if (error)
+ return error;
+
+ return 0;
+}
+
/*
* Not all devices report physical dimensions from HID.
* Compute the default from hardcoded logical dimension
@@ -1825,8 +1839,10 @@ static void wacom_remote_work(struct work_struct *work)
serial = data.remote[i].serial;
if (data.remote[i].connected) {

- if (remote->remotes[i].serial == serial)
+ if (remote->remotes[i].serial == serial) {
+ wacom_remote_attach_battery(wacom, i);
continue;
+ }

if (remote->remotes[i].serial)
wacom_remote_destroy_one(wacom, i);
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:10 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

No functional changes, just a prep patch for the one after.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (e7749f6)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (6f2fab8)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom.h | 6 ++++--
2.6.38/wacom_sys.c | 57 +++++++++++++++++++++++++++---------------------------
2.6.38/wacom_wac.c | 2 +-
3.17/wacom.h | 6 ++++--
3.17/wacom_sys.c | 53 +++++++++++++++++++++++++-------------------------
3.17/wacom_wac.c | 2 +-
3.7/wacom.h | 6 ++++--
3.7/wacom_sys.c | 57 +++++++++++++++++++++++++++---------------------------
3.7/wacom_wac.c | 2 +-
9 files changed, 100 insertions(+), 91 deletions(-)

diff --git a/2.6.38/wacom.h b/2.6.38/wacom.h
index e0c7be1..5ecd3b8 100644
--- a/2.6.38/wacom.h
+++ b/2.6.38/wacom.h
@@ -123,8 +123,10 @@ struct wacom_remote {
spinlock_t remote_lock;
struct kfifo remote_fifo;
struct kobject *remote_dir;
- struct attribute_group remote_group[WACOM_MAX_REMOTES];
- __u32 serial[WACOM_MAX_REMOTES];
+ struct {
+ struct attribute_group group;
+ u32 serial;
+ } remotes[WACOM_MAX_REMOTES];
};

struct wacom {
diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 5ce0210..41f8b9a 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1285,15 +1285,15 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int
int error = 0;
struct wacom_remote *remote = wacom->remote;

- remote->remote_group[index].name = kasprintf(GFP_KERNEL, "%d", serial);
- if (!remote->remote_group[index].name)
+ remote->remotes[index].group.name = kasprintf(GFP_KERNEL, "%d", serial);
+ if (!remote->remotes[index].group.name)
return -ENOMEM;

error = __wacom_devm_sysfs_create_group(wacom, remote->remote_dir,
- &remote->remote_group[index]);
+ &remote->remotes[index].group);

if (error) {
- remote->remote_group[index].name = NULL;
+ remote->remotes[index].group.name = NULL;
dev_err(&wacom->intf->dev,
"cannot create sysfs group err: %d\n", error);
return error;
@@ -1326,21 +1326,22 @@ static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
{
struct wacom_remote *remote = wacom->remote;
- u32 serial = remote->serial[index];
+ u32 serial = remote->remotes[index].serial;
int i;

- if (remote->remote_group[index].name)
- devres_release_group(&wacom->usbdev->dev, &remote->serial[index]);
+ if (remote->remotes[index].group.name)
+ devres_release_group(&wacom->usbdev->dev,
+ &remote->remotes[index]);

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (remote->serial[i] == serial) {
- remote->serial[i] = 0;
+ if (remote->remotes[i].serial == serial) {
+ remote->remotes[i].serial = 0;

/* Destroy the attribute group parts not
* covered by devres for this kernel.
*/
- kfree((char *)remote->remote_group[i].name);
- remote->remote_group[i].name = NULL;
+ kfree((char *)remote->remotes[i].group.name);
+ remote->remotes[i].group.name = NULL;

wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
}
@@ -1358,31 +1359,31 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
* check to make sure this serial isn't already paired.
*/
for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (remote->serial[k] == serial)
+ if (remote->remotes[k].serial == serial)
break;
}

if (k < WACOM_MAX_REMOTES) {
- remote->serial[index] = serial;
+ remote->remotes[index].serial = serial;
return 0;
}

- if (!devres_open_group(dev, &remote->serial[index], GFP_KERNEL))
+ if (!devres_open_group(dev, &remote->remotes[index], GFP_KERNEL))
return -ENOMEM;

error = wacom_remote_create_attr_group(wacom, serial, index);
if (error)
goto fail;

- remote->serial[index] = serial;
+ remote->remotes[index].serial = serial;

- devres_close_group(dev, &remote->serial[index]);
+ devres_close_group(dev, &remote->remotes[index]);

return 0;

fail:
- devres_release_group(dev, &remote->serial[index]);
- remote->serial[index] = 0;
+ devres_release_group(dev, &remote->remotes[index]);
+ remote->remotes[index].serial = 0;
return error;
}

@@ -1431,7 +1432,7 @@ static void wacom_remotes_destroy(void *data)
return;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom->remote->remote_group[i].name) {
+ if (wacom->remote->remotes[i].group.name) {
wacom_remote_destroy_one(wacom, i);
}
}
@@ -1466,11 +1467,11 @@ static int wacom_initialize_remotes(struct wacom *wacom)
return -ENOMEM;
}

- remote->remote_group[0] = remote0_serial_group;
- remote->remote_group[1] = remote1_serial_group;
- remote->remote_group[2] = remote2_serial_group;
- remote->remote_group[3] = remote3_serial_group;
- remote->remote_group[4] = remote4_serial_group;
+ remote->remotes[0].group = remote0_serial_group;
+ remote->remotes[1].group = remote1_serial_group;
+ remote->remotes[2].group = remote2_serial_group;
+ remote->remotes[3].group = remote3_serial_group;
+ remote->remotes[4].group = remote4_serial_group;

remote->remote_dir = kobject_create_and_add("wacom_remote",
&wacom->intf->dev.kobj);
@@ -1488,7 +1489,7 @@ static int wacom_initialize_remotes(struct wacom *wacom)

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
- remote->serial[i] = 0;
+ remote->remotes[i].serial = 0;
}

return 0;
@@ -1727,15 +1728,15 @@ static void wacom_remote_work(struct work_struct *work)
serial = data.remote[i].serial;
if (data.remote[i].connected) {

- if (remote->serial[i] == serial)
+ if (remote->remotes[i].serial == serial)
continue;

- if (remote->serial[i])
+ if (remote->remotes[i].serial)
wacom_remote_destroy_one(wacom, i);

wacom_remote_create_one(wacom, serial, i);

- } else if (remote->serial[i]) {
+ } else if (remote->remotes[i].serial) {
wacom_remote_destroy_one(wacom, i);
}
}
diff --git a/2.6.38/wacom_wac.c b/2.6.38/wacom_wac.c
index 7ccd5bc..4f369e8 100644
--- a/2.6.38/wacom_wac.c
+++ b/2.6.38/wacom_wac.c
@@ -756,7 +756,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
touch_ring_mode = (data[11] & 0xC0) >> 6;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (remote->serial[i] == serial)
+ if (remote->remotes[i].serial == serial)
wacom->led.select[i] = touch_ring_mode;
}

diff --git a/3.17/wacom.h b/3.17/wacom.h
index d2c9548..1dd9cce 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -134,8 +134,10 @@ struct wacom_remote {
spinlock_t remote_lock;
struct kfifo remote_fifo;
struct kobject *remote_dir;
- struct attribute_group remote_group[WACOM_MAX_REMOTES];
- __u32 serial[WACOM_MAX_REMOTES];
+ struct {
+ struct attribute_group group;
+ u32 serial;
+ } remotes[WACOM_MAX_REMOTES];
};

struct wacom {
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 3b2c71c..4c5b075 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1360,16 +1360,16 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
int error = 0;
struct wacom_remote *remote = wacom->remote;

- remote->remote_group[index].name = devm_kasprintf(&wacom->hdev->dev,
+ remote->remotes[index].group.name = devm_kasprintf(&wacom->hdev->dev,
GFP_KERNEL,
"%d", serial);
- if (!remote->remote_group[index].name)
+ if (!remote->remotes[index].group.name)
return -ENOMEM;

error = __wacom_devm_sysfs_create_group(wacom, remote->remote_dir,
- &remote->remote_group[index]);
+ &remote->remotes[index].group);
if (error) {
- remote->remote_group[index].name = NULL;
+ remote->remotes[index].group.name = NULL;
hid_err(wacom->hdev,
"cannot create sysfs group err: %d\n", error);
return error;
@@ -1473,11 +1473,11 @@ static int wacom_initialize_remotes(struct wacom *wacom)
return -ENOMEM;
}

- remote->remote_group[0] = remote0_serial_group;
- remote->remote_group[1] = remote1_serial_group;
- remote->remote_group[2] = remote2_serial_group;
- remote->remote_group[3] = remote3_serial_group;
- remote->remote_group[4] = remote4_serial_group;
+ remote->remotes[0].group = remote0_serial_group;
+ remote->remotes[1].group = remote1_serial_group;
+ remote->remotes[2].group = remote2_serial_group;
+ remote->remotes[3].group = remote3_serial_group;
+ remote->remotes[4].group = remote4_serial_group;

remote->remote_dir = kobject_create_and_add("wacom_remote",
&wacom->hdev->dev.kobj);
@@ -1494,7 +1494,7 @@ static int wacom_initialize_remotes(struct wacom *wacom)

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
- remote->serial[i] = 0;
+ remote->remotes[i].serial = 0;
}

error = devm_add_action_or_reset(&wacom->hdev->dev,
@@ -1974,16 +1974,17 @@ fail:
static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
{
struct wacom_remote *remote = wacom->remote;
- u32 serial = remote->serial[index];
+ u32 serial = remote->remotes[index].serial;
int i;

- if (remote->remote_group[index].name)
- devres_release_group(&wacom->hdev->dev, &remote->serial[index]);
+ if (remote->remotes[index].group.name)
+ devres_release_group(&wacom->hdev->dev,
+ &remote->remotes[index]);

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (remote->serial[i] == serial) {
- remote->serial[i] = 0;
- remote->remote_group[i].name = NULL;
+ if (remote->remotes[i].serial == serial) {
+ remote->remotes[i].serial = 0;
+ remote->remotes[i].group.name = NULL;
wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
}
}
@@ -2000,30 +2001,30 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
* check to make sure this serial isn't already paired.
*/
for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (remote->serial[k] == serial)
+ if (remote->remotes[k].serial == serial)
break;
}

if (k < WACOM_MAX_REMOTES) {
- remote->serial[index] = serial;
+ remote->remotes[index].serial = serial;
return 0;
}

- if (!devres_open_group(dev, &remote->serial[index], GFP_KERNEL))
+ if (!devres_open_group(dev, &remote->remotes[index], GFP_KERNEL))
return -ENOMEM;

error = wacom_remote_create_attr_group(wacom, serial, index);
if (error)
goto fail;

- remote->serial[index] = serial;
+ remote->remotes[index].serial = serial;

- devres_close_group(dev, &remote->serial[index]);
+ devres_close_group(dev, &remote->remotes[index]);
return 0;

fail:
- devres_release_group(dev, &remote->serial[index]);
- remote->serial[index] = 0;
+ devres_release_group(dev, &remote->remotes[index]);
+ remote->remotes[index].serial = 0;
return error;
}

@@ -2057,15 +2058,15 @@ static void wacom_remote_work(struct work_struct *work)
serial = data.remote[i].serial;
if (data.remote[i].connected) {

- if (remote->serial[i] == serial)
+ if (remote->remotes[i].serial == serial)
continue;

- if (remote->serial[i])
+ if (remote->remotes[i].serial)
wacom_remote_destroy_one(wacom, i);

wacom_remote_create_one(wacom, serial, i);

- } else if (remote->serial[i]) {
+ } else if (remote->remotes[i].serial) {
wacom_remote_destroy_one(wacom, i);
}
}
diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 7ab1553..96ced4e 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -814,7 +814,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
touch_ring_mode = (data[11] & 0xC0) >> 6;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (remote->serial[i] == serial)
+ if (remote->remotes[i].serial == serial)
wacom->led.groups[i].select = touch_ring_mode;
}

diff --git a/3.7/wacom.h b/3.7/wacom.h
index 2067a5c..492b09a 100644
--- a/3.7/wacom.h
+++ b/3.7/wacom.h
@@ -119,8 +119,10 @@ struct wacom_remote {
spinlock_t remote_lock;
struct kfifo remote_fifo;
struct kobject *remote_dir;
- struct attribute_group remote_group[WACOM_MAX_REMOTES];
- __u32 serial[WACOM_MAX_REMOTES];
+ struct {
+ struct attribute_group group;
+ u32 serial;
+ } remotes[WACOM_MAX_REMOTES];
};

struct wacom {
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index ef241c9..e899cb2 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1278,14 +1278,14 @@ static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int
int error = 0;
struct wacom_remote *remote = wacom->remote;

- remote->remote_group[index].name = kasprintf(GFP_KERNEL, "%d", serial);
- if (!remote->remote_group[index].name)
+ remote->remotes[index].group.name = kasprintf(GFP_KERNEL, "%d", serial);
+ if (!remote->remotes[index].group.name)
return -ENOMEM;

error = __wacom_devm_sysfs_create_group(wacom, remote->remote_dir,
- &remote->remote_group[index]);
+ &remote->remotes[index].group);
if (error) {
- remote->remote_group[index].name = NULL;
+ remote->remotes[index].group.name = NULL;
dev_err(&wacom->intf->dev,
"cannot create sysfs group err: %d\n", error);
return error;
@@ -1318,21 +1318,22 @@ static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
{
struct wacom_remote *remote = wacom->remote;
- u32 serial = remote->serial[index];
+ u32 serial = remote->remotes[index].serial;
int i;

- if (remote->remote_group[index].name)
- devres_release_group(&wacom->usbdev->dev, &remote->serial[index]);
+ if (remote->remotes[index].group.name)
+ devres_release_group(&wacom->usbdev->dev,
+ &remote->remotes[index]);

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (remote->serial[i] == serial) {
- remote->serial[i] = 0;
+ if (remote->remotes[i].serial == serial) {
+ remote->remotes[i].serial = 0;

/* Destroy the attribute group parts not
* covered by devres for this kernel.
*/
- kfree((char *)remote->remote_group[i].name);
- remote->remote_group[i].name = NULL;
+ kfree((char *)remote->remotes[i].group.name);
+ remote->remotes[i].group.name = NULL;

wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
}
@@ -1350,31 +1351,31 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
* check to make sure this serial isn't already paired.
*/
for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (remote->serial[k] == serial)
+ if (remote->remotes[k].serial == serial)
break;
}

if (k < WACOM_MAX_REMOTES) {
- remote->serial[index] = serial;
+ remote->remotes[index].serial = serial;
return 0;
}

- if (!devres_open_group(dev, &remote->serial[index], GFP_KERNEL))
+ if (!devres_open_group(dev, &remote->remotes[index], GFP_KERNEL))
return -ENOMEM;

error = wacom_remote_create_attr_group(wacom, serial, index);
if (error)
goto fail;

- remote->serial[index] = serial;
+ remote->remotes[index].serial = serial;

- devres_close_group(dev, &remote->serial[index]);
+ devres_close_group(dev, &remote->remotes[index]);

return 0;

fail:
- devres_release_group(dev, &remote->serial[index]);
- remote->serial[index] = 0;
+ devres_release_group(dev, &remote->remotes[index]);
+ remote->remotes[index].serial = 0;
return error;
}

@@ -1422,7 +1423,7 @@ static void wacom_remotes_destroy(struct wacom *wacom)
return;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom->remote->remote_group[i].name) {
+ if (wacom->remote->remotes[i].group.name) {
wacom_remote_destroy_one(wacom, i);
}
}
@@ -1457,11 +1458,11 @@ static int wacom_initialize_remotes(struct wacom *wacom)
return -ENOMEM;
}

- remote->remote_group[0] = remote0_serial_group;
- remote->remote_group[1] = remote1_serial_group;
- remote->remote_group[2] = remote2_serial_group;
- remote->remote_group[3] = remote3_serial_group;
- remote->remote_group[4] = remote4_serial_group;
+ remote->remotes[0].group = remote0_serial_group;
+ remote->remotes[1].group = remote1_serial_group;
+ remote->remotes[2].group = remote2_serial_group;
+ remote->remotes[3].group = remote3_serial_group;
+ remote->remotes[4].group = remote4_serial_group;

remote->remote_dir = kobject_create_and_add("wacom_remote",
&wacom->intf->dev.kobj);
@@ -1479,7 +1480,7 @@ static int wacom_initialize_remotes(struct wacom *wacom)

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
- remote->serial[i] = 0;
+ remote->remotes[i].serial = 0;
}

return 0;
@@ -1721,15 +1722,15 @@ static void wacom_remote_work(struct work_struct *work)
serial = data.remote[i].serial;
if (data.remote[i].connected) {

- if (remote->serial[i] == serial)
+ if (remote->remotes[i].serial == serial)
continue;

- if (remote->serial[i])
+ if (remote->remotes[i].serial)
wacom_remote_destroy_one(wacom, i);

wacom_remote_create_one(wacom, serial, i);

- } else if (remote->serial[i]) {
+ } else if (remote->remotes[i].serial) {
wacom_remote_destroy_one(wacom, i);
}
}
diff --git a/3.7/wacom_wac.c b/3.7/wacom_wac.c
index bd6c32a..8aa77c8 100644
--- a/3.7/wacom_wac.c
+++ b/3.7/wacom_wac.c
@@ -757,7 +757,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
touch_ring_mode = (data[11] & 0xC0) >> 6;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (remote->serial[i] == serial)
+ if (remote->remotes[i].serial == serial)
wacom->led.select[i] = touch_ring_mode;
}
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:14 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

When upowerd detects a new device, it tries to map this new device to
an input to guess its kind. It works OK for wired tablets when the
wireless module and its battery are attached, but not so well when
connected over wireless.
In that case, the battery is attached to the wireless HID node, not
the Pen or Pad HID node. So there is no input node as a parent of the
reported battery, which means it will be showed as a computer battery
in gnome-control-center.

If we set the power supply type to USB, upowerd has a heuristic that
detects "wacom_" in the name of the power_supply, and set the type to
tablet. So it's now clear that the reported battery of from a tablet.
(see https://cgit.freedesktop.org/upower/tree/src/linux/up-device-supply.c)

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (9698329)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (06ab7bd)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom_sys.c | 2 +-
3.17/wacom_sys.c | 4 ++--
3.7/wacom_sys.c | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index 481942a..97faf87 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1215,7 +1215,7 @@ static int __wacom_initialize_battery(struct wacom *wacom,
battery->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
battery->battery.get_property = wacom_battery_get_property;
battery->battery.name = battery->bat_name;
- battery->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ battery->battery.type = POWER_SUPPLY_TYPE_USB;
battery->battery.use_for_apm = 0;

error = power_supply_register(&wacom->usbdev->dev,
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 29a5396..7357037 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1196,7 +1196,7 @@ static int __wacom_initialize_battery(struct wacom *wacom,
battery->battery.get_property = wacom_battery_get_property;
sprintf(wacom->battery.bat_name, "wacom_battery_%ld", n);
battery->battery.name = wacom->battery.bat_name;
- battery->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ battery->battery.type = POWER_SUPPLY_TYPE_USB;
battery->battery.use_for_apm = 0;

battery->ac.properties = wacom_ac_props;
@@ -1249,7 +1249,7 @@ static int __wacom_initialize_battery(struct wacom *wacom,
bat_desc->get_property = wacom_battery_get_property;
sprintf(battery->bat_name, "wacom_battery_%ld", n);
bat_desc->name = battery->bat_name;
- bat_desc->type = POWER_SUPPLY_TYPE_BATTERY;
+ bat_desc->type = POWER_SUPPLY_TYPE_USB;
bat_desc->use_for_apm = 0;

ac_desc->properties = wacom_ac_props;
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index 37e1700..75d363e 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1212,7 +1212,7 @@ static int __wacom_initialize_battery(struct wacom *wacom,
battery->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
battery->battery.get_property = wacom_battery_get_property;
battery->battery.name = battery->bat_name;
- battery->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ battery->battery.type = POWER_SUPPLY_TYPE_USB;
battery->battery.use_for_apm = 0;

error = power_supply_register(&wacom->usbdev->dev,
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:12 UTC
Permalink
Previously, all the remotes attached to the same receiver would share the
same power_supply. That's not good as the remotes will constantly change
the battery information according to their own state.

To have something generic enough, we introduce struct wacom_battery
which regroups all the information we need for a battery.

This backport works around the split in the battery path at kernel 4.1.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (59d69bc)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (89f769c)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
2.6.38/wacom.h | 14 +++-
2.6.38/wacom_sys.c | 91 ++++++++++++++---------
2.6.38/wacom_wac.c | 55 +++++++-------
2.6.38/wacom_wac.h | 5 --
3.17/wacom.h | 27 +++++--
3.17/wacom_sys.c | 214 +++++++++++++++++++++++++++++++++--------------------
3.17/wacom_wac.c | 53 ++++++-------
3.17/wacom_wac.h | 6 --
3.7/wacom.h | 14 +++-
3.7/wacom_sys.c | 101 ++++++++++++++++---------
3.7/wacom_wac.c | 55 +++++++-------
3.7/wacom_wac.h | 5 --
12 files changed, 385 insertions(+), 255 deletions(-)

diff --git a/2.6.38/wacom.h b/2.6.38/wacom.h
index e501fae..0ccfcc1 100644
--- a/2.6.38/wacom.h
+++ b/2.6.38/wacom.h
@@ -119,6 +119,17 @@ enum wacom_worker {
WACOM_WORKER_REMOTE,
};

+struct wacom_battery {
+ struct power_supply battery;
+ struct power_supply ac;
+ char bat_name[WACOM_NAME_MAX];
+ char ac_name[WACOM_NAME_MAX];
+ int battery_capacity;
+ int bat_charging;
+ int bat_connected;
+ int ps_connected;
+};
+
struct wacom_remote {
spinlock_t remote_lock;
struct kfifo remote_fifo;
@@ -128,6 +139,7 @@ struct wacom_remote {
u32 serial;
struct input_dev *input;
bool registered;
+ struct wacom_battery battery;
} remotes[WACOM_MAX_REMOTES];
};

@@ -150,7 +162,7 @@ struct wacom {
u8 hlv; /* status led brightness button pressed (1..127) */
u8 img_lum; /* OLED matrix display brightness */
} led;
- struct power_supply battery;
+ struct wacom_battery battery;
};

static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
diff --git a/2.6.38/wacom_sys.c b/2.6.38/wacom_sys.c
index b8dbcc4..5683cd8 100644
--- a/2.6.38/wacom_sys.c
+++ b/2.6.38/wacom_sys.c
@@ -1159,12 +1159,13 @@ static int wacom_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
- struct wacom *wacom = container_of(psy, struct wacom, battery);
+ struct wacom_battery *battery = container_of(psy, struct wacom_battery,
+ battery);
int ret = 0;

switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
- val->intval = wacom->wacom_wac.bat_connected;
+ val->intval = battery->bat_connected;
break;
#ifdef POWER_SUPPLY_PROP_SCOPE
case POWER_SUPPLY_PROP_SCOPE:
@@ -1172,16 +1173,15 @@ static int wacom_battery_get_property(struct power_supply *psy,
break;
#endif
case POWER_SUPPLY_PROP_CAPACITY:
- val->intval =
- wacom->wacom_wac.battery_capacity;
+ val->intval = battery->battery_capacity;
break;
case POWER_SUPPLY_PROP_STATUS:
- if (wacom->wacom_wac.bat_charging)
+ if (battery->bat_charging)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
- else if (wacom->wacom_wac.battery_capacity == 100 &&
- wacom->wacom_wac.ps_connected)
+ else if (battery->battery_capacity == 100 &&
+ battery->ps_connected)
val->intval = POWER_SUPPLY_STATUS_FULL;
- else if (wacom->wacom_wac.ps_connected)
+ else if (battery->ps_connected)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
@@ -1194,48 +1194,65 @@ static int wacom_battery_get_property(struct power_supply *psy,
return ret;
}

-static int wacom_initialize_battery(struct wacom *wacom)
+static int __wacom_initialize_battery(struct wacom *wacom,
+ struct wacom_battery *battery)
{
static atomic_t battery_no = ATOMIC_INIT(0);
static DEFINE_SPINLOCK(ps_lock);
unsigned long flags;
int error = 0;
+ unsigned long n;

spin_lock_irqsave(&ps_lock, flags); /* Prevent potential race for the "wacom_battery" name */
- if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) {
- unsigned long n = atomic_inc_return(&battery_no) - 1;
+ n = atomic_inc_return(&battery_no) - 1;

- if (power_supply_get_by_name("wacom_battery"))
- sprintf(wacom->wacom_wac.bat_name, "wacom_battery_%ld", n);
- else
- sprintf(wacom->wacom_wac.bat_name, "wacom_battery");
+ if (power_supply_get_by_name("wacom_battery"))
+ sprintf(battery->bat_name, "wacom_battery_%ld", n);
+ else
+ sprintf(battery->bat_name, "wacom_battery");

- wacom->battery.properties = wacom_battery_props;
- wacom->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
- wacom->battery.get_property = wacom_battery_get_property;
- wacom->battery.name = wacom->wacom_wac.bat_name;
- wacom->battery.type = POWER_SUPPLY_TYPE_BATTERY;
- wacom->battery.use_for_apm = 0;
+ battery->battery.properties = wacom_battery_props;
+ battery->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
+ battery->battery.get_property = wacom_battery_get_property;
+ battery->battery.name = battery->bat_name;
+ battery->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ battery->battery.use_for_apm = 0;

- error = power_supply_register(&wacom->usbdev->dev,
- &wacom->battery);
+ error = power_supply_register(&wacom->usbdev->dev,
+ &battery->battery);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
- if (!error)
- power_supply_powers(&wacom->battery,
- &wacom->usbdev->dev);
+ if (!error)
+ power_supply_powers(&battery->battery,
+ &wacom->usbdev->dev);
#endif
- }
+
spin_unlock_irqrestore(&ps_lock, flags);

return error;
}

+static int wacom_initialize_battery(struct wacom *wacom)
+{
+ if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY)
+ return __wacom_initialize_battery(wacom, &wacom->battery);
+
+ return 0;
+}
+
static void wacom_destroy_battery(struct wacom *wacom)
{
- if (wacom->battery.dev) {
- power_supply_unregister(&wacom->battery);
- wacom->battery.dev = NULL;
+ if (wacom->battery.battery.dev) {
+ power_supply_unregister(&wacom->battery.battery);
+ wacom->battery.battery.dev = NULL;
+ }
+}
+
+static void wacom_destroy_remote_battery(struct wacom_battery *battery)
+{
+ if (battery->battery.dev) {
+ power_supply_unregister(&battery->battery);
+ battery->battery.dev = NULL;
}
}

@@ -1341,6 +1358,9 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
if (remote->remotes[index].input)
input_unregister_device(remote->remotes[index].input);

+ if (remote->remotes[index].battery.battery.dev)
+ wacom_destroy_remote_battery(&remote->remotes[index].battery);
+
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (remote->remotes[i].serial == serial) {
remote->remotes[i].serial = 0;
@@ -1402,7 +1422,7 @@ static void wacom_remotes_destroy(void *data)
return;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom->remote->remotes[i].group.name) {
+ if (remote->remotes[i].registered) {
wacom_remote_destroy_one(wacom, i);
}
}
@@ -1611,6 +1631,11 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,

remote->remotes[index].registered = true;

+ error = __wacom_initialize_battery(wacom,
+ &remote->remotes[index].battery);
+ if (error)
+ goto fail;
+
devres_close_group(dev, &remote->remotes[index]);

return 0;
@@ -1765,11 +1790,11 @@ void wacom_battery_work(struct work_struct *work)
struct wacom *wacom = container_of(work, struct wacom, battery_work);

if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
- !wacom->battery.dev) {
+ !wacom->battery.battery.dev) {
wacom_initialize_battery(wacom);
}
else if (!(wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
- wacom->battery.dev) {
+ wacom->battery.battery.dev) {
wacom_destroy_battery(wacom);
}
}
diff --git a/2.6.38/wacom_wac.c b/2.6.38/wacom_wac.c
index 4e246d0..4d14e97 100644
--- a/2.6.38/wacom_wac.c
+++ b/2.6.38/wacom_wac.c
@@ -41,27 +41,36 @@
static void wacom_report_numbered_buttons(struct input_dev *input_dev,
int button_cout, int mask);

-static void wacom_notify_battery(struct wacom_wac *wacom_wac,
+static void __wacom_notify_battery(struct wacom_battery *battery,
int bat_capacity, bool bat_charging, bool bat_connected,
bool ps_connected)
{
- struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- bool changed = wacom_wac->battery_capacity != bat_capacity ||
- wacom_wac->bat_charging != bat_charging ||
- wacom_wac->bat_connected != bat_connected ||
- wacom_wac->ps_connected != ps_connected;
+ bool changed = battery->battery_capacity != bat_capacity ||
+ battery->bat_charging != bat_charging ||
+ battery->bat_connected != bat_connected ||
+ battery->ps_connected != ps_connected;

if (changed) {
- wacom_wac->battery_capacity = bat_capacity;
- wacom_wac->bat_charging = bat_charging;
- wacom_wac->bat_connected = bat_connected;
- wacom_wac->ps_connected = ps_connected;
+ battery->battery_capacity = bat_capacity;
+ battery->bat_charging = bat_charging;
+ battery->bat_connected = bat_connected;
+ battery->ps_connected = ps_connected;

- if (wacom->battery.dev)
- power_supply_changed(&wacom->battery);
+ if (battery->battery.dev)
+ power_supply_changed(&battery->battery);
}
}

+static void wacom_notify_battery(struct wacom_wac *wacom_wac,
+ int bat_capacity, bool bat_charging, bool bat_connected,
+ bool ps_connected)
+{
+ struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+
+ __wacom_notify_battery(&wacom->battery, bat_capacity, bat_charging,
+ bat_connected, ps_connected);
+}
+
static int wacom_penpartner_irq(struct wacom_wac *wacom)
{
unsigned char *data = wacom->data;
@@ -701,7 +710,6 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
{
unsigned char *data = wacom_wac->data;
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- struct wacom_features *features = &wacom_wac->features;
struct wacom_remote *remote = wacom->remote;
struct input_dev *input;
int bat_charging, bat_percent, touch_ring_mode;
@@ -778,13 +786,8 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
wacom->led.select[i] = touch_ring_mode;
}

- if (!wacom->battery.dev &&
- !(features->quirks & WACOM_QUIRK_BATTERY)) {
- features->quirks |= WACOM_QUIRK_BATTERY;
- wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
- }
-
- wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1, bat_charging);
+ __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
+ bat_charging, 1, bat_charging);

out:
spin_unlock_irqrestore(&remote->remote_lock, flags);
@@ -1557,7 +1560,6 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)

static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
{
- struct wacom *w = container_of(wacom, struct wacom, wacom_wac);
unsigned char *data = wacom->data;
int connected;

@@ -1585,8 +1587,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
}

- if (w->battery.dev)
- wacom_notify_battery(wacom, battery, charging, 1, 0);
+ wacom_notify_battery(wacom, battery, charging, 1, 0);

} else if (wacom->pid != 0) {
/* disconnected while previously connected */
@@ -1623,14 +1624,14 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
wacom_notify_battery(wacom_wac, battery, charging,
battery || charging, 1);

- if (!wacom->battery.dev &&
+ if (!wacom->battery.battery.dev &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
features->quirks |= WACOM_QUIRK_BATTERY;
wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
}
}
else if ((features->quirks & WACOM_QUIRK_BATTERY) &&
- wacom->battery.dev) {
+ wacom->battery.battery.dev) {
features->quirks &= ~WACOM_QUIRK_BATTERY;
wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
@@ -1856,9 +1857,9 @@ void wacom_setup_device_quirks(struct wacom *wacom)
}
}

- if (features->type == REMOTE) {
+ if (features->type == REMOTE)
features->quirks |= WACOM_QUIRK_MONITOR;
- }
+
}

static void wacom_abs_set_axis(struct input_dev *input_dev,
diff --git a/2.6.38/wacom_wac.h b/2.6.38/wacom_wac.h
index abe52fb..844ab81 100644
--- a/2.6.38/wacom_wac.h
+++ b/2.6.38/wacom_wac.h
@@ -174,7 +174,6 @@ struct wacom_remote_data {

struct wacom_wac {
char name[WACOM_NAME_MAX];
- char bat_name[WACOM_NAME_MAX];
unsigned char *data;
int tool[2];
int id[2];
@@ -184,12 +183,8 @@ struct wacom_wac {
struct wacom_shared *shared;
struct input_dev *input;
int pid;
- int battery_capacity;
int num_contacts_left;
int *slots;
- int bat_charging;
- int bat_connected;
- int ps_connected;
};

#endif
diff --git a/3.17/wacom.h b/3.17/wacom.h
index c299a83..d3fb8b9 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -130,6 +130,24 @@ struct wacom_group_leds {
u8 select; /* status led selector (0..3) */
};

+struct wacom_battery {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
+ struct power_supply_desc bat_desc;
+ struct power_supply_desc ac_desc;
+ struct power_supply *battery;
+ struct power_supply *ac;
+#else
+ struct power_supply battery;
+ struct power_supply ac;
+#endif
+ char bat_name[WACOM_NAME_MAX];
+ char ac_name[WACOM_NAME_MAX];
+ int battery_capacity;
+ int bat_charging;
+ int bat_connected;
+ int ps_connected;
+};
+
struct wacom_remote {
spinlock_t remote_lock;
struct kfifo remote_fifo;
@@ -139,6 +157,7 @@ struct wacom_remote {
u32 serial;
struct input_dev *input;
bool registered;
+ struct wacom_battery battery;
} remotes[WACOM_MAX_REMOTES];
};

@@ -159,13 +178,9 @@ struct wacom {
u8 img_lum; /* OLED matrix display brightness */
} led;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
- struct power_supply *battery;
- struct power_supply *ac;
- struct power_supply_desc battery_desc;
- struct power_supply_desc ac_desc;
+ struct wacom_battery battery;
#else
- struct power_supply battery;
- struct power_supply ac;
+ struct wacom_battery battery;
#endif
bool resources;
};
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index efa03fb..793cb72 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1118,30 +1118,29 @@ static int wacom_battery_get_property(struct power_supply *psy,
union power_supply_propval *val)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
- struct wacom *wacom = power_supply_get_drvdata(psy);
+ struct wacom_battery *battery = power_supply_get_drvdata(psy);
#else
- struct wacom *wacom = container_of(psy, struct wacom, battery);
+ struct wacom_battery *battery = container_of(psy, struct wacom_battery, battery);
#endif
int ret = 0;

switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
- val->intval = wacom->wacom_wac.bat_connected;
+ val->intval = battery->bat_connected;
break;
case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- val->intval =
- wacom->wacom_wac.battery_capacity;
+ val->intval = battery->battery_capacity;
break;
case POWER_SUPPLY_PROP_STATUS:
- if (wacom->wacom_wac.bat_charging)
+ if (battery->bat_charging)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
- else if (wacom->wacom_wac.battery_capacity == 100 &&
- wacom->wacom_wac.ps_connected)
+ else if (battery->battery_capacity == 100 &&
+ battery->ps_connected)
val->intval = POWER_SUPPLY_STATUS_FULL;
- else if (wacom->wacom_wac.ps_connected)
+ else if (battery->ps_connected)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
@@ -1159,9 +1158,9 @@ static int wacom_ac_get_property(struct power_supply *psy,
union power_supply_propval *val)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
- struct wacom *wacom = power_supply_get_drvdata(psy);
+ struct wacom_battery *battery = power_supply_get_drvdata(psy);
#else
- struct wacom *wacom = container_of(psy, struct wacom, ac);
+ struct wacom_battery *battery = container_of(psy, struct wacom_battery, battery);
#endif
int ret = 0;

@@ -1169,7 +1168,7 @@ static int wacom_ac_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_PRESENT:
/* fall through */
case POWER_SUPPLY_PROP_ONLINE:
- val->intval = wacom->wacom_wac.ps_connected;
+ val->intval = battery->ps_connected;
break;
case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
@@ -1181,101 +1180,132 @@ static int wacom_ac_get_property(struct power_supply *psy,
return ret;
}

-static int wacom_initialize_battery(struct wacom *wacom)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
+static int __wacom_initialize_battery(struct wacom *wacom,
+ struct wacom_battery *battery)
{
static atomic_t battery_no = ATOMIC_INIT(0);
struct device *dev = &wacom->hdev->dev;
int error;
unsigned long n;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
- struct power_supply_config psy_cfg = { .drv_data = wacom, };
- struct power_supply_desc *bat_desc = &WACOM_POWERSUPPLY_DESC(wacom->battery);

- if (!devres_open_group(dev, bat_desc, GFP_KERNEL))
- return -ENOMEM;
-#endif
+ n = atomic_inc_return(&battery_no) - 1;

- if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) {
- n = atomic_inc_return(&battery_no) - 1;
-
- WACOM_POWERSUPPLY_DESC(wacom->battery).properties = wacom_battery_props;
- WACOM_POWERSUPPLY_DESC(wacom->battery).num_properties = ARRAY_SIZE(wacom_battery_props);
- WACOM_POWERSUPPLY_DESC(wacom->battery).get_property = wacom_battery_get_property;
- sprintf(wacom->wacom_wac.bat_name, "wacom_battery_%ld", n);
- WACOM_POWERSUPPLY_DESC(wacom->battery).name = wacom->wacom_wac.bat_name;
- WACOM_POWERSUPPLY_DESC(wacom->battery).type = POWER_SUPPLY_TYPE_BATTERY;
- WACOM_POWERSUPPLY_DESC(wacom->battery).use_for_apm = 0;
-
- WACOM_POWERSUPPLY_DESC(wacom->ac).properties = wacom_ac_props;
- WACOM_POWERSUPPLY_DESC(wacom->ac).num_properties = ARRAY_SIZE(wacom_ac_props);
- WACOM_POWERSUPPLY_DESC(wacom->ac).get_property = wacom_ac_get_property;
- sprintf(wacom->wacom_wac.ac_name, "wacom_ac_%ld", n);
- WACOM_POWERSUPPLY_DESC(wacom->ac).name = wacom->wacom_wac.ac_name;
- WACOM_POWERSUPPLY_DESC(wacom->battery).type = POWER_SUPPLY_TYPE_MAINS;
- WACOM_POWERSUPPLY_DESC(wacom->battery).use_for_apm = 0;
+ battery->battery.properties = wacom_battery_props;
+ battery->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
+ battery->battery.get_property = wacom_battery_get_property;
+ sprintf(wacom->battery.bat_name, "wacom_battery_%ld", n);
+ battery->battery.name = wacom->battery.bat_name;
+ battery->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ battery->battery.use_for_apm = 0;

-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
- wacom->battery = devm_power_supply_register(dev,
- &WACOM_POWERSUPPLY_DESC(wacom->battery),
- &psy_cfg);
- if (IS_ERR(wacom->battery)) {
- error = PTR_ERR(wacom->battery);
- goto err;
- }
-#else
- error = power_supply_register(dev,
- &wacom->battery);
+ battery->ac.properties = wacom_ac_props;
+ battery->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
+ battery->ac.get_property = wacom_ac_get_property;
+ sprintf(wacom->battery.ac_name, "wacom_ac_%ld", n);
+ battery->ac.name = wacom->battery.ac_name;
+ battery->ac.type = POWER_SUPPLY_TYPE_MAINS;
+ battery->ac.use_for_apm = 0;

- if (error)
- return error;
-#endif
+ error = power_supply_register(dev, &battery->battery);
+
+ if (error)
+ return error;

- power_supply_powers(WACOM_POWERSUPPLY_REF(wacom->battery), dev);
+ power_supply_powers(WACOM_POWERSUPPLY_REF(battery->battery), dev);
+
+ error = power_supply_register(dev, &battery->ac);
+
+ if (error) {
+ power_supply_unregister(&battery->battery);
+ return error;
+ }
+
+ power_supply_powers(WACOM_POWERSUPPLY_REF(battery->ac), dev);
+
+ return 0;
+}

-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
- wacom->ac = devm_power_supply_register(dev,
- &WACOM_POWERSUPPLY_DESC(wacom->battery),
- &psy_cfg);
- if (IS_ERR(wacom->ac)) {
- error = PTR_ERR(wacom->ac);
- goto err;
- }
#else
- error = power_supply_register(dev, &wacom->ac);
+static int __wacom_initialize_battery(struct wacom *wacom,
+ struct wacom_battery *battery)
+{
+ static atomic_t battery_no = ATOMIC_INIT(0);
+ struct device *dev = &wacom->hdev->dev;
+ struct power_supply_config psy_cfg = { .drv_data = battery, };
+ struct power_supply *ps_bat, *ps_ac;
+ struct power_supply_desc *bat_desc = &battery->bat_desc;
+ struct power_supply_desc *ac_desc = &battery->ac_desc;
+ unsigned long n;
+ int error;

- if (error) {
- power_supply_unregister(&wacom->battery);
- return error;
- }
-#endif
- power_supply_powers(WACOM_POWERSUPPLY_REF(wacom->ac), dev);
+ if (!devres_open_group(dev, bat_desc, GFP_KERNEL))
+ return -ENOMEM;
+
+ n = atomic_inc_return(&battery_no) - 1;
+
+ bat_desc->properties = wacom_battery_props;
+ bat_desc->num_properties = ARRAY_SIZE(wacom_battery_props);
+ bat_desc->get_property = wacom_battery_get_property;
+ sprintf(battery->bat_name, "wacom_battery_%ld", n);
+ bat_desc->name = battery->bat_name;
+ bat_desc->type = POWER_SUPPLY_TYPE_BATTERY;
+ bat_desc->use_for_apm = 0;
+
+ ac_desc->properties = wacom_ac_props;
+ ac_desc->num_properties = ARRAY_SIZE(wacom_ac_props);
+ ac_desc->get_property = wacom_ac_get_property;
+ sprintf(battery->ac_name, "wacom_ac_%ld", n);
+ ac_desc->name = battery->ac_name;
+ ac_desc->type = POWER_SUPPLY_TYPE_MAINS;
+ ac_desc->use_for_apm = 0;
+
+ ps_bat = devm_power_supply_register(dev, bat_desc, &psy_cfg);
+ if (IS_ERR(ps_bat)) {
+ error = PTR_ERR(ps_bat);
+ goto err;
}

-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
- devres_close_group(dev, bat_desc);
-#endif
+ ps_ac = devm_power_supply_register(dev, ac_desc, &psy_cfg);
+ if (IS_ERR(ps_ac)) {
+ error = PTR_ERR(ps_ac);
+ goto err;
+ }
+
+ power_supply_powers(ps_bat, &wacom->hdev->dev);
+ power_supply_powers(ps_ac, &wacom->hdev->dev);

+ battery->battery = ps_bat;
+ battery->ac = ps_ac;
+
+ devres_close_group(dev, bat_desc);
return 0;

-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
err:
devres_release_group(dev, bat_desc);
return error;
+}
#endif
+
+static int wacom_initialize_battery(struct wacom *wacom)
+{
+ if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY)
+ return __wacom_initialize_battery(wacom, &wacom->battery);
+
+ return 0;
}

static void wacom_destroy_battery(struct wacom *wacom)
{
- if (WACOM_POWERSUPPLY_DEVICE(wacom->battery)) {
-
+ if (WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery)) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
- devres_release_group(&wacom->hdev->dev, WACOM_POWERSUPPLY_DEVICE(wacom->battery));
+ devres_release_group(&wacom->hdev->dev, wacom->battery.battery);
#else
- power_supply_unregister(WACOM_POWERSUPPLY_REF(wacom->battery));
- power_supply_unregister(WACOM_POWERSUPPLY_REF(wacom->ac));
+ power_supply_unregister(&wacom->battery.battery);
+ power_supply_unregister(&wacom->battery.ac);
#endif
- WACOM_POWERSUPPLY_DEVICE(wacom->battery) = NULL;
- WACOM_POWERSUPPLY_DEVICE(wacom->ac) = NULL;
+ WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery) = NULL;
+ WACOM_POWERSUPPLY_DEVICE(wacom->battery.ac) = NULL;
}
}

@@ -1439,9 +1469,28 @@ static void wacom_remotes_destroy(void *data)
struct wacom *wacom = data;
struct wacom_remote *remote = wacom->remote;

+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
+ int i;
+ unsigned long flags;
+#endif
+
if (!remote)
return;

+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (remote->remotes[i].registered) {
+ spin_lock_irqsave(&remote->remote_lock, flags);
+ remote->remotes[i].registered = false;
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+
+ if (WACOM_POWERSUPPLY_DEVICE(remote->remotes[i].battery.battery)) {
+ power_supply_unregister(&remote->remotes[i].battery.battery);
+ power_supply_unregister(&remote->remotes[i].battery.ac);
+ }
+ }
+ }
+#endif
kobject_put(remote->remote_dir);
kfifo_free(&remote->remote_fifo);
wacom->remote = NULL;
@@ -1645,11 +1694,11 @@ void wacom_battery_work(struct work_struct *work)
struct wacom *wacom = container_of(work, struct wacom, battery_work);

if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
- !WACOM_POWERSUPPLY_DEVICE(wacom->battery)) {
+ !WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery)) {
wacom_initialize_battery(wacom);
}
else if (!(wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
- WACOM_POWERSUPPLY_DEVICE(wacom->battery)) {
+ WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery)) {
wacom_destroy_battery(wacom);
}
}
@@ -2047,6 +2096,11 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
if (error)
goto fail;

+ error = __wacom_initialize_battery(wacom,
+ &remote->remotes[index].battery);
+ if (error)
+ goto fail;
+
remote->remotes[index].registered = true;

devres_close_group(dev, &remote->remotes[index]);
diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 4cfd4dd..b2f3d6b 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -52,25 +52,34 @@ static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
*/
static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };

+static void __wacom_notify_battery(struct wacom_battery *battery,
+ int bat_capacity, bool bat_charging,
+ bool bat_connected, bool ps_connected)
+{
+ bool changed = battery->battery_capacity != bat_capacity ||
+ battery->bat_charging != bat_charging ||
+ battery->bat_connected != bat_connected ||
+ battery->ps_connected != ps_connected;
+
+ if (changed) {
+ battery->battery_capacity = bat_capacity;
+ battery->bat_charging = bat_charging;
+ battery->bat_connected = bat_connected;
+ battery->ps_connected = ps_connected;
+
+ if (WACOM_POWERSUPPLY_DEVICE(battery->battery))
+ power_supply_changed(WACOM_POWERSUPPLY_REF(battery->battery));
+ }
+}
+
static void wacom_notify_battery(struct wacom_wac *wacom_wac,
int bat_capacity, bool bat_charging, bool bat_connected,
bool ps_connected)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- bool changed = wacom_wac->battery_capacity != bat_capacity ||
- wacom_wac->bat_charging != bat_charging ||
- wacom_wac->bat_connected != bat_connected ||
- wacom_wac->ps_connected != ps_connected;

- if (changed) {
- wacom_wac->battery_capacity = bat_capacity;
- wacom_wac->bat_charging = bat_charging;
- wacom_wac->bat_connected = bat_connected;
- wacom_wac->ps_connected = ps_connected;
-
- if (WACOM_POWERSUPPLY_DEVICE(wacom->battery))
- power_supply_changed(WACOM_POWERSUPPLY_REF(wacom->battery));
- }
+ __wacom_notify_battery(&wacom->battery, bat_capacity, bat_charging,
+ bat_connected, ps_connected);
}

static int wacom_penpartner_irq(struct wacom_wac *wacom)
@@ -760,7 +769,6 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
struct input_dev *input;
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
struct wacom_remote *remote = wacom->remote;
- struct wacom_features *features = &wacom_wac->features;
int bat_charging, bat_percent, touch_ring_mode;
__u32 serial;
int i, index = -1;
@@ -835,14 +843,9 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
wacom->led.groups[i].select = touch_ring_mode;
}

- if (!WACOM_POWERSUPPLY_DEVICE(wacom->battery) &&
- !(features->quirks & WACOM_QUIRK_BATTERY)) {
- features->quirks |= WACOM_QUIRK_BATTERY;
- wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
- }
+ __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
+ bat_charging, 1, bat_charging);

- wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1,
- bat_charging);

out:
spin_unlock_irqrestore(&remote->remote_lock, flags);
@@ -2139,7 +2142,6 @@ static int wacom_bamboo_pad_irq(struct wacom_wac *wacom, size_t len)

static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
{
- struct wacom *w = container_of(wacom, struct wacom, wacom_wac);
unsigned char *data = wacom->data;
int connected;

@@ -2167,8 +2169,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
}

- if (WACOM_POWERSUPPLY_DEVICE(w->battery))
- wacom_notify_battery(wacom, battery, charging, 1, 0);
+ wacom_notify_battery(wacom, battery, charging, 1, 0);

} else if (wacom->pid != 0) {
/* disconnected while previously connected */
@@ -2205,14 +2206,14 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
wacom_notify_battery(wacom_wac, battery, charging,
battery || charging, 1);

- if (!WACOM_POWERSUPPLY_DEVICE(wacom->battery) &&
+ if (!WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery) &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
features->quirks |= WACOM_QUIRK_BATTERY;
wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
}
}
else if ((features->quirks & WACOM_QUIRK_BATTERY) &&
- WACOM_POWERSUPPLY_DEVICE(wacom->battery)) {
+ WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery)) {
features->quirks &= ~WACOM_QUIRK_BATTERY;
wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h
index b3c1a09..84e94ce 100644
--- a/3.17/wacom_wac.h
+++ b/3.17/wacom_wac.h
@@ -229,8 +229,6 @@ struct wacom_wac {
char pen_name[WACOM_NAME_MAX];
char touch_name[WACOM_NAME_MAX];
char pad_name[WACOM_NAME_MAX];
- char bat_name[WACOM_NAME_MAX];
- char ac_name[WACOM_NAME_MAX];
unsigned char data[WACOM_PKGLEN_MAX];
int tool[2];
int id[2];
@@ -242,11 +240,7 @@ struct wacom_wac {
struct input_dev *touch_input;
struct input_dev *pad_input;
int pid;
- int battery_capacity;
int num_contacts_left;
- int bat_charging;
- int bat_connected;
- int ps_connected;
u8 bt_features;
u8 bt_high_speed;
int mode_report;
diff --git a/3.7/wacom.h b/3.7/wacom.h
index 1183cbb..c6fc12c 100644
--- a/3.7/wacom.h
+++ b/3.7/wacom.h
@@ -115,6 +115,17 @@ enum wacom_worker {
WACOM_WORKER_REMOTE,
};

+struct wacom_battery {
+ struct power_supply battery;
+ struct power_supply ac;
+ char bat_name[WACOM_NAME_MAX];
+ char ac_name[WACOM_NAME_MAX];
+ int battery_capacity;
+ int bat_charging;
+ int bat_connected;
+ int ps_connected;
+};
+
struct wacom_remote {
spinlock_t remote_lock;
struct kfifo remote_fifo;
@@ -124,6 +135,7 @@ struct wacom_remote {
u32 serial;
struct input_dev *input;
bool registered;
+ struct wacom_battery battery;
} remotes[WACOM_MAX_REMOTES];
};

@@ -146,7 +158,7 @@ struct wacom {
u8 hlv; /* status led brightness button pressed (1..127) */
u8 img_lum; /* OLED matrix display brightness */
} led;
- struct power_supply battery;
+ struct wacom_battery battery;
};

static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c
index 3801468..0094ff5 100644
--- a/3.7/wacom_sys.c
+++ b/3.7/wacom_sys.c
@@ -1156,27 +1156,28 @@ static int wacom_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
- struct wacom *wacom = container_of(psy, struct wacom, battery);
+ struct wacom_battery *battery = container_of(psy, struct wacom_battery,
+ battery);
+
int ret = 0;

switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
- val->intval = wacom->wacom_wac.bat_connected;
+ val->intval = battery->bat_connected;
break;
case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- val->intval =
- wacom->wacom_wac.battery_capacity;
+ val->intval = battery->battery_capacity;
break;
case POWER_SUPPLY_PROP_STATUS:
- if (wacom->wacom_wac.bat_charging)
+ if (battery->bat_charging)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
- else if (wacom->wacom_wac.battery_capacity == 100 &&
- wacom->wacom_wac.ps_connected)
+ else if (battery->battery_capacity == 100 &&
+ battery->ps_connected)
val->intval = POWER_SUPPLY_STATUS_FULL;
- else if (wacom->wacom_wac.ps_connected)
+ else if (battery->ps_connected)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
@@ -1189,46 +1190,64 @@ static int wacom_battery_get_property(struct power_supply *psy,
return ret;
}

-static int wacom_initialize_battery(struct wacom *wacom)
+static int __wacom_initialize_battery(struct wacom *wacom,
+ struct wacom_battery *battery)
{
static atomic_t battery_no = ATOMIC_INIT(0);
static DEFINE_SPINLOCK(ps_lock);
unsigned long flags;
int error = 0;
+ unsigned long n;

spin_lock_irqsave(&ps_lock, flags); /* Prevent potential race for the "wacom_battery" name */
- if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) {
- unsigned long n = atomic_inc_return(&battery_no) - 1;
-
- if (power_supply_get_by_name("wacom_battery"))
- sprintf(wacom->wacom_wac.bat_name, "wacom_battery_%ld", n);
- else
- sprintf(wacom->wacom_wac.bat_name, "wacom_battery");
-
- wacom->battery.properties = wacom_battery_props;
- wacom->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
- wacom->battery.get_property = wacom_battery_get_property;
- wacom->battery.name = wacom->wacom_wac.bat_name;
- wacom->battery.type = POWER_SUPPLY_TYPE_BATTERY;
- wacom->battery.use_for_apm = 0;
-
- error = power_supply_register(&wacom->usbdev->dev,
- &wacom->battery);
-
- if (!error)
- power_supply_powers(&wacom->battery,
- &wacom->usbdev->dev);
- }
+
+ n = atomic_inc_return(&battery_no) - 1;
+
+ if (power_supply_get_by_name("wacom_battery"))
+ sprintf(battery->bat_name, "wacom_battery_%ld", n);
+ else
+ sprintf(battery->bat_name, "wacom_battery");
+
+ battery->battery.properties = wacom_battery_props;
+ battery->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
+ battery->battery.get_property = wacom_battery_get_property;
+ battery->battery.name = battery->bat_name;
+ battery->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ battery->battery.use_for_apm = 0;
+
+ error = power_supply_register(&wacom->usbdev->dev,
+ &battery->battery);
+
+ if (!error)
+ power_supply_powers(&battery->battery,
+ &wacom->usbdev->dev);
+
spin_unlock_irqrestore(&ps_lock, flags);

return error;
}

+static int wacom_initialize_battery(struct wacom *wacom)
+{
+ if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY)
+ return __wacom_initialize_battery(wacom, &wacom->battery);
+
+ return 0;
+}
+
static void wacom_destroy_battery(struct wacom *wacom)
{
- if (wacom->battery.dev) {
- power_supply_unregister(&wacom->battery);
- wacom->battery.dev = NULL;
+ if (wacom->battery.battery.dev) {
+ power_supply_unregister(&wacom->battery.battery);
+ wacom->battery.battery.dev = NULL;
+ }
+}
+
+static void wacom_destroy_remote_battery(struct wacom_battery *battery)
+{
+ if (battery->battery.dev) {
+ power_supply_unregister(&battery->battery);
+ battery->battery.dev = NULL;
}
}

@@ -1333,6 +1352,9 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
if (remote->remotes[index].input)
input_unregister_device(remote->remotes[index].input);

+ if (remote->remotes[index].battery.battery.dev)
+ wacom_destroy_remote_battery(&remote->remotes[index].battery);
+
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (remote->remotes[i].serial == serial) {
remote->remotes[i].serial = 0;
@@ -1392,7 +1414,7 @@ static void wacom_remotes_destroy(struct wacom *wacom)
return;

for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom->remote->remotes[i].group.name) {
+ if (remote->remotes[i].registered) {
wacom_remote_destroy_one(wacom, i);
}
}
@@ -1600,6 +1622,11 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,

remote->remotes[index].registered = true;

+ error = __wacom_initialize_battery(wacom,
+ &remote->remotes[index].battery);
+ if (error)
+ goto fail;
+
devres_close_group(dev, &remote->remotes[index]);

return 0;
@@ -1758,11 +1785,11 @@ void wacom_battery_work(struct work_struct *work)
struct wacom *wacom = container_of(work, struct wacom, battery_work);

if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
- !wacom->battery.dev) {
+ !wacom->battery.battery.dev) {
wacom_initialize_battery(wacom);
}
else if (!(wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
- wacom->battery.dev) {
+ wacom->battery.battery.dev) {
wacom_destroy_battery(wacom);
}
}
diff --git a/3.7/wacom_wac.c b/3.7/wacom_wac.c
index 252e871..ed8cedb 100644
--- a/3.7/wacom_wac.c
+++ b/3.7/wacom_wac.c
@@ -41,27 +41,36 @@
static void wacom_report_numbered_buttons(struct input_dev *input_dev,
int button_cout, int mask);

-static void wacom_notify_battery(struct wacom_wac *wacom_wac,
+static void __wacom_notify_battery(struct wacom_battery *battery,
int bat_capacity, bool bat_charging, bool bat_connected,
bool ps_connected)
{
- struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- bool changed = wacom_wac->battery_capacity != bat_capacity ||
- wacom_wac->bat_charging != bat_charging ||
- wacom_wac->bat_connected != bat_connected ||
- wacom_wac->ps_connected != ps_connected;
+ bool changed = battery->battery_capacity != bat_capacity ||
+ battery->bat_charging != bat_charging ||
+ battery->bat_connected != bat_connected ||
+ battery->ps_connected != ps_connected;

if (changed) {
- wacom_wac->battery_capacity = bat_capacity;
- wacom_wac->bat_charging = bat_charging;
- wacom_wac->bat_connected = bat_connected;
- wacom_wac->ps_connected = ps_connected;
+ battery->battery_capacity = bat_capacity;
+ battery->bat_charging = bat_charging;
+ battery->bat_connected = bat_connected;
+ battery->ps_connected = ps_connected;

- if (wacom->battery.dev)
- power_supply_changed(&wacom->battery);
+ if (battery->battery.dev)
+ power_supply_changed(&battery->battery);
}
}

+static void wacom_notify_battery(struct wacom_wac *wacom_wac,
+ int bat_capacity, bool bat_charging, bool bat_connected,
+ bool ps_connected)
+{
+ struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+
+ __wacom_notify_battery(&wacom->battery, bat_capacity, bat_charging,
+ bat_connected, ps_connected);
+}
+
static int wacom_penpartner_irq(struct wacom_wac *wacom)
{
unsigned char *data = wacom->data;
@@ -701,7 +710,6 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
{
unsigned char *data = wacom_wac->data;
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- struct wacom_features *features = &wacom_wac->features;
struct wacom_remote *remote = wacom->remote;
struct input_dev *input;
int bat_charging, bat_percent, touch_ring_mode;
@@ -778,14 +786,8 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
wacom->led.select[i] = touch_ring_mode;
}

- if (!wacom->battery.dev &&
- !(features->quirks & WACOM_QUIRK_BATTERY)) {
- features->quirks |= WACOM_QUIRK_BATTERY;
- wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
- }
-
- wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1,
- bat_charging);
+ __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
+ bat_charging, 1, bat_charging);

out:
spin_unlock_irqrestore(&remote->remote_lock, flags);
@@ -1537,7 +1539,6 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)

static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
{
- struct wacom *w = container_of(wacom, struct wacom, wacom_wac);
unsigned char *data = wacom->data;
int connected;

@@ -1565,8 +1566,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
}

- if (w->battery.dev)
- wacom_notify_battery(wacom, battery, charging, 1, 0);
+ wacom_notify_battery(wacom, battery, charging, 1, 0);

} else if (wacom->pid != 0) {
/* disconnected while previously connected */
@@ -1603,14 +1603,14 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
wacom_notify_battery(wacom_wac, battery, charging,
battery || charging, 1);

- if (!wacom->battery.dev &&
+ if (!wacom->battery.battery.dev &&
!(features->quirks & WACOM_QUIRK_BATTERY)) {
features->quirks |= WACOM_QUIRK_BATTERY;
wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
}
}
else if ((features->quirks & WACOM_QUIRK_BATTERY) &&
- wacom->battery.dev) {
+ wacom->battery.battery.dev) {
features->quirks &= ~WACOM_QUIRK_BATTERY;
wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
@@ -1835,9 +1835,8 @@ void wacom_setup_device_quirks(struct wacom *wacom)
}
}

- if (features->type == REMOTE) {
+ if (features->type == REMOTE)
features->quirks |= WACOM_QUIRK_MONITOR;
- }
}

static void wacom_abs_set_axis(struct input_dev *input_dev,
diff --git a/3.7/wacom_wac.h b/3.7/wacom_wac.h
index 7e12b8b..25a9ac5 100644
--- a/3.7/wacom_wac.h
+++ b/3.7/wacom_wac.h
@@ -174,7 +174,6 @@ struct wacom_remote_data {

struct wacom_wac {
char name[WACOM_NAME_MAX];
- char bat_name[WACOM_NAME_MAX];
unsigned char *data;
int tool[2];
int id[2];
@@ -184,11 +183,7 @@ struct wacom_wac {
struct wacom_shared *shared;
struct input_dev *input;
int pid;
- int battery_capacity;
int num_contacts_left;
- int bat_charging;
- int bat_connected;
- int ps_connected;
};

#endif
--
2.7.4
Aaron Armstrong Skomra
2016-10-20 18:43:16 UTC
Permalink
Instead of displaying a generic "tablet", now g-c-c shows a pretty
"Wacom Intuos Pro S (WL)".

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (9956953)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (e440823)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom.h | 1 +
3.17/wacom_sys.c | 11 +++++++++++
3.17/wacom_wac.h | 1 +
3 files changed, 13 insertions(+)

diff --git a/3.17/wacom.h b/3.17/wacom.h
index cb93199..1e2c898 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -131,6 +131,7 @@ struct wacom_group_leds {
};

struct wacom_battery {
+ struct wacom *wacom;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
struct power_supply_desc bat_desc;
struct power_supply *battery;
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 3330450..dde0466 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1101,6 +1101,7 @@ static int wacom_initialize_leds(struct wacom *wacom)
}

static enum power_supply_property wacom_battery_props[] = {
+ POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_SCOPE,
@@ -1119,6 +1120,9 @@ static int wacom_battery_get_property(struct power_supply *psy,
int ret = 0;

switch (psp) {
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = battery->wacom->wacom_wac.name;
+ break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = battery->bat_connected;
break;
@@ -1191,6 +1195,8 @@ static int __wacom_initialize_battery(struct wacom *wacom,
if (!devres_open_group(dev, bat_desc, GFP_KERNEL))
return -ENOMEM;

+ battery->wacom = wacom;
+
n = atomic_inc_return(&battery_no) - 1;

bat_desc->properties = wacom_battery_props;
@@ -1688,6 +1694,9 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
strlcpy(name, features->name, sizeof(name));
}

+ snprintf(wacom_wac->name, sizeof(wacom_wac->name), "%s%s",
+ name, suffix);
+
/* Append the device type to the name */
snprintf(wacom_wac->pen_name, sizeof(wacom_wac->pen_name),
"%s%s Pen", name, suffix);
@@ -1937,6 +1946,8 @@ static void wacom_wireless_work(struct work_struct *work)
goto fail;
}

+ strlcpy(wacom_wac->name, wacom_wac1->name,
+ sizeof(wacom_wac->name));
error = wacom_initialize_battery(wacom);
if (error)
goto fail;
diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h
index 84e94ce..20ce7cc 100644
--- a/3.17/wacom_wac.h
+++ b/3.17/wacom_wac.h
@@ -226,6 +226,7 @@ struct wacom_remote_data {
};

struct wacom_wac {
+ char name[WACOM_NAME_MAX];
char pen_name[WACOM_NAME_MAX];
char touch_name[WACOM_NAME_MAX];
char pad_name[WACOM_NAME_MAX];
--
2.7.4
Ping Cheng
2016-10-24 22:09:57 UTC
Permalink
Thank you Aaron for the heavy backward lifting! It is a big bonus for
those users who don't/can't upgrade their systems...

The patchset looks fine to me.

Acked-by: Ping Cheng <***@wacom.com>

Ping

On Thu, Oct 20, 2016 at 11:42 AM, Aaron Armstrong Skomra
Post by Aaron Armstrong Skomra
Since fd5f92b ("HID: wacom: reuse wacom_parse_and_register() in
wireless_work"), wacom->shared->type is not set.
Send the information of the battery if we have one.
---
2.6.38/wacom_wac.c | 3 ++-
3.17/wacom_wac.c | 3 ++-
3.7/wacom_wac.c | 3 ++-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/2.6.38/wacom_wac.c b/2.6.38/wacom_wac.c
index 91bf137..379bfdb 100644
--- a/2.6.38/wacom_wac.c
+++ b/2.6.38/wacom_wac.c
@@ -1547,6 +1547,7 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
{
+ struct wacom *w = container_of(wacom, struct wacom, wacom_wac);
unsigned char *data = wacom->data;
int connected;
@@ -1574,7 +1575,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
wacom_schedule_work(wacom);
}
- if (wacom->shared->type)
+ if (w->battery.dev)
wacom_notify_battery(wacom, battery, charging, 1, 0);
} else if (wacom->pid != 0) {
diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 81df74e..89cbe51 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -2131,6 +2131,7 @@ static int wacom_bamboo_pad_irq(struct wacom_wac *wacom, size_t len)
static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
{
+ struct wacom *w = container_of(wacom, struct wacom, wacom_wac);
unsigned char *data = wacom->data;
int connected;
@@ -2158,7 +2159,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
wacom_schedule_work(wacom);
}
- if (wacom->shared->type)
+ if (WACOM_POWERSUPPLY_DEVICE(w->battery))
wacom_notify_battery(wacom, battery, charging, 1, 0);
} else if (wacom->pid != 0) {
diff --git a/3.7/wacom_wac.c b/3.7/wacom_wac.c
index 3aac8ea..2a9e173 100644
--- a/3.7/wacom_wac.c
+++ b/3.7/wacom_wac.c
@@ -1528,6 +1528,7 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
{
+ struct wacom *w = container_of(wacom, struct wacom, wacom_wac);
unsigned char *data = wacom->data;
int connected;
@@ -1555,7 +1556,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
wacom_schedule_work(wacom);
}
- if (wacom->shared->type)
+ if (w->battery.dev)
wacom_notify_battery(wacom, battery, charging, 1, 0);
} else if (wacom->pid != 0) {
--
2.7.4
Loading...