Merge branches 'upstream-fixes', 'wacom' and 'waltop' into for-linus
authorJiri Kosina <jkosina@suse.cz>
Tue, 22 May 2012 09:33:42 +0000 (11:33 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 22 May 2012 09:35:11 +0000 (11:35 +0200)
Conflicts:
drivers/hid/hid-core.c

Documentation/ABI/testing/sysfs-driver-wacom
drivers/hid/Kconfig
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-wacom.c
drivers/hid/hid-waltop.c
drivers/hid/hid-wiimote-core.c
drivers/hid/usbhid/hid-quirks.c

index 0130d66..56c5455 100644 (file)
@@ -9,6 +9,14 @@ Description:
                or 0 otherwise. Writing to this file one of these values
                switches reporting speed.
 
+What:          /sys/class/leds/0005\:056A\:00BD.0001\:selector\:*/
+Date:          May 2012
+Kernel Version:        3.5
+Contact:       linux-bluetooth@vger.kernel.org
+Description:
+               LED selector for Intuos4 WL. There are 4 leds, but only one LED
+               can be lit at a time. Max brightness is 127.
+
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/led
 Date:          August 2011
 Contact:       linux-input@vger.kernel.org
index 80175c3..e9c68fe 100644 (file)
@@ -32,9 +32,13 @@ config HID
          If unsure, say Y.
 
 config HID_BATTERY_STRENGTH
-       bool
+       bool "Battery level reporting for HID devices"
        depends on HID && POWER_SUPPLY && HID = POWER_SUPPLY
        default n
+       ---help---
+       This option adds support of reporting battery strength (for HID devices
+       that support this feature) through power_supply class so that userspace
+       tools, such as upower, can display it.
 
 config HIDRAW
        bool "/dev/hidraw raw HID device support"
@@ -613,16 +617,10 @@ config THRUSTMASTER_FF
 config HID_WACOM
        tristate "Wacom Bluetooth devices support"
        depends on BT_HIDP
-       ---help---
-       Support for Wacom Graphire Bluetooth tablet.
-
-config HID_WACOM_POWER_SUPPLY
-       bool "Wacom Bluetooth devices power supply status support"
-       depends on HID_WACOM
+       depends on LEDS_CLASS
        select POWER_SUPPLY
        ---help---
-         Say Y here if you want to enable power supply status monitoring for
-         Wacom Bluetooth devices.
+       Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.
 
 config HID_WIIMOTE
        tristate "Nintendo Wii Remote support"
index 7a79e39..fa10f84 100644 (file)
@@ -458,6 +458,9 @@ static const struct hid_device_id apple_devices[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
                        APPLE_ISO_KEYBOARD },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+                               USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
index 9831a2c..8e3a6b2 100644 (file)
@@ -1511,7 +1511,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_BAANTO, USB_DEVICE_ID_BAANTO_MT_190W2), },
        { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
@@ -1660,6 +1659,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_PID_0038) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
        { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
index 4ff9941..9373f53 100644 (file)
 #define USB_DEVICE_ID_WALTOP_PID_0038                  0x0038
 #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH    0x0501
 #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH    0x0500
+#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET        0x0502
 
 #define USB_VENDOR_ID_WISEGROUP                0x0925
 #define USB_DEVICE_ID_SMARTJOY_PLUS    0x0005
index 7b43186..132b001 100644 (file)
@@ -225,7 +225,10 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
         * Verify and convert units.
         * See HID specification v1.11 6.2.2.7 Global Items for unit decoding
         */
-       if (code == ABS_X || code == ABS_Y || code == ABS_Z) {
+       switch (code) {
+       case ABS_X:
+       case ABS_Y:
+       case ABS_Z:
                if (field->unit == 0x11) {              /* If centimeters */
                        /* Convert to millimeters */
                        unit_exponent += 1;
@@ -239,7 +242,13 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
                } else {
                        return 0;
                }
-       } else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) {
+               break;
+
+       case ABS_RX:
+       case ABS_RY:
+       case ABS_RZ:
+       case ABS_TILT_X:
+       case ABS_TILT_Y:
                if (field->unit == 0x14) {              /* If degrees */
                        /* Convert to radians */
                        prev = logical_extents;
@@ -250,7 +259,9 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
                } else if (field->unit != 0x12) {       /* If not radians */
                        return 0;
                }
-       } else {
+               break;
+
+       default:
                return 0;
        }
 
@@ -623,6 +634,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                        map_key_clear(BTN_TOOL_RUBBER);
                        break;
 
+               case 0x3d: /* X Tilt */
+                       map_abs_clear(ABS_TILT_X);
+                       break;
+
+               case 0x3e: /* Y Tilt */
+                       map_abs_clear(ABS_TILT_Y);
+                       break;
+
                case 0x33: /* Touch */
                case 0x42: /* TipSwitch */
                case 0x43: /* TipSwitch2 */
index e1c38bb..5e8a7ed 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/hid.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <asm/unaligned.h>
 #include "usbhid/usbhid.h"
 #include "hid-ids.h"
 #include "hid-logitech-dj.h"
@@ -273,8 +274,8 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
                goto dj_device_allocate_fail;
        }
 
-       dj_dev->reports_supported = le32_to_cpu(
-               dj_report->report_params[DEVICE_PAIRED_RF_REPORT_TYPE]);
+       dj_dev->reports_supported = get_unaligned_le32(
+               dj_report->report_params + DEVICE_PAIRED_RF_REPORT_TYPE);
        dj_dev->hdev = dj_hiddev;
        dj_dev->dj_receiver_dev = djrcv_dev;
        dj_dev->device_index = dj_report->device_index;
index 067e296..fe23a1e 100644 (file)
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/module.h>
+#include <linux/leds.h>
 #include <linux/slab.h>
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
 #include <linux/power_supply.h>
-#endif
 
 #include "hid-ids.h"
 
 #define PAD_DEVICE_ID  0x0F
 
+#define WAC_CMD_LED_CONTROL     0x20
+
 struct wacom_data {
        __u16 tool;
        __u16 butstate;
@@ -41,16 +42,20 @@ struct wacom_data {
        __u32 id;
        __u32 serial;
        unsigned char high_speed;
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
-       int battery_capacity;
+       __u8 battery_capacity;
+       __u8 power_raw;
+       __u8 ps_connected;
        struct power_supply battery;
        struct power_supply ac;
-#endif
+       __u8 led_selector;
+       struct led_classdev *leds[4];
 };
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
-/*percent of battery capacity, 0 means AC online*/
-static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 };
+/*percent of battery capacity for Graphire
+  8th value means AC online and show 100% capacity */
+static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
+/*percent of battery capacity for Intuos4 WL, AC has a separate bit*/
+static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
 
 static enum power_supply_property wacom_battery_props[] = {
        POWER_SUPPLY_PROP_PRESENT,
@@ -64,13 +69,123 @@ static enum power_supply_property wacom_ac_props[] = {
        POWER_SUPPLY_PROP_SCOPE,
 };
 
+static void wacom_leds_set_brightness(struct led_classdev *led_dev,
+                                               enum led_brightness value)
+{
+       struct device *dev = led_dev->dev->parent;
+       struct hid_device *hdev;
+       struct wacom_data *wdata;
+       unsigned char *buf;
+       __u8 led = 0;
+       int i;
+
+       hdev = container_of(dev, struct hid_device, dev);
+       wdata = hid_get_drvdata(hdev);
+       for (i = 0; i < 4; ++i) {
+               if (wdata->leds[i] == led_dev)
+                       wdata->led_selector = i;
+       }
+
+       led = wdata->led_selector | 0x04;
+       buf = kzalloc(9, GFP_KERNEL);
+       if (buf) {
+               buf[0] = WAC_CMD_LED_CONTROL;
+               buf[1] = led;
+               buf[2] = value;
+               hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
+               kfree(buf);
+       }
+
+       return;
+}
+
+static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev)
+{
+       struct wacom_data *wdata;
+       struct device *dev = led_dev->dev->parent;
+       int value = 0;
+       int i;
+
+       wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+       for (i = 0; i < 4; ++i) {
+               if (wdata->leds[i] == led_dev) {
+                       value = wdata->leds[i]->brightness;
+                       break;
+               }
+       }
+
+       return value;
+}
+
+
+static int wacom_initialize_leds(struct hid_device *hdev)
+{
+       struct wacom_data *wdata = hid_get_drvdata(hdev);
+       struct led_classdev *led;
+       struct device *dev = &hdev->dev;
+       size_t namesz = strlen(dev_name(dev)) + 12;
+       char *name;
+       int i, ret;
+
+       wdata->led_selector = 0;
+
+       for (i = 0; i < 4; i++) {
+               led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
+               if (!led) {
+                       hid_warn(hdev,
+                                "can't allocate memory for LED selector\n");
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               name = (void *)&led[1];
+               snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i);
+               led->name = name;
+               led->brightness = 0;
+               led->max_brightness = 127;
+               led->brightness_get = wacom_leds_get_brightness;
+               led->brightness_set = wacom_leds_set_brightness;
+
+               wdata->leds[i] = led;
+
+               ret = led_classdev_register(dev, wdata->leds[i]);
+
+               if (ret) {
+                       wdata->leds[i] = NULL;
+                       kfree(led);
+                       hid_warn(hdev, "can't register LED\n");
+                       goto err;
+               }
+       }
+
+err:
+       return ret;
+}
+
+static void wacom_destroy_leds(struct hid_device *hdev)
+{
+       struct wacom_data *wdata = hid_get_drvdata(hdev);
+       struct led_classdev *led;
+       int i;
+
+       for (i = 0; i < 4; ++i) {
+               if (wdata->leds[i]) {
+                       led = wdata->leds[i];
+                       wdata->leds[i] = NULL;
+                       led_classdev_unregister(led);
+                       kfree(led);
+               }
+       }
+
+}
+
 static int wacom_battery_get_property(struct power_supply *psy,
                                enum power_supply_property psp,
                                union power_supply_propval *val)
 {
        struct wacom_data *wdata = container_of(psy,
                                        struct wacom_data, battery);
-       int power_state = batcap[wdata->battery_capacity];
        int ret = 0;
 
        switch (psp) {
@@ -81,11 +196,7 @@ static int wacom_battery_get_property(struct power_supply *psy,
                val->intval = POWER_SUPPLY_SCOPE_DEVICE;
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
-               /* show 100% battery capacity when charging */
-               if (power_state == 0)
-                       val->intval = 100;
-               else
-                       val->intval = power_state;
+               val->intval = wdata->battery_capacity;
                break;
        default:
                ret = -EINVAL;
@@ -99,17 +210,13 @@ static int wacom_ac_get_property(struct power_supply *psy,
                                union power_supply_propval *val)
 {
        struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
-       int power_state = batcap[wdata->battery_capacity];
        int ret = 0;
 
        switch (psp) {
        case POWER_SUPPLY_PROP_PRESENT:
                /* fall through */
        case POWER_SUPPLY_PROP_ONLINE:
-               if (power_state == 0)
-                       val->intval = 1;
-               else
-                       val->intval = 0;
+               val->intval = wdata->ps_connected;
                break;
        case POWER_SUPPLY_PROP_SCOPE:
                val->intval = POWER_SUPPLY_SCOPE_DEVICE;
@@ -120,41 +227,16 @@ static int wacom_ac_get_property(struct power_supply *psy,
        }
        return ret;
 }
-#endif
-
-static void wacom_set_features(struct hid_device *hdev)
-{
-       int ret;
-       __u8 rep_data[2];
-
-       /*set high speed, tablet mode*/
-       rep_data[0] = 0x03;
-       rep_data[1] = 0x20;
-       ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
-                               HID_FEATURE_REPORT);
-       return;
-}
 
-static void wacom_poke(struct hid_device *hdev, u8 speed)
+static void wacom_set_features(struct hid_device *hdev, u8 speed)
 {
        struct wacom_data *wdata = hid_get_drvdata(hdev);
        int limit, ret;
-       char rep_data[2];
-
-       rep_data[0] = 0x03 ; rep_data[1] = 0x00;
-       limit = 3;
-       do {
-               ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
-                               HID_FEATURE_REPORT);
-       } while (ret < 0 && limit-- > 0);
-
-       if (ret >= 0) {
-               if (speed == 0)
-                       rep_data[0] = 0x05;
-               else
-                       rep_data[0] = 0x06;
+       __u8 rep_data[2];
 
-               rep_data[1] = 0x00;
+       switch (hdev->product) {
+       case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
+               rep_data[0] = 0x03 ; rep_data[1] = 0x00;
                limit = 3;
                do {
                        ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
@@ -162,17 +244,47 @@ static void wacom_poke(struct hid_device *hdev, u8 speed)
                } while (ret < 0 && limit-- > 0);
 
                if (ret >= 0) {
-                       wdata->high_speed = speed;
-                       return;
+                       if (speed == 0)
+                               rep_data[0] = 0x05;
+                       else
+                               rep_data[0] = 0x06;
+
+                       rep_data[1] = 0x00;
+                       limit = 3;
+                       do {
+                               ret = hdev->hid_output_raw_report(hdev,
+                                       rep_data, 2, HID_FEATURE_REPORT);
+                       } while (ret < 0 && limit-- > 0);
+
+                       if (ret >= 0) {
+                               wdata->high_speed = speed;
+                               return;
+                       }
                }
+
+               /*
+                * Note that if the raw queries fail, it's not a hard failure
+                * and it is safe to continue
+                */
+               hid_warn(hdev, "failed to poke device, command %d, err %d\n",
+                        rep_data[0], ret);
+               break;
+       case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
+               if (speed == 1)
+                       wdata->features &= ~0x20;
+               else
+                       wdata->features |= 0x20;
+
+               rep_data[0] = 0x03;
+               rep_data[1] = wdata->features;
+
+               ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+                                       HID_FEATURE_REPORT);
+               if (ret >= 0)
+                       wdata->high_speed = speed;
+               break;
        }
 
-       /*
-        * Note that if the raw queries fail, it's not a hard failure and it
-        * is safe to continue
-        */
-       hid_warn(hdev, "failed to poke device, command %d, err %d\n",
-                rep_data[0], ret);
        return;
 }
 
@@ -196,7 +308,7 @@ static ssize_t wacom_store_speed(struct device *dev,
                return -EINVAL;
 
        if (new_speed == 0 || new_speed == 1) {
-               wacom_poke(hdev, new_speed);
+               wacom_set_features(hdev, new_speed);
                return strnlen(buf, PAGE_SIZE);
        } else
                return -EINVAL;
@@ -310,12 +422,16 @@ static int wacom_gr_parse_report(struct hid_device *hdev,
                input_sync(input);
        }
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
-       /* Store current battery capacity */
+       /* Store current battery capacity and power supply state*/
        rw = (data[7] >> 2 & 0x07);
-       if (rw != wdata->battery_capacity)
-               wdata->battery_capacity = rw;
-#endif
+       if (rw != wdata->power_raw) {
+               wdata->power_raw = rw;
+               wdata->battery_capacity = batcap_gr[rw];
+               if (rw == 7)
+                       wdata->ps_connected = 1;
+               else
+                       wdata->ps_connected = 0;
+       }
        return 1;
 }
 
@@ -369,6 +485,7 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
 {
        __u16 x, y, pressure;
        __u8 distance;
+       __u8 tilt_x, tilt_y;
 
        switch (data[1]) {
        case 0x80: /* Out of proximity report */
@@ -405,6 +522,8 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
                pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5)
                        | (data[1] & 0x01);
                distance = (data[9] >> 2) & 0x3f;
+               tilt_x = ((data[7] << 1) & 0x7e) | (data[8] >> 7);
+               tilt_y = data[8] & 0x7f;
 
                input_report_key(input, BTN_TOUCH, pressure > 1);
 
@@ -415,6 +534,8 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
                input_report_abs(input, ABS_Y, y);
                input_report_abs(input, ABS_PRESSURE, pressure);
                input_report_abs(input, ABS_DISTANCE, distance);
+               input_report_abs(input, ABS_TILT_X, tilt_x);
+               input_report_abs(input, ABS_TILT_Y, tilt_y);
                input_report_abs(input, ABS_MISC, wdata->id);
                input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
                input_report_key(input, wdata->tool, 1);
@@ -455,6 +576,7 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
        struct input_dev *input;
        unsigned char *data = (unsigned char *) raw_data;
        int i;
+       __u8 power_raw;
 
        if (!(hdev->claimed & HID_CLAIMED_INPUT))
                return 0;
@@ -462,13 +584,15 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
        hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
        input = hidinput->input;
 
-       /* Check if this is a tablet report */
-       if (data[0] != 0x03)
-               return 0;
-
        switch (hdev->product) {
        case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
-               return wacom_gr_parse_report(hdev, wdata, input, data);
+               if (data[0] == 0x03) {
+                       return wacom_gr_parse_report(hdev, wdata, input, data);
+               } else {
+                       hid_err(hdev, "Unknown report: %d,%d size:%d\n",
+                                       data[0], data[1], size);
+                       return 0;
+               }
                break;
        case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
                i = 1;
@@ -482,6 +606,13 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
                        wacom_i4_parse_report(hdev, wdata, input, data + i);
                        i += 10;
                        wacom_i4_parse_report(hdev, wdata, input, data + i);
+                       power_raw = data[i+10];
+                       if (power_raw != wdata->power_raw) {
+                               wdata->power_raw = power_raw;
+                               wdata->battery_capacity = batcap_i4[power_raw & 0x07];
+                               wdata->ps_connected = power_raw & 0x08;
+                       }
+
                        break;
                default:
                        hid_err(hdev, "Unknown report: %d,%d size:%d\n",
@@ -546,6 +677,8 @@ static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
                input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0);
                input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0);
                input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0);
+               input_set_abs_params(input, ABS_TILT_X, 0, 127, 0, 0);
+               input_set_abs_params(input, ABS_TILT_Y, 0, 127, 0, 0);
                break;
        }
 
@@ -584,19 +717,19 @@ static int wacom_probe(struct hid_device *hdev,
                hid_warn(hdev,
                         "can't create sysfs speed attribute err: %d\n", ret);
 
-       switch (hdev->product) {
-       case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
-               /* Set Wacom mode 2 with high reporting speed */
-               wacom_poke(hdev, 1);
-               break;
-       case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
+       wdata->features = 0;
+       wacom_set_features(hdev, 1);
+
+       if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) {
                sprintf(hdev->name, "%s", "Wacom Intuos4 WL");
-               wdata->features = 0;
-               wacom_set_features(hdev);
-               break;
+               ret = wacom_initialize_leds(hdev);
+               if (ret) {
+                       hid_warn(hdev,
+                                "can't create led attribute, err: %d\n", ret);
+                       goto destroy_leds;
+               }
        }
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
        wdata->battery.properties = wacom_battery_props;
        wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
        wdata->battery.get_property = wacom_battery_get_property;
@@ -629,16 +762,15 @@ static int wacom_probe(struct hid_device *hdev,
        }
 
        power_supply_powers(&wdata->ac, &hdev->dev);
-#endif
        return 0;
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
 err_ac:
        power_supply_unregister(&wdata->battery);
 err_battery:
        device_remove_file(&hdev->dev, &dev_attr_speed);
        hid_hw_stop(hdev);
-#endif
+destroy_leds:
+       wacom_destroy_leds(hdev);
 err_free:
        kfree(wdata);
        return ret;
@@ -646,16 +778,14 @@ err_free:
 
 static void wacom_remove(struct hid_device *hdev)
 {
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
        struct wacom_data *wdata = hid_get_drvdata(hdev);
-#endif
+
+       wacom_destroy_leds(hdev);
        device_remove_file(&hdev->dev, &dev_attr_speed);
        hid_hw_stop(hdev);
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
        power_supply_unregister(&wdata->battery);
        power_supply_unregister(&wdata->ac);
-#endif
        kfree(hid_get_drvdata(hdev));
 }
 
@@ -693,5 +823,5 @@ static void __exit wacom_exit(void)
 
 module_init(wacom_init);
 module_exit(wacom_exit);
+MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL");
 MODULE_LICENSE("GPL");
-
index 2cfd95c..745e4e9 100644 (file)
@@ -502,28 +502,146 @@ static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {
        0xC0                /*  End Collection                      */
 };
 
-struct waltop_state {
-       u8 pressure0;
-       u8 pressure1;
+/*
+ * See Sirius Battery Free Tablet description, device and HID report descriptors
+ * at
+ * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Sirius_Battery_Free_Tablet
+ */
+
+/* Size of the original report descriptor of Sirius Battery Free Tablet */
+#define SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE     335
+
+/* Fixed Sirius Battery Free Tablet descriptor */
+static __u8 sirius_battery_free_tablet_rdesc_fixed[] = {
+       0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+       0x09, 0x02,         /*  Usage (Pen),                        */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0x85, 0x10,         /*      Report ID (16),                 */
+       0x09, 0x20,         /*      Usage (Stylus),                 */
+       0xA0,               /*      Collection (Physical),          */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x15, 0x01,         /*          Logical Minimum (1),        */
+       0x25, 0x03,         /*          Logical Maximum (3),        */
+       0x75, 0x02,         /*          Report Size (2),            */
+       0x09, 0x42,         /*          Usage (Tip Switch),         */
+       0x09, 0x44,         /*          Usage (Barrel Switch),      */
+       0x09, 0x46,         /*          Usage (Tablet Pick),        */
+       0x80,               /*          Input,                      */
+       0x14,               /*          Logical Minimum (0),        */
+       0x25, 0x01,         /*          Logical Maximum (1),        */
+       0x75, 0x01,         /*          Report Size (1),            */
+       0x09, 0x3C,         /*          Usage (Invert),             */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0x09, 0x32,         /*          Usage (In Range),           */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x95, 0x03,         /*          Report Count (3),           */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0xA4,               /*          Push,                       */
+       0x05, 0x01,         /*          Usage Page (Desktop),       */
+       0x55, 0xFD,         /*          Unit Exponent (-3),         */
+       0x65, 0x13,         /*          Unit (Inch),                */
+       0x34,               /*          Physical Minimum (0),       */
+       0x14,               /*          Logical Minimum (0),        */
+       0x75, 0x10,         /*          Report Size (16),           */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
+       0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
+       0x09, 0x30,         /*          Usage (X),                  */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
+       0x26, 0xE0, 0x2E,   /*          Logical Maximum (12000),    */
+       0x09, 0x31,         /*          Usage (Y),                  */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0xB4,               /*          Pop,                        */
+       0x75, 0x10,         /*          Report Size (16),           */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x14,               /*          Logical Minimum (0),        */
+       0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+       0x09, 0x30,         /*          Usage (Tip Pressure),       */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0xA4,               /*          Push,                       */
+       0x55, 0xFE,         /*          Unit Exponent (-2),         */
+       0x65, 0x12,         /*          Unit (Radians),             */
+       0x35, 0x97,         /*          Physical Minimum (-105),    */
+       0x45, 0x69,         /*          Physical Maximum (105),     */
+       0x15, 0x97,         /*          Logical Minimum (-105),     */
+       0x25, 0x69,         /*          Logical Maximum (105),      */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x02,         /*          Report Count (2),           */
+       0x09, 0x3D,         /*          Usage (X Tilt),             */
+       0x09, 0x3E,         /*          Usage (Y Tilt),             */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0xB4,               /*          Pop,                        */
+       0xC0,               /*      End Collection,                 */
+       0xC0,               /*  End Collection,                     */
+       0x05, 0x01,         /*  Usage Page (Desktop),               */
+       0x09, 0x02,         /*  Usage (Mouse),                      */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0x85, 0x01,         /*      Report ID (1),                  */
+       0x09, 0x01,         /*      Usage (Pointer),                */
+       0xA0,               /*      Collection (Physical),          */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x03,         /*          Report Count (3),           */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0x09, 0x38,         /*          Usage (Wheel),              */
+       0x15, 0xFF,         /*          Logical Minimum (-1),       */
+       0x25, 0x01,         /*          Logical Maximum (1),        */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x81, 0x06,         /*          Input (Variable, Relative), */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x03,         /*          Report Count (3),           */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0xC0,               /*      End Collection,                 */
+       0xC0,               /*  End Collection,                     */
+       0x05, 0x01,         /*  Usage Page (Desktop),               */
+       0x09, 0x06,         /*  Usage (Keyboard),                   */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0x85, 0x0D,         /*      Report ID (13),                 */
+       0x05, 0x07,         /*      Usage Page (Keyboard),          */
+       0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */
+       0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */
+       0x14,               /*      Logical Minimum (0),            */
+       0x25, 0x01,         /*      Logical Maximum (1),            */
+       0x75, 0x01,         /*      Report Size (1),                */
+       0x95, 0x08,         /*      Report Count (8),               */
+       0x81, 0x02,         /*      Input (Variable),               */
+       0x75, 0x08,         /*      Report Size (8),                */
+       0x95, 0x01,         /*      Report Count (1),               */
+       0x81, 0x01,         /*      Input (Constant),               */
+       0x18,               /*      Usage Minimum (None),           */
+       0x29, 0x65,         /*      Usage Maximum (KB Application), */
+       0x14,               /*      Logical Minimum (0),            */
+       0x25, 0x65,         /*      Logical Maximum (101),          */
+       0x75, 0x08,         /*      Report Size (8),                */
+       0x95, 0x05,         /*      Report Count (5),               */
+       0x80,               /*      Input,                          */
+       0xC0,               /*  End Collection,                     */
+       0x05, 0x0C,         /*  Usage Page (Consumer),              */
+       0x09, 0x01,         /*  Usage (Consumer Control),           */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0x85, 0x0C,         /*      Report ID (12),                 */
+       0x09, 0xE9,         /*      Usage (Volume Inc),             */
+       0x09, 0xEA,         /*      Usage (Volume Dec),             */
+       0x14,               /*      Logical Minimum (0),            */
+       0x25, 0x01,         /*      Logical Maximum (1),            */
+       0x75, 0x01,         /*      Report Size (1),                */
+       0x95, 0x02,         /*      Report Count (2),               */
+       0x81, 0x02,         /*      Input (Variable),               */
+       0x75, 0x06,         /*      Report Size (6),                */
+       0x95, 0x01,         /*      Report Count (1),               */
+       0x81, 0x03,         /*      Input (Constant, Variable),     */
+       0x75, 0x10,         /*      Report Size (16),               */
+       0x95, 0x03,         /*      Report Count (3),               */
+       0x81, 0x03,         /*      Input (Constant, Variable),     */
+       0xC0                /*  End Collection                      */
 };
 
 static int waltop_probe(struct hid_device *hdev,
                        const struct hid_device_id *id)
 {
        int ret;
-       struct waltop_state *s;
-
-       s = kzalloc(sizeof(*s), GFP_KERNEL);
-       if (s == NULL) {
-               hid_err(hdev, "can't allocate device state\n");
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       s->pressure0 = 0;
-       s->pressure1 = 0;
-
-       hid_set_drvdata(hdev, s);
 
        ret = hid_parse(hdev);
        if (ret) {
@@ -539,7 +657,6 @@ static int waltop_probe(struct hid_device *hdev,
 
        return 0;
 err:
-       kfree(s);
        return ret;
 }
 
@@ -583,6 +700,12 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                        *rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed);
                }
                break;
+       case USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET:
+               if (*rsize == SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE) {
+                       rdesc = sirius_battery_free_tablet_rdesc_fixed;
+                       *rsize = sizeof(sirius_battery_free_tablet_rdesc_fixed);
+               }
+               break;
        }
        return rdesc;
 }
@@ -590,39 +713,72 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report,
                     u8 *data, int size)
 {
-       /* If this is a pen input report of a tablet with PID 0038 */
-       if (hdev->product == USB_DEVICE_ID_WALTOP_PID_0038 &&
-           report->type == HID_INPUT_REPORT &&
-           report->id == 16 &&
-           size == 8) {
-               struct waltop_state *s = hid_get_drvdata(hdev);
-
+       /* If this is a pen input report */
+       if (report->type == HID_INPUT_REPORT && report->id == 16 && size >= 8) {
                /*
-                * Ignore maximum pressure reported when a barrel button is
-                * pressed.
+                * Ignore reported pressure when a barrel button is pressed,
+                * because it is rarely correct.
                 */
 
                /* If a barrel button is pressed */
                if ((data[1] & 0xF) > 1) {
-                       /* Use the last known pressure */
-                       data[6] = s->pressure0;
-                       data[7] = s->pressure1;
-               } else {
-                       /* Remember reported pressure */
-                       s->pressure0 = data[6];
-                       s->pressure1 = data[7];
+                       /* Report zero pressure */
+                       data[6] = 0;
+                       data[7] = 0;
                }
        }
 
+       /* If this is a pen input report of Sirius Battery Free Tablet */
+       if (hdev->product == USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET &&
+           report->type == HID_INPUT_REPORT &&
+           report->id == 16 &&
+           size == 10) {
+               /*
+                * The tablet reports tilt as roughly sin(a)*21 (18 means 60
+                * degrees).
+                *
+                * This array stores angles as radians * 100, corresponding to
+                * reported values up to 60 degrees, as expected by userspace.
+                */
+               static const s8 tilt_to_radians[] = {
+                       0, 5, 10, 14, 19, 24, 29, 34, 40, 45,
+                       50, 56, 62, 68, 74, 81, 88, 96, 105
+               };
+
+               s8 tilt_x = (s8)data[8];
+               s8 tilt_y = (s8)data[9];
+               s8 sign_x = tilt_x >= 0 ? 1 : -1;
+               s8 sign_y = tilt_y >= 0 ? 1 : -1;
+
+               tilt_x *= sign_x;
+               tilt_y *= sign_y;
+
+               /*
+                * Reverse the Y Tilt direction to match the HID standard and
+                * userspace expectations. See HID Usage Tables v1.12 16.3.2
+                * Tilt Orientation.
+                */
+               sign_y *= -1;
+
+               /*
+                * This effectively clamps reported tilt to 60 degrees - the
+                * range expected by userspace
+                */
+               if (tilt_x > ARRAY_SIZE(tilt_to_radians) - 1)
+                       tilt_x = ARRAY_SIZE(tilt_to_radians) - 1;
+               if (tilt_y > ARRAY_SIZE(tilt_to_radians) - 1)
+                       tilt_y = ARRAY_SIZE(tilt_to_radians) - 1;
+
+               data[8] = tilt_to_radians[tilt_x] * sign_x;
+               data[9] = tilt_to_radians[tilt_y] * sign_y;
+       }
+
        return 0;
 }
 
 static void waltop_remove(struct hid_device *hdev)
 {
-       struct waltop_state *s = hid_get_drvdata(hdev);
-
        hid_hw_stop(hdev);
-       kfree(s);
 }
 
 static const struct hid_device_id waltop_devices[] = {
@@ -638,6 +794,8 @@ static const struct hid_device_id waltop_devices[] = {
                                USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
                                USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
+                        USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, waltop_devices);
index cac3589..84e2fbe 100644 (file)
@@ -769,7 +769,7 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
 
        /*
         * Basic IR data is encoded into 3 bytes. The first two bytes are the
-        * upper 8 bit of the X/Y data, the 3rd byte contains the lower 2 bits
+        * lower 8 bit of the X/Y data, the 3rd byte contains the upper 2 bits
         * of both.
         * If data is packed, then the 3rd byte is put first and slightly
         * reordered. This allows to interleave packed and non-packed data to
@@ -778,17 +778,11 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
         */
 
        if (packed) {
-               x = ir[1] << 2;
-               y = ir[2] << 2;
-
-               x |= ir[0] & 0x3;
-               y |= (ir[0] >> 2) & 0x3;
+               x = ir[1] | ((ir[0] & 0x03) << 8);
+               y = ir[2] | ((ir[0] & 0x0c) << 6);
        } else {
-               x = ir[0] << 2;
-               y = ir[1] << 2;
-
-               x |= (ir[2] >> 4) & 0x3;
-               y |= (ir[2] >> 6) & 0x3;
+               x = ir[0] | ((ir[2] & 0x30) << 4);
+               y = ir[1] | ((ir[2] & 0xc0) << 2);
        }
 
        input_report_abs(wdata->ir, xid, x);
index 782c639..0597ee6 100644 (file)
@@ -88,6 +88,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 
        { USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },