Re: Async upd(4) - patch 7/7

2015-05-11 Thread Martin Pieuchot

On 2015-05-07 04:19, David Higgs wrote:

On Apr 30, 2015, at 7:09 AM, Martin Pieuchot  wrote:
[...]


Your tweaks were good, so I tweaked it further:
- When submit fails, invalidate affected sensors as described above.
- When invalidating sensors, do it recursively.
- When battery is not present, invalidate children but not 
BatteryPresent.


Let me know what you think.


Committed thanks!.

I'm looking forward to see more supported sensors added to upd(4) :)

M.



Re: Async upd(4) - patch 7/7

2015-05-06 Thread David Higgs

> On Apr 30, 2015, at 7:09 AM, Martin Pieuchot  wrote:
> 
> On 24/04/15(Fri) 20:48, David Higgs wrote:
>> This is the final patch in the series.
>> 
>> Utilize the pending flags and report callback for their intended purpose - 
>> to process async behavior.
>> 
>> Apply splusb() to ensure report callbacks can't fire before their data 
>> structures have been properly updated.  This only needs to happen in 
>> upd_refresh(); all other calls to upd_request_children() are from a report 
>> callback.
> 
> This is some good work.  I don't think your patch #6 makes sense without
> #7, so I merged them.
> 
> I don't think you need a "pending" flags for the sensors, since what you
> are querying are the reports.  You basically do not want to send to
> requests for the same report at once.
> 

I still disagree.  However, the fix for this isn’t difficult and can be handled 
in a future diff.

> I'd also take the simpler approach of not deactivating all sensors if
> you fail to *submit* a transfer.  When such thing happens it's either
> because the device/bus is going away or because we cannot allocate
> memory.
> 
Even in these situations, invalidating all affected sensors seems an easy and 
consistent thing to do.

> I tweaked your diff below, included some comments and your copyright.
> This is untested but I hope you'll correct/improve it.
> 

Your tweaks were good, so I tweaked it further:
- When submit fails, invalidate affected sensors as described above.
- When invalidating sensors, do it recursively.
- When battery is not present, invalidate children but not BatteryPresent.

Let me know what you think.

--david

--- a/upd.c
+++ b/upd.c
@@ -1,6 +1,7 @@
 /* $OpenBSD: upd.c,v 1.19 2015/04/30 10:09:31 mpi Exp $ */
 
 /*
+ * Copyright (c) 2015 David Higgs 
  * Copyright (c) 2014 Andre de Oliveira 
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -78,25 +79,28 @@ static struct upd_usage_entry upd_usage_
 };
 #define UPD_MAX_SENSORS(nitems(upd_usage_batdep) + 
nitems(upd_usage_roots))
 
+SLIST_HEAD(upd_sensor_head, upd_sensor);
+
 struct upd_report {
-   size_t  size;
-   SLIST_HEAD(, upd_sensor)sensors;
+   size_t  size;   /* Size of the report */
+   struct upd_sensor_head  sensors;/* List in dependency order */
+   int pending;/* Waiting for an answer */
 };
 
-SLIST_HEAD(upd_sensor_head, upd_sensor);
 struct upd_sensor {
-   struct ksensor  ksensor;
-   struct hid_item hitem;
-   int attached;
-   struct upd_sensor_head  children;
-   SLIST_ENTRY(upd_sensor) dep_next;
-   SLIST_ENTRY(upd_sensor) rep_next;
+   struct ksensor  ksensor;
+   struct hid_item hitem;
+   int attached;   /* Is there a matching report */
+   struct upd_sensor_head  children;   /* list of children sensors */
+   SLIST_ENTRY(upd_sensor) dep_next;   /* next in the child list */
+   SLIST_ENTRY(upd_sensor) rep_next;   /* next in the report list */
 };
 
 struct upd_softc {
struct uhidevsc_hdev;
int  sc_num_sensors;
u_intsc_max_repid;
+   char sc_buf[256];
 
/* sensor framework */
struct ksensordevsc_sensordev;
@@ -112,11 +116,13 @@ void upd_attach_sensor_tree(struct upd_s
 struct upd_usage_entry *, struct upd_sensor_head *);
 int  upd_detach(struct device *, int);
 
-void upd_refresh(void *);
-void upd_update_sensors(struct upd_softc *, uint8_t *, unsigned int, int);
-void upd_update_sensor_value(struct upd_softc *, struct upd_sensor *,
-uint8_t *, int);
 void upd_intr(struct uhidev *, void *, uint);
+void upd_refresh(void *);
+void upd_request_children(struct upd_softc *, struct upd_sensor_head *);
+void upd_update_report_cb(void *, int, void *, int);
+
+void upd_sensor_invalidate(struct upd_softc *, struct upd_sensor *);
+void upd_sensor_update(struct upd_softc *, struct upd_sensor *, uint8_t *, 
int);
 int upd_lookup_usage_entry(void *, int, struct upd_usage_entry *,
 struct hid_item *);
 struct upd_sensor *upd_lookup_sensor(struct upd_softc *, int, int);
@@ -126,10 +132,7 @@ struct cfdriver upd_cd = {
 };
 
 const struct cfattach upd_ca = {
-   sizeof(struct upd_softc),
-   upd_match,
-   upd_attach,
-   upd_detach
+   sizeof(struct upd_softc), upd_match, upd_attach, upd_detach
 };
 
 int
@@ -273,42 +276,50 @@ upd_detach(struct device *self, int flag
sensor = &sc->sc_sensors[i];
if (sensor->attached)
sensor_detach(&sc->sc_sensordev, &sensor->ksensor);
-   DPRINTF(("upd_detach: %s\n", sensor->ksensor.desc));
}
 
free(sc->sc_reports, M_USBDEV, 0);
free(sc->sc_s

Re: Async upd(4) - patch 7/7

2015-04-30 Thread David Higgs
On Thu, Apr 30, 2015 at 7:09 AM, Martin Pieuchot  wrote:

> On 24/04/15(Fri) 20:48, David Higgs wrote:
> > This is the final patch in the series.
> >
> > Utilize the pending flags and report callback for their intended purpose
> - to process async behavior.
> >
> > Apply splusb() to ensure report callbacks can't fire before their data
> structures have been properly updated.  This only needs to happen in
> upd_refresh(); all other calls to upd_request_children() are from a report
> callback.
>
> This is some good work.  I don't think your patch #6 makes sense without
> #7, so I merged them.
>

Sounds good, thanks for all the help.

I don't think you need a "pending" flags for the sensors, since what you
> are querying are the reports.  You basically do not want to send to
> requests for the same report at once.
>

In general the code tries to avoid requesting reports more than once, but
this prevents sensor dependencies from causing some nasty problems.  In the
example below, I don't want the update of C to re-update A and trigger an
infinite loop by requesting B.

Sensor A (report 1) -> Sensor B (report 2) -> Sensor C (report 1)

The alternative is to allow inconsistent sensor values.  If the value of B
affects the value of C, I would rather perform a 2nd request for report 1
once I have the value of B, than to put garbage/bogus values into C.

I prefer to keep sensor values consistent, to ensure nobody's sensorsd
starts to panic and because I doubt many real devices have this kind of
annoying HID descriptor layout.


> I'd also take the simpler approach of not deactivating all sensors if
> you fail to *submit* a transfer.  When such thing happens it's either
> because the device/bus is going away or because we cannot allocate
> memory.
>

This sounds fine for the bus/device case or if M_NOWAIT would trigger a
panic.  How about if the usb device itself runs out of memory/buffers; will
the rest of the system stay happy?  Again, I prefer to err on the side of
consistency and invalidate child sensors so sensorsd isn't looking at stale
values.


> I tweaked your diff below, included some comments and your copyright.
> This is untested but I hope you'll correct/improve it.
>

I'll take a look over the next week.


> I'm also curious, which new reports/sensors do you want to add?
>

I haven't looked at this in some months.  My consumer-grade device had
several useful sensors that aren't currently handled.  There are some
"internal" reports (CapacityMode, AtRate) that aren't suitable as sensors,
but might fix other sensor values being mis-reported.  And there are
interactive things that can be done via reports - silencing the audible
alarm, requesting self-tests - that would be good as sysctls or ioctls
someday.

I'll be happy to look at lsusb output if anyone has a device in mind.

Thanks.

--david


Re: Async upd(4) - patch 7/7

2015-04-30 Thread Martin Pieuchot
On 24/04/15(Fri) 20:48, David Higgs wrote:
> This is the final patch in the series.
> 
> Utilize the pending flags and report callback for their intended purpose - to 
> process async behavior.
> 
> Apply splusb() to ensure report callbacks can't fire before their data 
> structures have been properly updated.  This only needs to happen in 
> upd_refresh(); all other calls to upd_request_children() are from a report 
> callback.

This is some good work.  I don't think your patch #6 makes sense without
#7, so I merged them.

I don't think you need a "pending" flags for the sensors, since what you
are querying are the reports.  You basically do not want to send to
requests for the same report at once.

I'd also take the simpler approach of not deactivating all sensors if
you fail to *submit* a transfer.  When such thing happens it's either
because the device/bus is going away or because we cannot allocate
memory.

I tweaked your diff below, included some comments and your copyright.
This is untested but I hope you'll correct/improve it.

I'm also curious, which new reports/sensors do you want to add?

Cheers,
Martin

Index: upd.c
===
RCS file: /cvs/src/sys/dev/usb/upd.c,v
retrieving revision 1.19
diff -u -p -r1.19 upd.c
--- upd.c   30 Apr 2015 10:09:31 -  1.19
+++ upd.c   30 Apr 2015 11:02:04 -
@@ -1,6 +1,7 @@
 /* $OpenBSD: upd.c,v 1.19 2015/04/30 10:09:31 mpi Exp $ */
 
 /*
+ * Copyright (c) 2015 David Higgs 
  * Copyright (c) 2014 Andre de Oliveira 
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -78,25 +79,28 @@ static struct upd_usage_entry upd_usage_
 };
 #define UPD_MAX_SENSORS(nitems(upd_usage_batdep) + 
nitems(upd_usage_roots))
 
+SLIST_HEAD(upd_sensor_head, upd_sensor);
+
 struct upd_report {
-   size_t  size;
-   SLIST_HEAD(, upd_sensor)sensors;
+   size_t  size;   /* Size of the report */
+   struct upd_sensor_head  sensors;/* List in dependency order */
+   int pending;/* Waiting for an answer */
 };
 
-SLIST_HEAD(upd_sensor_head, upd_sensor);
 struct upd_sensor {
-   struct ksensor  ksensor;
-   struct hid_item hitem;
-   int attached;
-   struct upd_sensor_head  children;
-   SLIST_ENTRY(upd_sensor) dep_next;
-   SLIST_ENTRY(upd_sensor) rep_next;
+   struct ksensor  ksensor;
+   struct hid_item hitem;
+   int attached;   /* Is there a matching report */
+   struct upd_sensor_head  children;   /* list of children sensors */
+   SLIST_ENTRY(upd_sensor) dep_next;   /* next in the child list */
+   SLIST_ENTRY(upd_sensor) rep_next;   /* next in the report list */
 };
 
 struct upd_softc {
struct uhidevsc_hdev;
int  sc_num_sensors;
u_intsc_max_repid;
+   char sc_buf[256];
 
/* sensor framework */
struct ksensordevsc_sensordev;
@@ -112,11 +116,13 @@ void upd_attach_sensor_tree(struct upd_s
 struct upd_usage_entry *, struct upd_sensor_head *);
 int  upd_detach(struct device *, int);
 
-void upd_refresh(void *);
-void upd_update_sensors(struct upd_softc *, uint8_t *, unsigned int, int);
-void upd_update_sensor_value(struct upd_softc *, struct upd_sensor *,
-uint8_t *, int);
 void upd_intr(struct uhidev *, void *, uint);
+void upd_refresh(void *);
+void upd_request_children(struct upd_softc *, struct upd_sensor_head *);
+void upd_update_report_cb(void *, int, void *, int);
+
+void upd_sensor_invalidate(struct upd_softc *, struct upd_sensor *);
+void upd_sensor_update(struct upd_softc *, struct upd_sensor *, uint8_t *, 
int);
 int upd_lookup_usage_entry(void *, int, struct upd_usage_entry *,
 struct hid_item *);
 struct upd_sensor *upd_lookup_sensor(struct upd_softc *, int, int);
@@ -126,10 +132,7 @@ struct cfdriver upd_cd = {
 };
 
 const struct cfattach upd_ca = {
-   sizeof(struct upd_softc),
-   upd_match,
-   upd_attach,
-   upd_detach
+   sizeof(struct upd_softc), upd_match, upd_attach, upd_detach
 };
 
 int
@@ -273,42 +276,51 @@ upd_detach(struct device *self, int flag
sensor = &sc->sc_sensors[i];
if (sensor->attached)
sensor_detach(&sc->sc_sensordev, &sensor->ksensor);
-   DPRINTF(("upd_detach: %s\n", sensor->ksensor.desc));
}
 
free(sc->sc_reports, M_USBDEV, 0);
free(sc->sc_sensors, M_USBDEV, 0);
-   DPRINTF(("upd_detach: complete\n"));
return (0);
 }
 
 void
 upd_refresh(void *arg)
 {
-   struct upd_softc*sc = (struct upd_softc *)arg;
+   struct upd_softc*sc = arg;
+   int  s

Re: Async upd(4)

2015-03-09 Thread David Higgs
On Mon, Mar 9, 2015 at 6:04 AM, Martin Pieuchot 
wrote:

> On 05/03/15(Thu) 12:25, David Higgs wrote:
> >
> > On Mar 3, 2015, at 8:44 AM, David Higgs  wrote:
> >
> > > With much help from mpi@, I have made a first big step towards
> improving upd(4).  I'm not sure when tree lock ends, but I'm still happy to
> accept feedback if right now isn't the time to commit.  There's plenty more
> to do, but I'd like to get this ironed out before moving on.
> > >
> > > New behavior with this diff:
> > > - Leverage new USB async reporting (must have up-to-date tree)
> > > - Sensor dependencies ensure reports are gathered in useful order
> > > - Track pending reports to minimize USB queries
> > > - Relevant sensors immediately invalidated when battery is removed
> (instead of waiting for the next refresh)
> > >
> > > Things that may need sanity checks:
> > > - Simplified upd_attach; the old code seemed to have redundant /
> confusing logic
> > > - Integer promotion/truncation with batpres and hdata/adjust variables
> >
> > Below is an overhauled diff with some additional considerations I came
> up with.
> >
> > Improvements on the previous version:
> > - ACPresent no longer depends on BatteryPresent
> > - Sensor dependencies now handled manually, so dynamic behavior can be
> added later.
> > - Avoid hypothetical cases where certain USB report layouts could
> trigger:
> >   - Infinite loops in sensor dependencies.
> >   - Updating sensor contents using stale information.
> >   - Unnecessary sensor invalidation.
> >   - Redundant USB transfers.
> >
> > As before, comments, questions, and feedback are welcome.
>
> That's great, some comments inline.
>
> >  int  upd_match(struct device *, void *, void *);
> >  void upd_attach(struct device *, struct device *, void *);
> >  int  upd_detach(struct device *, int);
> >
> >  void upd_refresh(void *);
> > -void upd_update_sensors(struct upd_softc *, uint8_t *, unsigned int,
> int);
> > -void upd_intr(struct uhidev *, void *, uint);
> > +void upd_request_sensor_refresh(struct upd_softc *, uint8_t, uint8_t,
> int);
> > +void upd_update_sensor_cb(void *, int, void *, int);
> > +void upd_mark_sensor_invalid(struct upd_softc *, struct upd_sensor *,
> int);
> >  struct upd_usage_entry *upd_lookup_usage_entry(const struct hid_item *);
> >  struct upd_sensor *upd_lookup_sensor(struct upd_softc *, int, int);
> > +int upd_battery_present(struct upd_softc *);
> > +void upd_update_batpres_sensor(struct upd_softc *, struct upd_sensor *,
> > +uint8_t *, int);
> > +void upd_update_batdep_sensor(struct upd_softc *, struct upd_sensor *,
> > +uint8_t *, int);
> > +void upd_update_sensor_value(struct upd_softc *, struct upd_sensor *,
> > +uint8_t *, int);
> > +void upd_intr(struct uhidev *, void *, uint);
> > +
> > +static struct upd_usage_entry upd_usage_table[] = {
> > + { HUP_BATTERY,  HUB_REL_STATEOF_CHARGE,
> > + SENSOR_PERCENT, "RelativeStateOfCharge",
> > + upd_update_batdep_sensor },
> > + { HUP_BATTERY,  HUB_ABS_STATEOF_CHARGE,
> > + SENSOR_PERCENT, "AbsoluteStateOfCharge",
> > + upd_update_batdep_sensor },
> > + { HUP_BATTERY,  HUB_REM_CAPACITY,
> > + SENSOR_PERCENT, "RemainingCapacity",
> > + upd_update_batdep_sensor },
> > + { HUP_BATTERY,  HUB_FULLCHARGE_CAPACITY,
> > + SENSOR_PERCENT, "FullChargeCapacity",
> > + upd_update_batdep_sensor },
> > + { HUP_BATTERY,  HUB_CHARGING,
> > + SENSOR_INDICATOR,   "Charging",
> > + upd_update_batdep_sensor },
> > + { HUP_BATTERY,  HUB_DISCHARGING,
> > + SENSOR_INDICATOR,   "Discharging",
> > + upd_update_batdep_sensor },
> > + { HUP_BATTERY,  HUB_BATTERY_PRESENT,
> > + SENSOR_INDICATOR,   "BatteryPresent",
> > + upd_update_batpres_sensor },
> > + { HUP_POWER,HUP_SHUTDOWN_IMMINENT,
> > + SENSOR_INDICATOR,   "ShutdownImminent",
> > + upd_update_sensor_value },
> > + { HUP_BATTERY,  HUB_AC_PRESENT,
> > + SENSOR_INDICATOR,   "ACPresent",
> > + upd_update_batdep_sensor },
> > + { HUP_BATTERY,  HUB_ATRATE_TIMETOFULL,
> > + SENSOR_TIMEDELTA,   "AtRateTimeToFull",
> > + upd_update_batdep_sensor }
> > +};
>
> I see that all the HUP_BATTERY sensors have the same dependency.   Why
> not have a table for items without dependency (the parents) and a child
> table per parent?  This way you would have only one "upd_update_sensor"
> function.  This is really the key of this driver.  Why a flat list like
> you have right now you need much more code, flags and customs functions.


This does seem simpler; I'll give it a shot.


> >
> >  struct cfdriver upd_cd = {
> >   NULL, "upd", DV_DULL
> > @@ -183,38 +207,30 @@ upd_attach(struct device *parent, struct
> >sc->sc_num_sensors < sc->sc_max_sensors; ) {
> >   DPRINTF(("upd: repid=%d\n", item.report_ID));
> >   if (item.kind != hid_feature ||
> > -

Re: Async upd(4)

2015-03-09 Thread Martin Pieuchot
On 05/03/15(Thu) 12:25, David Higgs wrote:
> 
> On Mar 3, 2015, at 8:44 AM, David Higgs  wrote:
> 
> > With much help from mpi@, I have made a first big step towards improving 
> > upd(4).  I’m not sure when tree lock ends, but I’m still happy to accept 
> > feedback if right now isn’t the time to commit.  There’s plenty more to do, 
> > but I’d like to get this ironed out before moving on.
> > 
> > New behavior with this diff:
> > - Leverage new USB async reporting (must have up-to-date tree)
> > - Sensor dependencies ensure reports are gathered in useful order
> > - Track pending reports to minimize USB queries
> > - Relevant sensors immediately invalidated when battery is removed (instead 
> > of waiting for the next refresh)
> > 
> > Things that may need sanity checks:
> > - Simplified upd_attach; the old code seemed to have redundant / confusing 
> > logic
> > - Integer promotion/truncation with batpres and hdata/adjust variables
> 
> Below is an overhauled diff with some additional considerations I came up 
> with.
> 
> Improvements on the previous version:
> - ACPresent no longer depends on BatteryPresent
> - Sensor dependencies now handled manually, so dynamic behavior can be added 
> later.
> - Avoid hypothetical cases where certain USB report layouts could trigger:
>   - Infinite loops in sensor dependencies.
>   - Updating sensor contents using stale information.
>   - Unnecessary sensor invalidation.
>   - Redundant USB transfers.
> 
> As before, comments, questions, and feedback are welcome.

That's great, some comments inline.

>  int  upd_match(struct device *, void *, void *);
>  void upd_attach(struct device *, struct device *, void *);
>  int  upd_detach(struct device *, int);
>  
>  void upd_refresh(void *);
> -void upd_update_sensors(struct upd_softc *, uint8_t *, unsigned int, int);
> -void upd_intr(struct uhidev *, void *, uint);
> +void upd_request_sensor_refresh(struct upd_softc *, uint8_t, uint8_t, int);
> +void upd_update_sensor_cb(void *, int, void *, int);
> +void upd_mark_sensor_invalid(struct upd_softc *, struct upd_sensor *, int);
>  struct upd_usage_entry *upd_lookup_usage_entry(const struct hid_item *);
>  struct upd_sensor *upd_lookup_sensor(struct upd_softc *, int, int);
> +int upd_battery_present(struct upd_softc *);
> +void upd_update_batpres_sensor(struct upd_softc *, struct upd_sensor *,
> +uint8_t *, int);
> +void upd_update_batdep_sensor(struct upd_softc *, struct upd_sensor *,
> +uint8_t *, int);
> +void upd_update_sensor_value(struct upd_softc *, struct upd_sensor *,
> +uint8_t *, int);
> +void upd_intr(struct uhidev *, void *, uint);
> +
> +static struct upd_usage_entry upd_usage_table[] = {
> + { HUP_BATTERY,  HUB_REL_STATEOF_CHARGE,
> + SENSOR_PERCENT, "RelativeStateOfCharge",
> + upd_update_batdep_sensor },
> + { HUP_BATTERY,  HUB_ABS_STATEOF_CHARGE,
> + SENSOR_PERCENT, "AbsoluteStateOfCharge",
> + upd_update_batdep_sensor },
> + { HUP_BATTERY,  HUB_REM_CAPACITY,
> + SENSOR_PERCENT, "RemainingCapacity",
> + upd_update_batdep_sensor },
> + { HUP_BATTERY,  HUB_FULLCHARGE_CAPACITY,
> + SENSOR_PERCENT, "FullChargeCapacity",
> + upd_update_batdep_sensor },
> + { HUP_BATTERY,  HUB_CHARGING,
> + SENSOR_INDICATOR,   "Charging",
> + upd_update_batdep_sensor },
> + { HUP_BATTERY,  HUB_DISCHARGING,
> + SENSOR_INDICATOR,   "Discharging",
> + upd_update_batdep_sensor },
> + { HUP_BATTERY,  HUB_BATTERY_PRESENT,
> + SENSOR_INDICATOR,   "BatteryPresent",
> + upd_update_batpres_sensor },
> + { HUP_POWER,HUP_SHUTDOWN_IMMINENT,
> + SENSOR_INDICATOR,   "ShutdownImminent",
> + upd_update_sensor_value },
> + { HUP_BATTERY,  HUB_AC_PRESENT,
> + SENSOR_INDICATOR,   "ACPresent",
> + upd_update_batdep_sensor },
> + { HUP_BATTERY,  HUB_ATRATE_TIMETOFULL,
> + SENSOR_TIMEDELTA,   "AtRateTimeToFull",
> + upd_update_batdep_sensor }
> +};

I see that all the HUP_BATTERY sensors have the same dependency.   Why
not have a table for items without dependency (the parents) and a child
table per parent?  This way you would have only one "upd_update_sensor"
function.  This is really the key of this driver.  Why a flat list like
you have right now you need much more code, flags and customs functions.

>  
>  struct cfdriver upd_cd = {
>   NULL, "upd", DV_DULL
> @@ -183,38 +207,30 @@ upd_attach(struct device *parent, struct
>sc->sc_num_sensors < sc->sc_max_sensors; ) {
>   DPRINTF(("upd: repid=%d\n", item.report_ID));
>   if (item.kind != hid_feature ||
> - item.report_ID < 0)
> + item.report_ID < 0 ||
> + item.report_ID >= sc->sc_max_repid)
>   continue;
> -
>   if ((entry = upd_lookup_usage_entry(&item)) == NULL)
>   continue;
> -
> 

Re: Async upd(4)

2015-03-05 Thread David Higgs

On Mar 3, 2015, at 8:44 AM, David Higgs  wrote:

> With much help from mpi@, I have made a first big step towards improving 
> upd(4).  I’m not sure when tree lock ends, but I’m still happy to accept 
> feedback if right now isn’t the time to commit.  There’s plenty more to do, 
> but I’d like to get this ironed out before moving on.
> 
> New behavior with this diff:
> - Leverage new USB async reporting (must have up-to-date tree)
> - Sensor dependencies ensure reports are gathered in useful order
> - Track pending reports to minimize USB queries
> - Relevant sensors immediately invalidated when battery is removed (instead 
> of waiting for the next refresh)
> 
> Things that may need sanity checks:
> - Simplified upd_attach; the old code seemed to have redundant / confusing 
> logic
> - Integer promotion/truncation with batpres and hdata/adjust variables

Below is an overhauled diff with some additional considerations I came up with.

Improvements on the previous version:
- ACPresent no longer depends on BatteryPresent
- Sensor dependencies now handled manually, so dynamic behavior can be added 
later.
- Avoid hypothetical cases where certain USB report layouts could trigger:
  - Infinite loops in sensor dependencies.
  - Updating sensor contents using stale information.
  - Unnecessary sensor invalidation.
  - Redundant USB transfers.

As before, comments, questions, and feedback are welcome.

--david


Index: upd.c
===
RCS file: /cvs/src/sys/dev/usb/upd.c,v
retrieving revision 1.13
diff -u -p -r1.13 upd.c
--- upd.c   11 Jan 2015 03:08:38 -  1.13
+++ upd.c   5 Mar 2015 17:06:19 -
@@ -39,45 +39,17 @@
 #define DPRINTF(x)
 #endif
 
-struct upd_usage_entry {
-   uint8_t usage_pg;
-   uint8_t usage_id;
-   enum sensor_typesenstype;
-   char*usage_name; /* sensor string */
-};
-
-static struct upd_usage_entry upd_usage_table[] = {
-   { HUP_BATTERY,  HUB_REL_STATEOF_CHARGE,
-   SENSOR_PERCENT,  "RelativeStateOfCharge" },
-   { HUP_BATTERY,  HUB_ABS_STATEOF_CHARGE,
-   SENSOR_PERCENT,  "AbsoluteStateOfCharge" },
-   { HUP_BATTERY,  HUB_REM_CAPACITY,
-   SENSOR_PERCENT,  "RemainingCapacity" },
-   { HUP_BATTERY,  HUB_FULLCHARGE_CAPACITY,
-   SENSOR_PERCENT,  "FullChargeCapacity" },
-   { HUP_BATTERY,  HUB_CHARGING,
-   SENSOR_INDICATOR,"Charging" },
-   { HUP_BATTERY,  HUB_DISCHARGING,
-   SENSOR_INDICATOR,"Discharging" },
-   { HUP_BATTERY,  HUB_BATTERY_PRESENT,
-   SENSOR_INDICATOR,"BatteryPresent" },
-   { HUP_POWER,HUP_SHUTDOWN_IMMINENT,
-   SENSOR_INDICATOR,"ShutdownImminent" },
-   { HUP_BATTERY,  HUB_AC_PRESENT,
-   SENSOR_INDICATOR,"ACPresent" },
-   { HUP_BATTERY,  HUB_ATRATE_TIMETOFULL,
-   SENSOR_TIMEDELTA,"AtRateTimeToFull" }
-};
-
 struct upd_report {
size_t  size;
-   int enabled;
+   int pending;
 };
 
 struct upd_sensor {
struct ksensor  ksensor;
struct hid_item hitem;
+   struct upd_usage_entry  *entry;
int attached;
+   int pending;
 };
 
 struct upd_softc {
@@ -85,6 +57,7 @@ struct upd_softc {
int  sc_num_sensors;
u_intsc_max_repid;
u_intsc_max_sensors;
+   char sc_buf[256];
 
/* sensor framework */
struct ksensordevsc_sensordev;
@@ -93,15 +66,66 @@ struct upd_softc {
struct upd_sensor   *sc_sensors;
 };
 
+struct upd_usage_entry {
+   uint8_t usage_pg;
+   uint8_t usage_id;
+   enum sensor_typesenstype;
+   char*usage_name; /* sensor string */
+   void (*update_sensor)(struct upd_softc *, struct upd_sensor *,
+   uint8_t *, int);
+};
+
 int  upd_match(struct device *, void *, void *);
 void upd_attach(struct device *, struct device *, void *);
 int  upd_detach(struct device *, int);
 
 void upd_refresh(void *);
-void upd_update_sensors(struct upd_softc *, uint8_t *, unsigned int, int);
-void upd_intr(struct uhidev *, void *, uint);
+void upd_request_sensor_refresh(struct upd_softc *, uint8_t, uint8_t, int);
+void upd_update_sensor_cb(void *, int, void *, int);
+void upd_mark_sensor_invalid(struct upd_softc *, struct upd_sensor *, int);
 struct upd_usage_entry *upd_lookup_usage_entry(const struct hid_item *);
 struct upd_sensor *upd_lookup_sensor(struct upd_softc *, int, int);
+int upd_battery_present(struct upd_softc *);
+void upd_update_batpres_sensor(struct upd_softc *, struct upd_sensor *,
+uint8_t *, int);
+void upd_update_batdep_sensor(struct upd_softc *, struct upd_sensor *,
+uint8_t *, int);
+void u