Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[cascardo/linux.git] / drivers / hid / wacom_sys.c
index f0568a7..e8607d0 100644 (file)
@@ -406,6 +406,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
                else if (features->type == WACOM_27QHDT) {
                        return wacom_set_device_mode(hdev, 131, 3, 2);
                }
+               else if (features->type == BAMBOO_PAD) {
+                       return wacom_set_device_mode(hdev, 2, 2, 2);
+               }
        } else if (features->device_type == BTN_TOOL_PEN) {
                if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
                        return wacom_set_device_mode(hdev, 2, 2, 2);
@@ -524,6 +527,11 @@ static int wacom_add_shared_data(struct hid_device *hdev)
 
        wacom_wac->shared = &data->shared;
 
+       if (wacom_wac->features.device_type == BTN_TOOL_FINGER)
+               wacom_wac->shared->touch = hdev;
+       else if (wacom_wac->features.device_type == BTN_TOOL_PEN)
+               wacom_wac->shared->pen = hdev;
+
 out:
        mutex_unlock(&wacom_udev_list_lock);
        return retval;
@@ -541,14 +549,22 @@ static void wacom_release_shared_data(struct kref *kref)
        kfree(data);
 }
 
-static void wacom_remove_shared_data(struct wacom_wac *wacom)
+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;
 
-       if (wacom->shared) {
-               data = container_of(wacom->shared, struct wacom_hdev_data, shared);
                kref_put(&data->kref, wacom_release_shared_data);
-               wacom->shared = NULL;
+               wacom_wac->shared = NULL;
        }
 }
 
@@ -929,6 +945,7 @@ static void wacom_destroy_leds(struct wacom *wacom)
 }
 
 static enum power_supply_property wacom_battery_props[] = {
+       POWER_SUPPLY_PROP_PRESENT,
        POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_SCOPE,
        POWER_SUPPLY_PROP_CAPACITY
@@ -944,10 +961,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 *wacom = power_supply_get_drvdata(psy);
        int ret = 0;
 
        switch (psp) {
+               case POWER_SUPPLY_PROP_PRESENT:
+                       val->intval = wacom->wacom_wac.bat_connected;
+                       break;
                case POWER_SUPPLY_PROP_SCOPE:
                        val->intval = POWER_SUPPLY_SCOPE_DEVICE;
                        break;
@@ -961,6 +981,8 @@ static int wacom_battery_get_property(struct power_supply *psy,
                        else if (wacom->wacom_wac.battery_capacity == 100 &&
                                    wacom->wacom_wac.ps_connected)
                                val->intval = POWER_SUPPLY_STATUS_FULL;
+                       else if (wacom->wacom_wac.ps_connected)
+                               val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
                        else
                                val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
                        break;
@@ -976,7 +998,7 @@ static int wacom_ac_get_property(struct power_supply *psy,
                                enum power_supply_property psp,
                                union power_supply_propval *val)
 {
-       struct wacom *wacom = container_of(psy, struct wacom, ac);
+       struct wacom *wacom = power_supply_get_drvdata(psy);
        int ret = 0;
 
        switch (psp) {
@@ -998,42 +1020,46 @@ 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);
-       int error;
+       struct power_supply_config psy_cfg = { .drv_data = wacom, };
        unsigned long n;
 
        if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) {
+               struct power_supply_desc *bat_desc = &wacom->battery_desc;
+               struct power_supply_desc *ac_desc = &wacom->ac_desc;
                n = atomic_inc_return(&battery_no) - 1;
 
-               wacom->battery.properties = wacom_battery_props;
-               wacom->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
-               wacom->battery.get_property = wacom_battery_get_property;
+               bat_desc->properties = wacom_battery_props;
+               bat_desc->num_properties = ARRAY_SIZE(wacom_battery_props);
+               bat_desc->get_property = wacom_battery_get_property;
                sprintf(wacom->wacom_wac.bat_name, "wacom_battery_%ld", n);
-               wacom->battery.name = wacom->wacom_wac.bat_name;
-               wacom->battery.type = POWER_SUPPLY_TYPE_BATTERY;
-               wacom->battery.use_for_apm = 0;
+               bat_desc->name = wacom->wacom_wac.bat_name;
+               bat_desc->type = POWER_SUPPLY_TYPE_BATTERY;
+               bat_desc->use_for_apm = 0;
 
-               wacom->ac.properties = wacom_ac_props;
-               wacom->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
-               wacom->ac.get_property = wacom_ac_get_property;
+               ac_desc->properties = wacom_ac_props;
+               ac_desc->num_properties = ARRAY_SIZE(wacom_ac_props);
+               ac_desc->get_property = wacom_ac_get_property;
                sprintf(wacom->wacom_wac.ac_name, "wacom_ac_%ld", n);
-               wacom->ac.name = wacom->wacom_wac.ac_name;
-               wacom->ac.type = POWER_SUPPLY_TYPE_MAINS;
-               wacom->ac.use_for_apm = 0;
-
-               error = power_supply_register(&wacom->hdev->dev,
-                                             &wacom->battery);
-               if (error)
-                       return error;
-
-               power_supply_powers(&wacom->battery, &wacom->hdev->dev);
-
-               error = power_supply_register(&wacom->hdev->dev, &wacom->ac);
-               if (error) {
-                       power_supply_unregister(&wacom->battery);
-                       return error;
+               ac_desc->name = wacom->wacom_wac.ac_name;
+               ac_desc->type = POWER_SUPPLY_TYPE_MAINS;
+               ac_desc->use_for_apm = 0;
+
+               wacom->battery = power_supply_register(&wacom->hdev->dev,
+                                             &wacom->battery_desc, &psy_cfg);
+               if (IS_ERR(wacom->battery))
+                       return PTR_ERR(wacom->battery);
+
+               power_supply_powers(wacom->battery, &wacom->hdev->dev);
+
+               wacom->ac = power_supply_register(&wacom->hdev->dev,
+                                                 &wacom->ac_desc,
+                                                 &psy_cfg);
+               if (IS_ERR(wacom->ac)) {
+                       power_supply_unregister(wacom->battery);
+                       return PTR_ERR(wacom->ac);
                }
 
-               power_supply_powers(&wacom->ac, &wacom->hdev->dev);
+               power_supply_powers(wacom->ac, &wacom->hdev->dev);
        }
 
        return 0;
@@ -1041,12 +1067,11 @@ static int wacom_initialize_battery(struct wacom *wacom)
 
 static void wacom_destroy_battery(struct wacom *wacom)
 {
-       if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
-            wacom->battery.dev) {
-               power_supply_unregister(&wacom->battery);
-               wacom->battery.dev = NULL;
-               power_supply_unregister(&wacom->ac);
-               wacom->ac.dev = NULL;
+       if (wacom->battery) {
+               power_supply_unregister(wacom->battery);
+               wacom->battery = NULL;
+               power_supply_unregister(wacom->ac);
+               wacom->ac = NULL;
        }
 }
 
@@ -1313,6 +1338,20 @@ fail:
        return;
 }
 
+void wacom_battery_work(struct work_struct *work)
+{
+       struct wacom *wacom = container_of(work, struct wacom, work);
+
+       if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
+            !wacom->battery) {
+               wacom_initialize_battery(wacom);
+       }
+       else if (!(wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
+                wacom->battery) {
+               wacom_destroy_battery(wacom);
+       }
+}
+
 /*
  * Not all devices report physical dimensions from HID.
  * Compute the default from hardcoded logical dimension
@@ -1373,6 +1412,9 @@ static int wacom_probe(struct hid_device *hdev,
 
        hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
 
+       /* hid-core sets this quirk for the boot interface */
+       hdev->quirks &= ~HID_QUIRK_NOGET;
+
        wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
        if (!wacom)
                return -ENOMEM;
@@ -1412,6 +1454,21 @@ static int wacom_probe(struct hid_device *hdev,
                        goto fail_allocate_inputs;
        }
 
+       /*
+        * Bamboo Pad has a generic hid handling for the Pen, and we switch it
+        * into debug mode for the touch part.
+        * We ignore the other interfaces.
+        */
+       if (features->type == BAMBOO_PAD) {
+               if (features->pktlen == WACOM_PKGLEN_PENABLED) {
+                       features->type = HID_GENERIC;
+               } else if ((features->pktlen != WACOM_PKGLEN_BPAD_TOUCH) &&
+                          (features->pktlen != WACOM_PKGLEN_BPAD_TOUCH_USB)) {
+                       error = -ENODEV;
+                       goto fail_shared_data;
+               }
+       }
+
        /* set the default size in case we do not get them from hid */
        wacom_set_default_phy(features);
 
@@ -1446,6 +1503,12 @@ static int wacom_probe(struct hid_device *hdev,
                features->y_max = 4096;
        }
 
+       /*
+        * Same thing for Bamboo PAD
+        */
+       if (features->type == BAMBOO_PAD)
+               features->device_type = BTN_TOOL_FINGER;
+
        if (hdev->bus == BUS_BLUETOOTH)
                features->quirks |= WACOM_QUIRK_BATTERY;
 
@@ -1462,19 +1525,17 @@ static int wacom_probe(struct hid_device *hdev,
        snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name),
                "%s Pad", features->name);
 
-       if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
-               /* Append the device type to the name */
-               if (features->device_type != BTN_TOOL_FINGER)
-                       strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
-               else if (features->touch_max)
-                       strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX);
-               else
-                       strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
+       /* Append the device type to the name */
+       if (features->device_type != BTN_TOOL_FINGER)
+               strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
+       else if (features->touch_max)
+               strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX);
+       else
+               strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
 
-               error = wacom_add_shared_data(hdev);
-               if (error)
-                       goto fail_shared_data;
-       }
+       error = wacom_add_shared_data(hdev);
+       if (error)
+               goto fail_shared_data;
 
        if (!(features->quirks & WACOM_QUIRK_MONITOR) &&
             (features->quirks & WACOM_QUIRK_BATTERY)) {
@@ -1527,7 +1588,7 @@ fail_register_inputs:
        wacom_clean_inputs(wacom);
        wacom_destroy_battery(wacom);
 fail_battery:
-       wacom_remove_shared_data(wacom_wac);
+       wacom_remove_shared_data(wacom);
 fail_shared_data:
        wacom_clean_inputs(wacom);
 fail_allocate_inputs:
@@ -1550,7 +1611,7 @@ static void wacom_remove(struct hid_device *hdev)
        if (hdev->bus == BUS_BLUETOOTH)
                device_remove_file(&hdev->dev, &dev_attr_speed);
        wacom_destroy_battery(wacom);
-       wacom_remove_shared_data(&wacom->wacom_wac);
+       wacom_remove_shared_data(wacom);
 
        hid_set_drvdata(hdev, NULL);
        kfree(wacom);