From: Jeremy Fitzhardinge <jeremy@goop.org>
To: Daniel Nicoletti <dantti12@gmail.com>
Cc: linux-input@vger.kernel.org, Jiri Kosina <jkosina@suse.cz>,
vojtech@ucw.cz, Przemo Firszt <przemo@firszt.eu>,
Richard Hughes <richard@hughsie.com>
Subject: Re: [PATCH RFC] hid-input: add support for HID devices reporting Battery Strength
Date: Fri, 02 Dec 2011 22:09:50 -0800 [thread overview]
Message-ID: <4ED9BD2E.1010105@goop.org> (raw)
In-Reply-To: <CACo8zOcvKwr0wDkytvJfqyx4kV0ceYyCt+qnDqiSgxNywpzeHg@mail.gmail.com>
On 12/02/2011 10:29 AM, Daniel Nicoletti wrote:
> Thanks for the reply,
>
> 2011/12/2 Jeremy Fitzhardinge <jeremy@goop.org>:
>>> If I understood correctly when talking to Jeremy he said his device
>>> never actually
>>> reported the status as an input event (sorry if I didn't understand it
>>> correctly),
>> No, it does. When the mouse first connects it reports the battery level
>> as an Input event. Without my patch, X sees the battery level as a
>> strange little absolute axis on the mouse, which it ignores.
>>
>> I don't know if the mouse also reports the battery later on
>> spontaneously; I haven't observed it, so I suspect you may be right that
>> you have to poll it to get further updates.
> Right, my devices don't send any data if not asked, even if the battery change
> it's status (what did happen because I've put some old batteries.
> So in this case we will need to keep your code on the raw event and probably
> check that into the get_properties part.
>
>>> and
>>> after reading HID specs I believe it's really because it was meant to be probed,
>>> I have an Apple Keyboard and Magic Trackpad both bluetooth batteries operated,
>>> so using PacketLogger I saw that Mac OSX always ask the battery status using
>>> the so called GetFeature.
>> Could you cite a specific reference? I don't see any references to
>> "GetFeature" in HID spec I have. The closest I see is
>> "Get_Report(INPUT/OUTPUT/FEATURE)", which specifically says "This
>> request is not intended to be used for polling the device state on a
>> regular basis". Though I'm not at all surprised if device manufacturers
>> ignore this, or that it is contradictory with some other part of the spec.
> Sure, HUT1_12v2.pdf section 4.8 Feature Notifications, at the end you
> will see GetReport(Feature) (sorry it was GetReport() not GetFeature()).
> Also when I run my code hcidump shows this, which means it knows what
> a GetReport is: (and Mac OSX PackatLogger.app too)
> HIDP: Get report: Feature report
>
>>> What my patch does is basically:
>>> - store the report id that matches the battery_strength
>>> - setup the battery if 0x6.0x20 is found, even if that is reported as a feature
>>> (as it was meant to be but only the MagicTrackpad does)
>>> - when upower or someone access /sys/class/power_supply/hid-*/capacity it
>>> will probe the device and return it's status.
>> How often does usermode read this file? Does it/can it select on the
>> file to wait for changes.
>>
>> Given that battery level shouldn't change that quickly, I wonder if
>> having a timer poll the device every minute or something of that order
>> might be useful?
> Yes, this is concerning but imo the /sys.../capacity file should return
> the current value, and to do that it need to probe, it the probe timer
> is too often then upower needs fixing, we have done our part into the
> kernel...
>
>>> It works great for both devices, but I have two concerns:
>>> - the report_features function has a duplicated code
>> Yes, but that's easy to fix.
>>
>>> - it would be nice if it was possible for specific drivers to provide their own
>>> probe as there might be some strange devices... (but maybe it's
>>> already possible)
>> I'd wait until there's a device which can't be handled by this mechanism
>> before trying to generalize it. Unless we can unify the wacom driver,
>> but that seems to be in its own little world.
> sounds like a better idea.
>
>>> I've talked to the upower dev and he fixed it to be able to show the
>>> right percentage.
>> Cool, but I have some concerns about that (see below).
>>
>>> Here how the uevent file (in /sys/class/power_supply/hid-*/) looks like:
>>> POWER_SUPPLY_NAME=hid-00:22:41:D9:18:E7-battery
>>> POWER_SUPPLY_PRESENT=1
>>> POWER_SUPPLY_ONLINE=1
>>> POWER_SUPPLY_CAPACITY=66
>>> POWER_SUPPLY_MODEL_NAME=MacAdmin’s keyboard
>>> POWER_SUPPLY_STATUS=Discharging
>>>
>>> POWER_SUPPLY_NAME=hid-70:CD:60:F5:FF:3F-battery
>>> POWER_SUPPLY_PRESENT=1
>>> POWER_SUPPLY_ONLINE=1
>>> POWER_SUPPLY_CAPACITY=62
>>> POWER_SUPPLY_MODEL_NAME=nexx’s Trackpad
>>> POWER_SUPPLY_STATUS=Discharging
>>>
>>> and the patch (note that this is my first kernel patch so sorry if
>>> formatting is not ok, should I attach it?):
>>> diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
>>> index b9b8c75..8fac47c 100644
>>> --- a/drivers/hid/hid-input.c
>>> +++ b/drivers/hid/hid-input.c
>>> @@ -277,6 +277,7 @@ static enum power_supply_property
>>> hidinput_battery_props[] = {
>>> POWER_SUPPLY_PROP_ONLINE,
>>> POWER_SUPPLY_PROP_CAPACITY,
>>> POWER_SUPPLY_PROP_MODEL_NAME,
>>> + POWER_SUPPLY_PROP_STATUS
>>> };
>>>
>>> static int hidinput_get_battery_property(struct power_supply *psy,
>>> @@ -285,6 +286,9 @@ static int hidinput_get_battery_property(struct
>>> power_supply *psy,
>>> {
>>> struct hid_device *dev = container_of(psy, struct hid_device, battery);
>>> int ret = 0;
>>> + int ret_rep;
>>> + __u8 *buf = NULL;
>>> + unsigned char report_number = dev->battery_report_id;
>>>
>>> switch (prop) {
>>> case POWER_SUPPLY_PROP_PRESENT:
>>> @@ -293,28 +297,45 @@ static int hidinput_get_battery_property(struct
>>> power_supply *psy,
>>> break;
>>>
>>> case POWER_SUPPLY_PROP_CAPACITY:
>>> - if (dev->battery_min < dev->battery_max &&
>>> - dev->battery_val >= dev->battery_min &&
>>> - dev->battery_val <= dev->battery_max)
>>> - val->intval = (100 * (dev->battery_val - dev->battery_min)) /
>>> - (dev->battery_max - dev->battery_min);
>>> - else
>>> + buf = kmalloc(2 * sizeof(__u8), GFP_KERNEL);
>> Why allocate a two byte buffer? Why not just put it on the stack? How
>> do you know that's the right size?
> Sorry I'm not kernel expert I just saw some other code working like this..
> I know the size because the first byte is the report_id (in my case 0x47 or 71),
> but the following bytes are reported by Report Size(8) and Report Count(1)
> as the raw function calculates the count by the buf size.
> (note that I might be wrong, but for my devices it works like this).
>
>>> + if (!buf) {
>>> + ret = -ENOMEM;
>>> + break;
>>> + }
>>> +
>>> + memset(buf, 0, sizeof(buf));
>>> + ret_rep = dev->hid_get_raw_report(dev, report_number, buf,
>>> sizeof(buf), HID_FEATURE_REPORT);
>>> + if (ret_rep != 2) {
>>> ret = -EINVAL;
>>> + break;
>>> + }
>>> +
>>> + /* store the returned value */
>>> + /* I'm not calculating this using the logical_minimum and maximum */
>>> + /* because my device returns 0-100 even though the min and max are 0-255 */
>>> + val->intval = buf[1];
>> That's definitely not the case for my mouse. I'm not sure what the
>> range actually is, but I've seen values reported > 100 with fresh
>> alkaline batteries. Initially I also thought it was using a 0-100 range
>> despite the min/max, and I added a per-device quirk mechanism - but
>> since my device didn't need it, I did't include it in the patch
>> posting. I'd reinstate it if there are devices that report 0-100.
> Sure, then we need some quirks... As even the keyboar that reports the max as
> 255 actually returns in 0-100 interval..
>
>>> break;
>>>
>>> case POWER_SUPPLY_PROP_MODEL_NAME:
>>> val->strval = dev->name;
>>> break;
>>>
>>> + case POWER_SUPPLY_PROP_STATUS:
>>> + val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
>>> + break;
>>> +
>>> default:
>>> ret = -EINVAL;
>>> break;
>>> }
>>>
>>> + if (buf) {
>>> + kfree(buf);
>>> + }
>>> return ret;
>>> }
>>>
>>> -static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max)
>>> +static void hidinput_setup_battery(struct hid_device *dev, unsigned
>>> id, s32 min, s32 max)
>>> {
>>> struct power_supply *battery = &dev->battery;
>>> int ret;
>>> @@ -326,7 +347,7 @@ static void hidinput_setup_battery(struct
>>> hid_device *dev, s32 min, s32 max)
>>> if (battery->name == NULL)
>>> return;
>>>
>>> - battery->type = POWER_SUPPLY_TYPE_BATTERY;
>>> + battery->type = POWER_SUPPLY_TYPE_USB;
>> What's the purpose of this? Is it to make upower behave in a
>> different/better way? My reading is that this means that it's powered
>> by USB ("Standard Downstream Port"). A bluetooth device doesn't have
>> any USB involved at all (except if the BT adapter itself is USB, which
>> is moot).
>>
>> If upower is getting confused thinking that a "battery" is necessarily a
>> laptop battery, then I think it needs to be fixed to pay closer
>> attention to the device tree topology.
>>
>> (looks up upower) Ah, I see.
>>
>> The changes in the current upower.git look very suspect to me, if
>> nothing else because of the hard-coded "magicmouse" and "wacom", and the
>> use of POWER_SUPPLY_TYPE_USB. Can upower not look to see if there's a
>> power-supply hanging off a HID device and report that as peripheral power?
> I have to talk to Richard (ah you CC him in this email..), but tbh I think the
> change in upower should just look at what properties the battery is
> capable of providing,
> I changed it to USB since IIRC using it as BATTERY made it think it was a power
> supply of the computer..
Yes, but I think that's either a bug in upower or an ambiguity in what
power_supply means (or perhaps, what a power_supply is powering) -
either way, that's something deserving of further discussion.
But either way, the mouse definitely isn't being powered by USB - the
whole point is that it's battery powered. The kernel shouldn't tell
lies to work around other problems.
>>> - if (!drv->feature_mapping)
>>> - return;
>>> -
>>> rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
>>> list_for_each_entry(rep, &rep_enum->report_list, list)
>>> for (i = 0; i < rep->maxfield; i++)
>>> - for (j = 0; j < rep->field[i]->maxusage; j++)
>>> - drv->feature_mapping(hid, rep->field[i],
>>> - rep->field[i]->usage + j);
>>> + for (j = 0; j < rep->field[i]->maxusage; j++) {
>>> + /* Verify if Battery Strength feature is available */
>>> + if (((rep->field[i]->usage + j)->hid & HID_USAGE_PAGE) ==
>>> HID_UP_GENDEVCTRLS &&
>>> + ((rep->field[i]->usage + j)->hid & HID_USAGE) == 0x20) {
>>> + hidinput_setup_battery(hid,
>>> + rep->id,
>>> + rep->field[i]->logical_minimum,
>>> + rep->field[i]->logical_maximum);
>>> + }
>>> +
>>> + if (drv->feature_mapping)
>>> + drv->feature_mapping(hid, rep->field[i],
>>> + rep->field[i]->usage + j);
>>> + }
>> I'd be inclined to split all this out into a separate function, so that
>> you can make it common with the code on the input path.
> Yes, might be better I couldn't think of a nice way to share this part..
> But in the end does my Patch probes your device? :D
Yes, it does! I changed it to ask for the appropriate report
(INPUT/FEATURE) depending on how it appeared in the original descriptor,
and made a few other cleanups, which I'll post shortly.
J
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2011-12-03 6:10 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-11-19 6:52 Supporting Battery Strength from my Bluetooth Mouse Jeremy Fitzhardinge
2011-11-19 11:18 ` Jiri Kosina
2011-11-19 21:34 ` Jeremy Fitzhardinge
2011-11-20 10:26 ` Jiri Kosina
2011-11-21 16:38 ` Jeremy Fitzhardinge
2011-11-21 17:36 ` Dmitry Torokhov
2011-11-21 17:49 ` Jeremy Fitzhardinge
2011-11-21 23:29 ` Jiri Kosina
2011-11-21 23:34 ` Jeremy Fitzhardinge
2011-11-22 0:03 ` Jiri Kosina
2011-11-23 8:49 ` [PATCH RFC] hid-input: add support for HID devices reporting Battery Strength Jeremy Fitzhardinge
2011-11-23 16:36 ` Chase Douglas
2011-11-23 21:07 ` Jeremy Fitzhardinge
2011-11-23 21:52 ` Przemo Firszt
2011-11-28 21:33 ` Jiri Kosina
2011-12-02 5:52 ` Daniel Nicoletti
2011-12-02 17:44 ` Jeremy Fitzhardinge
2011-12-02 18:29 ` Daniel Nicoletti
2011-12-03 6:09 ` Jeremy Fitzhardinge [this message]
2011-12-03 6:13 ` [GIT PULL RFC] directly poll battery strength when reading power_supply Jeremy Fitzhardinge
2011-12-06 9:17 ` Jiri Kosina
2011-12-08 1:56 ` Jeremy Fitzhardinge
2012-05-19 4:10 ` Daniel Nicoletti
2011-12-06 9:56 ` Richard Hughes
2011-12-06 17:10 ` Jeremy Fitzhardinge
2011-12-07 12:51 ` Richard Hughes
2011-12-07 17:25 ` Jeremy Fitzhardinge
2011-12-07 17:29 ` Richard Hughes
2011-12-07 17:36 ` Jeremy Fitzhardinge
2011-12-07 17:41 ` Richard Hughes
2011-12-08 1:41 ` [GIT PULL] power_supply: add power supply scope Jeremy Fitzhardinge
2011-12-08 1:41 ` Jeremy Fitzhardinge
2011-12-08 10:02 ` Anton Vorontsov
2011-12-08 10:05 ` Richard Hughes
2011-12-08 10:42 ` Anton Vorontsov
2011-12-08 10:41 ` Anton Vorontsov
2011-12-08 16:53 ` Jeremy Fitzhardinge
2011-12-08 23:36 ` Anton Vorontsov
2011-12-09 8:18 ` Jeremy Fitzhardinge
2011-12-09 9:59 ` Anton Vorontsov
2011-12-09 16:58 ` Jeremy Fitzhardinge
2011-12-09 10:17 ` Anton Vorontsov
2011-12-09 17:49 ` Jeremy Fitzhardinge
2011-12-09 20:00 ` Daniel Nicoletti
2011-12-09 20:36 ` Jeremy Fitzhardinge
2011-12-02 17:58 ` [PATCH RFC] hid-input: add support for HID devices reporting Battery Strength Jeremy Fitzhardinge
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4ED9BD2E.1010105@goop.org \
--to=jeremy@goop.org \
--cc=dantti12@gmail.com \
--cc=jkosina@suse.cz \
--cc=linux-input@vger.kernel.org \
--cc=przemo@firszt.eu \
--cc=richard@hughsie.com \
--cc=vojtech@ucw.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.