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 <benjamin.tissoi...@redhat.com>
Acked-by: Ping Cheng <pi...@wacom.com>
Signed-off-by: Jiri Kosina <jkos...@suse.cz>
[aaron.sko...@wacom.com: Imported into input-wacom repository (83e6b40)]
Signed-off-by: Aaron Armstrong Skomra <aaron.sko...@wacom.com>
[aaron.sko...@wacom.com: Backported from input-wacom repository (3c055ea)]
Signed-off-by: Aaron Armstrong Skomra <aaron.sko...@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


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most 
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
_______________________________________________
Linuxwacom-devel mailing list
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to