Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b30ff4c2 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "UPSTREAM: HID: input: map digitizer battery usage"

parents e780a105 e2a50d2c
Loading
Loading
Loading
Loading
+135 −62
Original line number Diff line number Diff line
@@ -303,6 +303,7 @@ static enum power_supply_property hidinput_battery_props[] = {

#define HID_BATTERY_QUIRK_PERCENT	(1 << 0) /* always reports percent */
#define HID_BATTERY_QUIRK_FEATURE	(1 << 1) /* ask for feature report */
#define HID_BATTERY_QUIRK_IGNORE	(1 << 2) /* completely ignore the battery */

static const struct hid_device_id hid_battery_quirks[] = {
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
@@ -320,6 +321,9 @@ static const struct hid_device_id hid_battery_quirks[] = {
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
		USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
	  HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM,
		USB_DEVICE_ID_ELECOM_BM084),
	  HID_BATTERY_QUIRK_IGNORE },
	{}
};

@@ -335,13 +339,45 @@ static unsigned find_battery_quirk(struct hid_device *hdev)
	return quirks;
}

static int hidinput_scale_battery_capacity(struct hid_device *dev,
					   int value)
{
	if (dev->battery_min < dev->battery_max &&
	    value >= dev->battery_min && value <= dev->battery_max)
		value = ((value - dev->battery_min) * 100) /
			(dev->battery_max - dev->battery_min);

	return value;
}

static int hidinput_query_battery_capacity(struct hid_device *dev)
{
	u8 *buf;
	int ret;

	buf = kmalloc(2, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2,
				 dev->battery_report_type, HID_REQ_GET_REPORT);
	if (ret != 2) {
		kfree(buf);
		return -ENODATA;
	}

	ret = hidinput_scale_battery_capacity(dev, buf[1]);
	kfree(buf);
	return ret;
}

static int hidinput_get_battery_property(struct power_supply *psy,
					 enum power_supply_property prop,
					 union power_supply_propval *val)
{
	struct hid_device *dev = power_supply_get_drvdata(psy);
	int value;
	int ret = 0;
	__u8 *buf;

	switch (prop) {
	case POWER_SUPPLY_PROP_PRESENT:
@@ -350,29 +386,15 @@ static int hidinput_get_battery_property(struct power_supply *psy,
		break;

	case POWER_SUPPLY_PROP_CAPACITY:

		buf = kmalloc(2 * sizeof(__u8), GFP_KERNEL);
		if (!buf) {
			ret = -ENOMEM;
			break;
		}
		ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2,
					 dev->battery_report_type,
					 HID_REQ_GET_REPORT);

		if (ret != 2) {
			ret = -ENODATA;
			kfree(buf);
			break;
		if (dev->battery_report_type == HID_FEATURE_REPORT) {
			value = hidinput_query_battery_capacity(dev);
			if (value < 0)
				return value;
		} else  {
			value = dev->battery_capacity;
		}
		ret = 0;

		if (dev->battery_min < dev->battery_max &&
		    buf[1] >= dev->battery_min &&
		    buf[1] <= dev->battery_max)
			val->intval = (100 * (buf[1] - dev->battery_min)) /
				(dev->battery_max - dev->battery_min);
		kfree(buf);
		val->intval = value;
		break;

	case POWER_SUPPLY_PROP_MODEL_NAME:
@@ -380,6 +402,21 @@ static int hidinput_get_battery_property(struct power_supply *psy,
		break;

	case POWER_SUPPLY_PROP_STATUS:
		if (!dev->battery_reported &&
		    dev->battery_report_type == HID_FEATURE_REPORT) {
			value = hidinput_query_battery_capacity(dev);
			if (value < 0)
				return value;

			dev->battery_capacity = value;
			dev->battery_reported = true;
		}

		if (!dev->battery_reported)
			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
		else if (dev->battery_capacity == 100)
			val->intval = POWER_SUPPLY_STATUS_FULL;
		else
			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
		break;

@@ -395,27 +432,33 @@ static int hidinput_get_battery_property(struct power_supply *psy,
	return ret;
}

static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field)
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field)
{
	struct power_supply_desc *psy_desc = NULL;
	struct power_supply_desc *psy_desc;
	struct power_supply_config psy_cfg = { .drv_data = dev, };
	unsigned quirks;
	s32 min, max;
	int error;

	if (field->usage->hid != HID_DC_BATTERYSTRENGTH)
		return false;	/* no match */
	if (dev->battery)
		return 0;	/* already initialized? */

	if (dev->battery != NULL)
		goto out;	/* already initialized? */
	quirks = find_battery_quirk(dev);

	hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",
		dev->bus, dev->vendor, dev->product, dev->version, quirks);

	if (quirks & HID_BATTERY_QUIRK_IGNORE)
		return 0;

	psy_desc = kzalloc(sizeof(*psy_desc), GFP_KERNEL);
	if (psy_desc == NULL)
		goto out;
	if (!psy_desc)
		return -ENOMEM;

	psy_desc->name = kasprintf(GFP_KERNEL, "hid-%s-battery", dev->uniq);
	if (psy_desc->name == NULL) {
		kfree(psy_desc);
		goto out;
	if (!psy_desc->name) {
		error = -ENOMEM;
		goto err_free_mem;
	}

	psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
@@ -424,11 +467,6 @@ static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
	psy_desc->use_for_apm = 0;
	psy_desc->get_property = hidinput_get_battery_property;

	quirks = find_battery_quirk(dev);

	hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",
		dev->bus, dev->vendor, dev->product, dev->version, quirks);

	min = field->logical_minimum;
	max = field->logical_maximum;

@@ -447,17 +485,20 @@ static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,

	dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);
	if (IS_ERR(dev->battery)) {
		hid_warn(dev, "can't register power supply: %ld\n",
				PTR_ERR(dev->battery));
		error = PTR_ERR(dev->battery);
		hid_warn(dev, "can't register power supply: %d\n", error);
		goto err_free_name;
	}

	power_supply_powers(dev->battery, &dev->dev);
	return 0;

err_free_name:
	kfree(psy_desc->name);
err_free_mem:
	kfree(psy_desc);
	dev->battery = NULL;
	} else {
		power_supply_powers(dev->battery, &dev->dev);
	}

out:
	return true;
	return error;
}

static void hidinput_cleanup_battery(struct hid_device *dev)
@@ -473,16 +514,33 @@ static void hidinput_cleanup_battery(struct hid_device *dev)
	kfree(psy_desc);
	dev->battery = NULL;
}

static void hidinput_update_battery(struct hid_device *dev, int value)
{
	if (!dev->battery)
		return;

	if (value == 0 || value < dev->battery_min || value > dev->battery_max)
		return;

	dev->battery_capacity = hidinput_scale_battery_capacity(dev, value);
	dev->battery_reported = true;
	power_supply_changed(dev->battery);
}
#else  /* !CONFIG_HID_BATTERY_STRENGTH */
static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
				  struct hid_field *field)
{
	return false;
	return 0;
}

static void hidinput_cleanup_battery(struct hid_device *dev)
{
}

static void hidinput_update_battery(struct hid_device *dev, int value)
{
}
#endif	/* CONFIG_HID_BATTERY_STRENGTH */

static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
@@ -684,6 +742,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
			}
			break;

		case 0x3b: /* Battery Strength */
			hidinput_setup_battery(device, HID_INPUT_REPORT, field);
			usage->type = EV_PWR;
			goto ignore;

		case 0x3c: /* Invert */
			map_key_clear(BTN_TOOL_RUBBER);
			break;
@@ -924,11 +987,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
		break;

	case HID_UP_GENDEVCTRLS:
		if (hidinput_setup_battery(device, HID_INPUT_REPORT, field))
		switch (usage->hid) {
		case HID_DC_BATTERYSTRENGTH:
			hidinput_setup_battery(device, HID_INPUT_REPORT, field);
			usage->type = EV_PWR;
			goto ignore;
		else
		}
		goto unknown;
		break;

	case HID_UP_HPVENDOR:	/* Reported on a Dutch layout HP5308 */
		set_bit(EV_REP, input->evbit);
@@ -1006,7 +1071,6 @@ mapped:
	if (usage->code > max)
		goto ignore;


	if (usage->type == EV_ABS) {

		int a = field->logical_minimum;
@@ -1065,14 +1129,19 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
	struct input_dev *input;
	unsigned *quirks = &hid->quirks;

	if (!field->hidinput)
	if (!usage->type)
		return;

	input = field->hidinput->input;
	if (usage->type == EV_PWR) {
		hidinput_update_battery(hid, value);
		return;
	}

	if (!usage->type)
	if (!field->hidinput)
		return;

	input = field->hidinput->input;

	if (usage->hat_min < usage->hat_max || usage->hat_dir) {
		int hat_dir = usage->hat_dir;
		if (!hat_dir)
@@ -1349,6 +1418,7 @@ static void report_features(struct hid_device *hid)
	struct hid_driver *drv = hid->driver;
	struct hid_report_enum *rep_enum;
	struct hid_report *rep;
	struct hid_usage *usage;
	int i, j;

	rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
@@ -1359,12 +1429,15 @@ static void report_features(struct hid_device *hid)
				continue;

			for (j = 0; j < rep->field[i]->maxusage; j++) {
				usage = &rep->field[i]->usage[j];

				/* Verify if Battery Strength feature is available */
				hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]);
				if (usage->hid == HID_DC_BATTERYSTRENGTH)
					hidinput_setup_battery(hid, HID_FEATURE_REPORT,
							       rep->field[i]);

				if (drv->feature_mapping)
					drv->feature_mapping(hid, rep->field[i],
							     rep->field[i]->usage + j);
					drv->feature_mapping(hid, rep->field[i], usage);
			}
		}
}
+2 −0
Original line number Diff line number Diff line
@@ -529,10 +529,12 @@ struct hid_device { /* device report descriptor */
	 * battery is non-NULL.
	 */
	struct power_supply *battery;
	__s32 battery_capacity;
	__s32 battery_min;
	__s32 battery_max;
	__s32 battery_report_type;
	__s32 battery_report_id;
	bool battery_reported;
#endif

	unsigned int status;						/* see STAT flags above */