Re: arm64: make cwfg(4) report battery information to apm(4)

2021-03-24 Thread Jeremie Courreges-Anglas
On Wed, Mar 24 2021, Klemens Nanni  wrote:
> On Wed, Mar 24, 2021 at 12:49:51AM +0100, Jeremie Courreges-Anglas wrote:
>  
>> >> > @@ -202,6 +217,12 @@ cwfg_attach(struct device *parent, struc
>> >> >  
>> >> > sensor_task_register(sc, cwfg_update_sensors, 5);
>> >> >  
>> >> > +#if NAPM > 0
>> >> > +   /* make sure we have the apm state initialized before apm 
>> >> > attaches */
>> >> > +   cwfg_update_sensors(sc);
>> >> > +   apm_setinfohook(cwfg_apminfo);
>> >> > +#endif
>> >> > +
>> >> > printf("\n");
>> >> >  }
>> >> >  
>> >> > @@ -324,6 +345,7 @@ cwfg_update_sensors(void *arg)
>> >> > uint32_t vcell, rtt, tmp;
>> >> > uint8_t val;
>> >> > int error, n;
>> >> > +   u_char bat_percent;
>> >> >  
>> >> > if ((error = cwfg_lock(sc)) != 0)
>> >> > return;
>> >> > @@ -348,6 +370,7 @@ cwfg_update_sensors(void *arg)
>> >> > if ((error = cwfg_read(sc, SOC_HI_REG, &val)) != 0)
>> >> > goto done;
>> >> > if (val != 0xff) {
>> >> > +   bat_percent = val;
>> >> > sc->sc_sensor[CWFG_SENSOR_SOC].value = val * 1000;
>> >> > sc->sc_sensor[CWFG_SENSOR_SOC].flags &= 
>> >> > ~SENSOR_FINVALID;
>> >> > }
>> >> 
>> >> If val == 0xff bat_percent is unitialized.  Note that in this error
>> >> condition the sensors code leaves sc->sc_sensor[CWFG_SENSOR_SOC].value
>> >> alone.
>> > Oops.  Both `val' and `rtt' can be "useless" and we could end up with
>> > a partially updated `cwfg_power'.
>> 
>> With the current code, rtt is always meaningful.  I was really talking
>> only about bat_percent being possibly uninitialized.
> Yes, `rtt' always means something but the code does not always populate
> the struct member with it from which I read unconditionally - this is
> what I meant.
>
> Hence, instead of always reading from it and possibly getting a stale
> value, the second diff makes sure that each update cycle resets every
> value and only updates those that come from a fresh reading.
>
>> > If we always reset all values up front and then update whatever is
>> > possible, we can avoid the intermediate variable completely and end up
>> > with `cwfg_power' providing consistent readings.
>> 
>> Except if reading one register fails and we take the goto done shortcut.
>> In that case sensors and apm get out of sync, which is bad IMHO.
> My intention was that I'd rather provide an all reset struct with a
> single value updated that is known to be good rather than lazily
> updating whatever is possible.
>
>> >> So to keep apm and sensors in sync I think it would be better to reuse
>> >> the cached sc->sc_sensor[CWFG_SENSOR_SOC].value.
>> > I did `sc->sc_sensor[CWFG_SENSOR_SOC].value / 1000' first but ended up
>> > with bogus values, hence the `bat_percent' buffer to avoid arithmetics.
>> >
>> >
>> >> I don't know whether the error condition mentioned above happens
>> >> frequently with this driver.  Reporting APM_BATT_ABSENT (and similar for
>> >> sensors) would be useful, and could be done in a subsequent step.
>> > But that isn't the case?  From apm(4):
>> >
>> >  APM_BATTERY_ABSENT
>> >   No battery installed.
>> >
>> > The driver just can't tell us enough, but the battery is still there
>> > (we get good percentage/liftime readings), so
>> >
>> >  APM_BATT_UNKNOWN
>> >   Cannot read the current battery state.
>> >
>> > is only appropiate here imho.
>> >
>> >
>> >> What's the underlying hardware, does it involve a pluggable battery?
>> > Nope, Pinebook Pro with one internal battery and AC.
>> 
>> Since the battery can't be removed in your pinebook, then obviously
>> APM_BATTERY_ABSENT isn't very meaningful.  But maybe the CellWise
>> hardware supports pluggable batteries.  Anyway...
>> 
>> The diff below is mostly your diff, except:
>> - statically initialize cwfg_power with proper values.  That way there's
>>   a reason less for initializing it early by forcefully calling
>>   cwfg_update_sensors().
> I like that, thanks.
>
>> - only update cwfg_power when we already fetched new values for sensors.
> As outlined above, I'd like to avoid this approach.
>
> Let's assume the sensor works fine and all values are read correctly,
> then apm shows something like this:
>
>   Battery state: high, 78% remaining, 323 minutes life estimate
>
> Now if for whatever reason in cwfg_update_sensors() only readings for
> RTT (battery remaining minutes) start failing, your diff would keep
> updating SOC (battery percent) without touching RTT, so apm would trend
> like so
>
>   Battery state: high, 70% remaining, 323 minutes life estimate
>   Battery state: high, 50% remaining, 323 minutes life estimate
>
> Or not?  To deal with this I reset everything to invalid/unknown, such
> that in the above scenario apm would trend like so
>
>   Battery state: high, 78% remaining, 323 minutes lif

Re: arm64: make cwfg(4) report battery information to apm(4)

2021-03-23 Thread Klemens Nanni
On Wed, Mar 24, 2021 at 12:49:51AM +0100, Jeremie Courreges-Anglas wrote:
 
> >> > @@ -202,6 +217,12 @@ cwfg_attach(struct device *parent, struc
> >> >  
> >> >  sensor_task_register(sc, cwfg_update_sensors, 5);
> >> >  
> >> > +#if NAPM > 0
> >> > +/* make sure we have the apm state initialized before apm 
> >> > attaches */
> >> > +cwfg_update_sensors(sc);
> >> > +apm_setinfohook(cwfg_apminfo);
> >> > +#endif
> >> > +
> >> >  printf("\n");
> >> >  }
> >> >  
> >> > @@ -324,6 +345,7 @@ cwfg_update_sensors(void *arg)
> >> >  uint32_t vcell, rtt, tmp;
> >> >  uint8_t val;
> >> >  int error, n;
> >> > +u_char bat_percent;
> >> >  
> >> >  if ((error = cwfg_lock(sc)) != 0)
> >> >  return;
> >> > @@ -348,6 +370,7 @@ cwfg_update_sensors(void *arg)
> >> >  if ((error = cwfg_read(sc, SOC_HI_REG, &val)) != 0)
> >> >  goto done;
> >> >  if (val != 0xff) {
> >> > +bat_percent = val;
> >> >  sc->sc_sensor[CWFG_SENSOR_SOC].value = val * 1000;
> >> >  sc->sc_sensor[CWFG_SENSOR_SOC].flags &= 
> >> > ~SENSOR_FINVALID;
> >> >  }
> >> 
> >> If val == 0xff bat_percent is unitialized.  Note that in this error
> >> condition the sensors code leaves sc->sc_sensor[CWFG_SENSOR_SOC].value
> >> alone.
> > Oops.  Both `val' and `rtt' can be "useless" and we could end up with
> > a partially updated `cwfg_power'.
> 
> With the current code, rtt is always meaningful.  I was really talking
> only about bat_percent being possibly uninitialized.
Yes, `rtt' always means something but the code does not always populate
the struct member with it from which I read unconditionally - this is
what I meant.

Hence, instead of always reading from it and possibly getting a stale
value, the second diff makes sure that each update cycle resets every
value and only updates those that come from a fresh reading.

> > If we always reset all values up front and then update whatever is
> > possible, we can avoid the intermediate variable completely and end up
> > with `cwfg_power' providing consistent readings.
> 
> Except if reading one register fails and we take the goto done shortcut.
> In that case sensors and apm get out of sync, which is bad IMHO.
My intention was that I'd rather provide an all reset struct with a
single value updated that is known to be good rather than lazily
updating whatever is possible.

> >> So to keep apm and sensors in sync I think it would be better to reuse
> >> the cached sc->sc_sensor[CWFG_SENSOR_SOC].value.
> > I did `sc->sc_sensor[CWFG_SENSOR_SOC].value / 1000' first but ended up
> > with bogus values, hence the `bat_percent' buffer to avoid arithmetics.
> >
> >
> >> I don't know whether the error condition mentioned above happens
> >> frequently with this driver.  Reporting APM_BATT_ABSENT (and similar for
> >> sensors) would be useful, and could be done in a subsequent step.
> > But that isn't the case?  From apm(4):
> >
> >  APM_BATTERY_ABSENT
> >   No battery installed.
> >
> > The driver just can't tell us enough, but the battery is still there
> > (we get good percentage/liftime readings), so
> >
> >  APM_BATT_UNKNOWN
> >   Cannot read the current battery state.
> >
> > is only appropiate here imho.
> >
> >
> >> What's the underlying hardware, does it involve a pluggable battery?
> > Nope, Pinebook Pro with one internal battery and AC.
> 
> Since the battery can't be removed in your pinebook, then obviously
> APM_BATTERY_ABSENT isn't very meaningful.  But maybe the CellWise
> hardware supports pluggable batteries.  Anyway...
> 
> The diff below is mostly your diff, except:
> - statically initialize cwfg_power with proper values.  That way there's
>   a reason less for initializing it early by forcefully calling
>   cwfg_update_sensors().
I like that, thanks.

> - only update cwfg_power when we already fetched new values for sensors.
As outlined above, I'd like to avoid this approach.

Let's assume the sensor works fine and all values are read correctly,
then apm shows something like this:

Battery state: high, 78% remaining, 323 minutes life estimate

Now if for whatever reason in cwfg_update_sensors() only readings for
RTT (battery remaining minutes) start failing, your diff would keep
updating SOC (battery percent) without touching RTT, so apm would trend
like so

Battery state: high, 70% remaining, 323 minutes life estimate
Battery state: high, 50% remaining, 323 minutes life estimate

Or not?  To deal with this I reset everything to invalid/unknown, such
that in the above scenario apm would trend like so

Battery state: high, 78% remaining, 323 minutes life estimate
Battery state: high, 70% remaining, unknown life estimate
Battery state: high, 50% remaining, unknown life estimate

Which reads ar

Re: arm64: make cwfg(4) report battery information to apm(4)

2021-03-23 Thread Jeremie Courreges-Anglas
On Mon, Mar 22 2021, Klemens Nanni  wrote:
> Better diff at the end thanks to jca's eyeballing, see comments inline.
>
> kettenis:  I see room for improvement in our subsystems and their
> interactions, but I don't think the current situation is bad enough to
> leave those bits out for now.
>
> Feedback? OK?
>

[...]

>> > @@ -202,6 +217,12 @@ cwfg_attach(struct device *parent, struc
>> >  
>> >sensor_task_register(sc, cwfg_update_sensors, 5);
>> >  
>> > +#if NAPM > 0
>> > +  /* make sure we have the apm state initialized before apm attaches */
>> > +  cwfg_update_sensors(sc);
>> > +  apm_setinfohook(cwfg_apminfo);
>> > +#endif
>> > +
>> >printf("\n");
>> >  }
>> >  
>> > @@ -324,6 +345,7 @@ cwfg_update_sensors(void *arg)
>> >uint32_t vcell, rtt, tmp;
>> >uint8_t val;
>> >int error, n;
>> > +  u_char bat_percent;
>> >  
>> >if ((error = cwfg_lock(sc)) != 0)
>> >return;
>> > @@ -348,6 +370,7 @@ cwfg_update_sensors(void *arg)
>> >if ((error = cwfg_read(sc, SOC_HI_REG, &val)) != 0)
>> >goto done;
>> >if (val != 0xff) {
>> > +  bat_percent = val;
>> >sc->sc_sensor[CWFG_SENSOR_SOC].value = val * 1000;
>> >sc->sc_sensor[CWFG_SENSOR_SOC].flags &= ~SENSOR_FINVALID;
>> >}
>> 
>> If val == 0xff bat_percent is unitialized.  Note that in this error
>> condition the sensors code leaves sc->sc_sensor[CWFG_SENSOR_SOC].value
>> alone.
> Oops.  Both `val' and `rtt' can be "useless" and we could end up with
> a partially updated `cwfg_power'.

With the current code, rtt is always meaningful.  I was really talking
only about bat_percent being possibly uninitialized.

> If we always reset all values up front and then update whatever is
> possible, we can avoid the intermediate variable completely and end up
> with `cwfg_power' providing consistent readings.

Except if reading one register fails and we take the goto done shortcut.
In that case sensors and apm get out of sync, which is bad IMHO.

[...]

>> So to keep apm and sensors in sync I think it would be better to reuse
>> the cached sc->sc_sensor[CWFG_SENSOR_SOC].value.
> I did `sc->sc_sensor[CWFG_SENSOR_SOC].value / 1000' first but ended up
> with bogus values, hence the `bat_percent' buffer to avoid arithmetics.
>
>
>> I don't know whether the error condition mentioned above happens
>> frequently with this driver.  Reporting APM_BATT_ABSENT (and similar for
>> sensors) would be useful, and could be done in a subsequent step.
> But that isn't the case?  From apm(4):
>
>  APM_BATTERY_ABSENT
>   No battery installed.
>
> The driver just can't tell us enough, but the battery is still there
> (we get good percentage/liftime readings), so
>
>  APM_BATT_UNKNOWN
>   Cannot read the current battery state.
>
> is only appropiate here imho.
>
>
>> What's the underlying hardware, does it involve a pluggable battery?
> Nope, Pinebook Pro with one internal battery and AC.

Since the battery can't be removed in your pinebook, then obviously
APM_BATTERY_ABSENT isn't very meaningful.  But maybe the CellWise
hardware supports pluggable batteries.  Anyway...

The diff below is mostly your diff, except:
- statically initialize cwfg_power with proper values.  That way there's
  a reason less for initializing it early by forcefully calling
  cwfg_update_sensors().
- only update cwfg_power when we already fetched new values for sensors.

I hope that this approach will make changing the cwfg_update_sensors()
code easier.

If it works for you and you agree with this tweaked proposal, ok jca@


Index: cwfg.c
===
RCS file: /d/cvs/src/sys/dev/fdt/cwfg.c,v
retrieving revision 1.2
diff -u -p -p -u -r1.2 cwfg.c
--- cwfg.c  22 Mar 2021 18:37:26 -  1.2
+++ cwfg.c  23 Mar 2021 23:49:22 -
@@ -32,12 +32,15 @@
 #include 
 #include 
 
+#include 
 #include 
 
 #include 
 
 #include 
 
+#include "apm.h"
+
 #defineVERSION_REG 0x00
 #defineVCELL_HI_REG0x02
 #define VCELL_HI_MASK  0x3f
@@ -119,6 +122,22 @@ struct cfdriver cwfg_cd = {
NULL, "cwfg", DV_DULL
 };
 
+#if NAPM > 0
+struct apm_power_info cwfg_power = {
+   .battery_state = APM_BATT_UNKNOWN,
+   .ac_state = APM_AC_UNKNOWN,
+   .battery_life = 0,
+   .minutes_left = -1,
+};
+
+int
+cwfg_apminfo(struct apm_power_info *info)
+{
+   memcpy(info, &cwfg_power, sizeof(*info));
+   return 0;
+}
+#endif
+
 int
 cwfg_match(struct device *parent, void *match, void *aux)
 {
@@ -202,6 +221,10 @@ cwfg_attach(struct device *parent, struc
 
sensor_task_register(sc, cwfg_update_sensors, 5);
 
+#if NAPM > 0
+   apm_setinfohook(cwfg_apminfo);
+#endif
+
printf("\n");
 }
 
@@ -350,6 +373,11 @@ cwfg_update_sensors(void *arg)
if (val != 0xff) {
sc->sc_sensor[CWFG_SENSOR_SOC].va

Re: arm64: make cwfg(4) report battery information to apm(4)

2021-03-22 Thread Klemens Nanni
Better diff at the end thanks to jca's eyeballing, see comments inline.

kettenis:  I see room for improvement in our subsystems and their
interactions, but I don't think the current situation is bad enough to
leave those bits out for now.

Feedback? OK?

On Mon, Mar 22, 2021 at 01:21:02AM +0100, Jeremie Courreges-Anglas wrote:
> > Index: dev/fdt/cwfg.c
> > ===
> > RCS file: /cvs/src/sys/dev/fdt/cwfg.c,v
> > retrieving revision 1.1
> > diff -u -p -r1.1 cwfg.c
> > --- dev/fdt/cwfg.c  10 Jun 2020 17:51:21 -  1.1
> > +++ dev/fdt/cwfg.c  20 Mar 2021 23:43:13 -
> > @@ -32,12 +32,15 @@
> >  #include 
> >  #include 
> >  
> > +#include 
> >  #include 
> >  
> >  #include 
> >  
> >  #include 
> >  
> > +#include "apm.h"
> > +
> >  #defineVERSION_REG 0x00
> >  #defineVCELL_HI_REG0x02
> >  #define VCELL_HI_MASK  0x3f
> > @@ -119,6 +122,18 @@ struct cfdriver cwfg_cd = {
> > NULL, "cwfg", DV_DULL
> >  };
> >  
> > +int cwfg_apminfo(struct apm_power_info *info);
> 
> Why out of the #if NAPM > 0 check?
Copied over from the loongson driver; the declaration doesn't hurt
outside but isn't needed either.  I've removed it.

> > +#if NAPM > 0
> > +struct apm_power_info cwfg_power;
> > +
> > +int
> > +cwfg_apminfo(struct apm_power_info *info)
> > +{
> > +   bcopy(&cwfg_power, info, sizeof(*info));
> 
> There's no overlap between source and destination, better use memcpy.
> (Else, better use memmove.)
Right, I also copied this over from loongson (we can dust that one off
as well later on).

> 
> > +   return 0;
> > +}
> > +#endif
> > +
> >  int
> >  cwfg_match(struct device *parent, void *match, void *aux)
> >  {
> > @@ -202,6 +217,12 @@ cwfg_attach(struct device *parent, struc
> >  
> > sensor_task_register(sc, cwfg_update_sensors, 5);
> >  
> > +#if NAPM > 0
> > +   /* make sure we have the apm state initialized before apm attaches */
> > +   cwfg_update_sensors(sc);
> > +   apm_setinfohook(cwfg_apminfo);
> > +#endif
> > +
> > printf("\n");
> >  }
> >  
> > @@ -324,6 +345,7 @@ cwfg_update_sensors(void *arg)
> > uint32_t vcell, rtt, tmp;
> > uint8_t val;
> > int error, n;
> > +   u_char bat_percent;
> >  
> > if ((error = cwfg_lock(sc)) != 0)
> > return;
> > @@ -348,6 +370,7 @@ cwfg_update_sensors(void *arg)
> > if ((error = cwfg_read(sc, SOC_HI_REG, &val)) != 0)
> > goto done;
> > if (val != 0xff) {
> > +   bat_percent = val;
> > sc->sc_sensor[CWFG_SENSOR_SOC].value = val * 1000;
> > sc->sc_sensor[CWFG_SENSOR_SOC].flags &= ~SENSOR_FINVALID;
> > }
> 
> If val == 0xff bat_percent is unitialized.  Note that in this error
> condition the sensors code leaves sc->sc_sensor[CWFG_SENSOR_SOC].value
> alone.
Oops.  Both `val' and `rtt' can be "useless" and we could end up with
a partially updated `cwfg_power'.

If we always reset all values up front and then update whatever is
possible, we can avoid the intermediate variable completely and end up
with `cwfg_power' providing consistent readings.

> 
> > @@ -363,6 +386,14 @@ cwfg_update_sensors(void *arg)
> > sc->sc_sensor[CWFG_SENSOR_RTT].value = rtt;
> > sc->sc_sensor[CWFG_SENSOR_RTT].flags &= ~SENSOR_FINVALID;
> > }
> > +
> > +#if NAPM > 0
> > +   cwfg_power.battery_state = bat_percent > sc->sc_alert_level ?
> > +   APM_BATT_HIGH : APM_BATT_LOW;
> 
> It's cool that this driver keeps track of the "alert level".  acpibat(4)
> also does that on amd64, but the apm(4)-through-acpi(4) userland
> interface just hardcodes levels:
> 
>   /* running on battery */
>   pi->battery_life = remaining * 100 / capacity;
>   if (pi->battery_life > 50)
>   pi->battery_state = APM_BATT_HIGH;
>   else if (pi->battery_life > 25)
>   pi->battery_state = APM_BATT_LOW;
>   else
>   pi->battery_state = APM_BATT_CRITICAL;
> 
> Maybe the levels reported by hardware couldn't be trusted?  Or maybe
> those hardcoded values were deemed good enough, back then.  Anyway, on
> this new hardware I think it makes sense to just trust the exported
> values and later act if we get reports.
Yes, I explicitly want to use what hardware provides and we can still
tweak it to more sensible values if need be.

> 
> > +   cwfg_power.ac_state = APM_AC_UNKNOWN;
> 
> This kinda points out the need for an AC driver on this platform.
> If done in another driver, the code will need to be changed.  But this
> looks acceptable to me for now.
Yup.

> 
> > +   cwfg_power.battery_life = bat_percent;
> 
> So to keep apm and sensors in sync I think it would be better to reuse
> the cached sc->sc_sensor[CWFG_SENSOR_SOC].value.
I did `sc->sc_sensor[CWFG_SENSOR_SOC].value / 1000' first but ended up
with bogus values, hence the `bat_percent' buffer to avoid arithmetics.


> I don

Re: arm64: make cwfg(4) report battery information to apm(4)

2021-03-21 Thread Theo de Raadt
Klemens Nanni  wrote:

> > So which is better:
> > 
> > (1) try to emit some information for the people who quicky-use the apm 
> > interface
> > 
> > (2) change apm to not print those lines on architectures where we are 
> > unsure.
> > 
> > I think (1) is acceptable for a tool which has never promised perfect 
> > accuracy. 
> I concur (obviously).
> 
> > I suspect hard-wiring this to one driver is going to be better than scanning
> > the sensor list and heuristically determining which specific sensors to 
> > look at,
> > because the only good selector now is strcmp(sensor->desc, "battery 
> > remaining minutes")
> > yuck.
> To be fair, kettenis proposed a rough idea to have simpler/faster checks
> than strcmp().  With a simple flag you wouldn't need any heuristics
> either but let the sensor framework -which has all the pieces- do the
> work and put a stamp on the ready-to-use value saying "use this as
> battery level".

that simple flag will probably be too simple, and it won't be long
before someone in another architecture wants it to mean something more,
or wants another flag, and before long there will be zeal to flag carrying to
the sensor framework.

and what happens if two drivers set the flag?

Another way of doing this is for an platform to name the sensor driver which
has the info, and then search the sensor free.

Or, simply write per-platform code that finds it's own stuff.



Re: arm64: make cwfg(4) report battery information to apm(4)

2021-03-21 Thread Jeremie Courreges-Anglas
On Sun, Mar 21 2021, Mark Kettenis  wrote:
>> Date: Sun, 21 Mar 2021 17:22:05 +0100
>> From: Klemens Nanni 
>> 
>> On Sun, Mar 21, 2021 at 02:02:00PM +0100, Mark Kettenis wrote:
>> > > Date: Sun, 21 Mar 2021 01:02:53 +0100
>> > > From: Klemens Nanni 
>> > > 
>> > > apm(4/arm64) merely provides an all zero/unknown stub for those values,
>> > > e.g. apm(8) output is useless.
>> > > 
>> > > Hardware sensors however provide the information:
>> > > 
>> > >  $ sysctl hw.sensors
>> > >  hw.sensors.rktemp0.temp0=32.22 degC (CPU)
>> > >  hw.sensors.rktemp0.temp1=33.89 degC (GPU)
>> > >  hw.sensors.cwfg0.volt0=3.76 VDC (battery voltage)
>> > >  hw.sensors.cwfg0.raw0=259 (battery remaining minutes)
>> > >  hw.sensors.cwfg0.percent0=58.00% (battery percent)
>> > > 
>> > > Diff below simply copies them over using apm_setinfohook()
>> > > (I've looked at sys/arch/loongson/dev/kb3310.c which does the same):
>> > > 
>> > >  $ apm
>> > >  Battery state: high, 58% remaining, 259 minutes life estimate
>> > >  A/C adapter state: not known
>> > >  Performance adjustment mode: auto (408 MHz)
>> > > 
>> > > Feedback? OK?
>> > 
>> > This doesn't scale.
>> What exactly does not scale?  The way how various drivers hook into
>> apm(4)?  I'm not familiar enough (yet) with the framework(s) to judge
>> their overall design and/or interop strategy off hand.
>
> Since there is no firmware abstraction like on i386 (and to some
> extent amd64) there will be many drivers that provide battery
> informarion on armv7/arm64.
>
>> > The whole apm(4) interface is too closely tied to the original APM
>> > BIOS model.  Even with acpi(4) it is a bit of a square peg for a round
>> > hole, for example on machines with more than one battery.
>> Right, there is hardware which doesn't fit this model and our apm* is
>> not exactly up to speed with those, but I still don't see actual issues
>> (as per above).
>> 
>> > I'm not even sure apm(8) should bother reporting some sort of battery
>> > status.
>> apm* showing battery information seems only naturally to me since that
>> is the driver/daemon/tool one issues power commands with, often based
>> on such information - think of `apmd -z 15':  given that I want my box
>> to safely suspend around 15% remaining battery, it seems only
>> consequential that apm* is the same tool I query such information with.
>
> apmd(8) and apm(8) are not the same tool though.  Having a deamon to
> run scripts on certain power-state changes makes some sense, but I'd
> argue that sensorsd(8) could be a reasonable place to implement this
> as well.

When I dived into the apm(4) and apmd(8) code I noted how redundant it
was considering sensorsd(8).  But the user interface of sensorsd(8)
needs a fair bit of pondering before it can be proposed as
a replacement.  sensorsd(8) is fairly generic and its configuration
format, while extensible, isn't easy to use.  To be fair I didn't even
try to make it execute stuff based on battery level.  I suspect it
would just be useful to execute commands based on changes in one driver,
when what you need to mimic apmd(8) is to merge the values coming from
different drivers.

> The need to run apmd(8) in order to suspend/hibernate is a bit of an
> historical wart.

It's not clear to me right now why this was needed and why it's not
needed anymore.

(I'm just talking about basic suspend/hibernate, not about the
nifty -z/-Z additions in apmd(8)).

> And we already removed powermanagement state support
> from apmd(8).  These days, users should probably just use
> /etc/sysctl.conf to set the powermanagement state instead of starting
> apmd(8) with the appropriate -A, -H or -L option.

Indeed, -A/-H/-L are just syntactical sugar.  I wouldn't mind seeing
them go.

>> > But if it does, my suggestion would be to make it use the
>> > sensors framework.  That would need some work though such that drivers
>> > can mark sensors as providing battery information.  Maybe add a
>> > SENSOR_FBATTERY flag?

Why the 'F' and not just SENSOR_BATTERY?

>> You mean apm(8) directly using sensor_find(9) or so to look for
>> suitable sensors instead of relaying values throuh apm(4)?
>
> That's a possibility.  But having apm(4) do that might be a useful
> middle ground as it would mean you don't have to change the userland
> tools just yet.

I'm not familiar at all with the sensors framework, but if presenting
the same simple apm(4) interface is doable using sensors, then you can
count me as a reviewer! :)

(I don't know where the apm(4) interface comes from, but it looks like
we have a bunch of ports also using it.)

> My main concern with your diff is having to add APM
> hooks in all the drivers...

Or maybe we need a nicer way to register APM hooks.  IIUC
apm_setinfohook was copied from miod's work on loongson where a single
driver is in charge, depending on the underlying hardware. So it
probably can't solve all use cases as is.

>> It sounds simpler in principal but that's just my naive guess;
>> I'll take a curious look

Re: arm64: make cwfg(4) report battery information to apm(4)

2021-03-21 Thread Klemens Nanni
On Sun, Mar 21, 2021 at 11:56:42AM -0600, Theo de Raadt wrote:
> The sensor framework generally does not know where a sensor is.  A
> sensor could reside on some device which has been plugged in, rather
> than be the primary sensor.
> 
> But the users of apm are only hoping for best effort.
> 
> meaning "some information", not "perfect information".  Many PC BIOS
> have lied in these fields before also, yet all the apm command users
> survived.
That's what my diff does really: best effort for some information.

> So which is better:
> 
> (1) try to emit some information for the people who quicky-use the apm 
> interface
> 
> (2) change apm to not print those lines on architectures where we are unsure.
> 
> I think (1) is acceptable for a tool which has never promised perfect 
> accuracy. 
I concur (obviously).

> I suspect hard-wiring this to one driver is going to be better than scanning
> the sensor list and heuristically determining which specific sensors to look 
> at,
> because the only good selector now is strcmp(sensor->desc, "battery remaining 
> minutes")
> yuck.
To be fair, kettenis proposed a rough idea to have simpler/faster checks
than strcmp().  With a simple flag you wouldn't need any heuristics
either but let the sensor framework -which has all the pieces- do the
work and put a stamp on the ready-to-use value saying "use this as
battery level".



Re: arm64: make cwfg(4) report battery information to apm(4)

2021-03-21 Thread Jeremie Courreges-Anglas
On Sun, Mar 21 2021, Klemens Nanni  wrote:
> apm(4/arm64) merely provides an all zero/unknown stub for those values,
> e.g. apm(8) output is useless.
>
> Hardware sensors however provide the information:
>
>   $ sysctl hw.sensors
>   hw.sensors.rktemp0.temp0=32.22 degC (CPU)
>   hw.sensors.rktemp0.temp1=33.89 degC (GPU)
>   hw.sensors.cwfg0.volt0=3.76 VDC (battery voltage)
>   hw.sensors.cwfg0.raw0=259 (battery remaining minutes)
>   hw.sensors.cwfg0.percent0=58.00% (battery percent)
>
> Diff below simply copies them over using apm_setinfohook()
> (I've looked at sys/arch/loongson/dev/kb3310.c which does the same):
>
>   $ apm
>   Battery state: high, 58% remaining, 259 minutes life estimate
>   A/C adapter state: not known
>   Performance adjustment mode: auto (408 MHz)
>
> Feedback? OK?

Feedback:

> Index: dev/fdt/cwfg.c
> ===
> RCS file: /cvs/src/sys/dev/fdt/cwfg.c,v
> retrieving revision 1.1
> diff -u -p -r1.1 cwfg.c
> --- dev/fdt/cwfg.c10 Jun 2020 17:51:21 -  1.1
> +++ dev/fdt/cwfg.c20 Mar 2021 23:43:13 -
> @@ -32,12 +32,15 @@
>  #include 
>  #include 
>  
> +#include 
>  #include 
>  
>  #include 
>  
>  #include 
>  
> +#include "apm.h"
> +
>  #define  VERSION_REG 0x00
>  #define  VCELL_HI_REG0x02
>  #define   VCELL_HI_MASK  0x3f
> @@ -119,6 +122,18 @@ struct cfdriver cwfg_cd = {
>   NULL, "cwfg", DV_DULL
>  };
>  
> +int cwfg_apminfo(struct apm_power_info *info);

Why out of the #if NAPM > 0 check?

> +#if NAPM > 0
> +struct apm_power_info cwfg_power;
> +
> +int
> +cwfg_apminfo(struct apm_power_info *info)
> +{
> + bcopy(&cwfg_power, info, sizeof(*info));

There's no overlap between source and destination, better use memcpy.
(Else, better use memmove.)

> + return 0;
> +}
> +#endif
> +
>  int
>  cwfg_match(struct device *parent, void *match, void *aux)
>  {
> @@ -202,6 +217,12 @@ cwfg_attach(struct device *parent, struc
>  
>   sensor_task_register(sc, cwfg_update_sensors, 5);
>  
> +#if NAPM > 0
> + /* make sure we have the apm state initialized before apm attaches */
> + cwfg_update_sensors(sc);
> + apm_setinfohook(cwfg_apminfo);
> +#endif
> +
>   printf("\n");
>  }
>  
> @@ -324,6 +345,7 @@ cwfg_update_sensors(void *arg)
>   uint32_t vcell, rtt, tmp;
>   uint8_t val;
>   int error, n;
> + u_char bat_percent;
>  
>   if ((error = cwfg_lock(sc)) != 0)
>   return;
> @@ -348,6 +370,7 @@ cwfg_update_sensors(void *arg)
>   if ((error = cwfg_read(sc, SOC_HI_REG, &val)) != 0)
>   goto done;
>   if (val != 0xff) {
> + bat_percent = val;
>   sc->sc_sensor[CWFG_SENSOR_SOC].value = val * 1000;
>   sc->sc_sensor[CWFG_SENSOR_SOC].flags &= ~SENSOR_FINVALID;
>   }

If val == 0xff bat_percent is unitialized.  Note that in this error
condition the sensors code leaves sc->sc_sensor[CWFG_SENSOR_SOC].value
alone.

> @@ -363,6 +386,14 @@ cwfg_update_sensors(void *arg)
>   sc->sc_sensor[CWFG_SENSOR_RTT].value = rtt;
>   sc->sc_sensor[CWFG_SENSOR_RTT].flags &= ~SENSOR_FINVALID;
>   }
> +
> +#if NAPM > 0
> + cwfg_power.battery_state = bat_percent > sc->sc_alert_level ?
> + APM_BATT_HIGH : APM_BATT_LOW;

It's cool that this driver keeps track of the "alert level".  acpibat(4)
also does that on amd64, but the apm(4)-through-acpi(4) userland
interface just hardcodes levels:

/* running on battery */
pi->battery_life = remaining * 100 / capacity;
if (pi->battery_life > 50)
pi->battery_state = APM_BATT_HIGH;
else if (pi->battery_life > 25)
pi->battery_state = APM_BATT_LOW;
else
pi->battery_state = APM_BATT_CRITICAL;

Maybe the levels reported by hardware couldn't be trusted?  Or maybe
those hardcoded values were deemed good enough, back then.  Anyway, on
this new hardware I think it makes sense to just trust the exported
values and later act if we get reports.

> + cwfg_power.ac_state = APM_AC_UNKNOWN;

This kinda points out the need for an AC driver on this platform.
If done in another driver, the code will need to be changed.  But this
looks acceptable to me for now.

> + cwfg_power.battery_life = bat_percent;

So to keep apm and sensors in sync I think it would be better to reuse
the cached sc->sc_sensor[CWFG_SENSOR_SOC].value.

I don't know whether the error condition mentioned above happens
frequently with this driver.  Reporting APM_BATT_ABSENT (and similar for
sensors) would be useful, and could be done in a subsequent step.

What's the underlying hardware, does it involve a pluggable battery?

> + cwfg_power.minutes_left = sc->sc_sensor[CWFG_SENSOR_RTT].value;
> +#endif
>  
>  done:
>   cwfg_unlock(sc);
>

-- 
jca | P

Re: arm64: make cwfg(4) report battery information to apm(4)

2021-03-21 Thread Theo de Raadt
The sensor framework generally does not know where a sensor is.  A
sensor could reside on some device which has been plugged in, rather
than be the primary sensor.

But the users of apm are only hoping for best effort.

meaning "some information", not "perfect information".  Many PC BIOS
have lied in these fields before also, yet all the apm command users
survived.

So which is better:

(1) try to emit some information for the people who quicky-use the apm interface

(2) change apm to not print those lines on architectures where we are unsure.

I think (1) is acceptable for a tool which has never promised perfect accuracy. 

I suspect hard-wiring this to one driver is going to be better than scanning
the sensor list and heuristically determining which specific sensors to look at,
because the only good selector now is strcmp(sensor->desc, "battery remaining 
minutes")
yuck.


Mark Kettenis  wrote:

> > Date: Sun, 21 Mar 2021 17:22:05 +0100
> > From: Klemens Nanni 
> > 
> > On Sun, Mar 21, 2021 at 02:02:00PM +0100, Mark Kettenis wrote:
> > > > Date: Sun, 21 Mar 2021 01:02:53 +0100
> > > > From: Klemens Nanni 
> > > > 
> > > > apm(4/arm64) merely provides an all zero/unknown stub for those values,
> > > > e.g. apm(8) output is useless.
> > > > 
> > > > Hardware sensors however provide the information:
> > > > 
> > > > $ sysctl hw.sensors
> > > > hw.sensors.rktemp0.temp0=32.22 degC (CPU)
> > > > hw.sensors.rktemp0.temp1=33.89 degC (GPU)
> > > > hw.sensors.cwfg0.volt0=3.76 VDC (battery voltage)
> > > > hw.sensors.cwfg0.raw0=259 (battery remaining minutes)
> > > > hw.sensors.cwfg0.percent0=58.00% (battery percent)
> > > > 
> > > > Diff below simply copies them over using apm_setinfohook()
> > > > (I've looked at sys/arch/loongson/dev/kb3310.c which does the same):
> > > > 
> > > > $ apm
> > > > Battery state: high, 58% remaining, 259 minutes life estimate
> > > > A/C adapter state: not known
> > > > Performance adjustment mode: auto (408 MHz)
> > > > 
> > > > Feedback? OK?
> > > 
> > > This doesn't scale.
> > What exactly does not scale?  The way how various drivers hook into
> > apm(4)?  I'm not familiar enough (yet) with the framework(s) to judge
> > their overall design and/or interop strategy off hand.
> 
> Since there is no firmware abstraction like on i386 (and to some
> extent amd64) there will be many drivers that provide battery
> informarion on armv7/arm64.
> 
> > > The whole apm(4) interface is too closely tied to the original APM
> > > BIOS model.  Even with acpi(4) it is a bit of a square peg for a round
> > > hole, for example on machines with more than one battery.
> > Right, there is hardware which doesn't fit this model and our apm* is
> > not exactly up to speed with those, but I still don't see actual issues
> > (as per above).
> > 
> > > I'm not even sure apm(8) should bother reporting some sort of battery
> > > status.
> > apm* showing battery information seems only naturally to me since that
> > is the driver/daemon/tool one issues power commands with, often based
> > on such information - think of `apmd -z 15':  given that I want my box
> > to safely suspend around 15% remaining battery, it seems only
> > consequential that apm* is the same tool I query such information with.
> 
> apmd(8) and apm(8) are not the same tool though.  Having a deamon to
> run scripts on certain power-state changes makes some sense, but I'd
> argue that sensorsd(8) could be a reasonable place to implement this
> as well.
> 
> The need to run apmd(8) in order to suspend/hibernate is a bit of an
> historical wart.  And we already removed powermanagement state support
> from apmd(8).  These days, users should probably just use
> /etc/sysctl.conf to set the powermanagement state instead of starting
> apmd(8) with the appropriate -A, -H or -L option.
> 
> > > But if it does, my suggestion would be to make it use the
> > > sensors framework.  That would need some work though such that drivers
> > > can mark sensors as providing battery information.  Maybe add a
> > > SENSOR_FBATTERY flag?
> > You mean apm(8) directly using sensor_find(9) or so to look for
> > suitable sensors instead of relaying values throuh apm(4)?
> 
> That's a possibility.  But having apm(4) do that might be a useful
> middle ground as it would mean you don't have to change the userland
> tools just yet.  My main concern with your diff is having to add APM
> hooks in all the drivers...
> 
> > It sounds simpler in principal but that's just my naive guess;
> > I'll take a curious look into whether/how this could work.
> 



Re: arm64: make cwfg(4) report battery information to apm(4)

2021-03-21 Thread Mark Kettenis
> Date: Sun, 21 Mar 2021 17:22:05 +0100
> From: Klemens Nanni 
> 
> On Sun, Mar 21, 2021 at 02:02:00PM +0100, Mark Kettenis wrote:
> > > Date: Sun, 21 Mar 2021 01:02:53 +0100
> > > From: Klemens Nanni 
> > > 
> > > apm(4/arm64) merely provides an all zero/unknown stub for those values,
> > > e.g. apm(8) output is useless.
> > > 
> > > Hardware sensors however provide the information:
> > > 
> > >   $ sysctl hw.sensors
> > >   hw.sensors.rktemp0.temp0=32.22 degC (CPU)
> > >   hw.sensors.rktemp0.temp1=33.89 degC (GPU)
> > >   hw.sensors.cwfg0.volt0=3.76 VDC (battery voltage)
> > >   hw.sensors.cwfg0.raw0=259 (battery remaining minutes)
> > >   hw.sensors.cwfg0.percent0=58.00% (battery percent)
> > > 
> > > Diff below simply copies them over using apm_setinfohook()
> > > (I've looked at sys/arch/loongson/dev/kb3310.c which does the same):
> > > 
> > >   $ apm
> > >   Battery state: high, 58% remaining, 259 minutes life estimate
> > >   A/C adapter state: not known
> > >   Performance adjustment mode: auto (408 MHz)
> > > 
> > > Feedback? OK?
> > 
> > This doesn't scale.
> What exactly does not scale?  The way how various drivers hook into
> apm(4)?  I'm not familiar enough (yet) with the framework(s) to judge
> their overall design and/or interop strategy off hand.

Since there is no firmware abstraction like on i386 (and to some
extent amd64) there will be many drivers that provide battery
informarion on armv7/arm64.

> > The whole apm(4) interface is too closely tied to the original APM
> > BIOS model.  Even with acpi(4) it is a bit of a square peg for a round
> > hole, for example on machines with more than one battery.
> Right, there is hardware which doesn't fit this model and our apm* is
> not exactly up to speed with those, but I still don't see actual issues
> (as per above).
> 
> > I'm not even sure apm(8) should bother reporting some sort of battery
> > status.
> apm* showing battery information seems only naturally to me since that
> is the driver/daemon/tool one issues power commands with, often based
> on such information - think of `apmd -z 15':  given that I want my box
> to safely suspend around 15% remaining battery, it seems only
> consequential that apm* is the same tool I query such information with.

apmd(8) and apm(8) are not the same tool though.  Having a deamon to
run scripts on certain power-state changes makes some sense, but I'd
argue that sensorsd(8) could be a reasonable place to implement this
as well.

The need to run apmd(8) in order to suspend/hibernate is a bit of an
historical wart.  And we already removed powermanagement state support
from apmd(8).  These days, users should probably just use
/etc/sysctl.conf to set the powermanagement state instead of starting
apmd(8) with the appropriate -A, -H or -L option.

> > But if it does, my suggestion would be to make it use the
> > sensors framework.  That would need some work though such that drivers
> > can mark sensors as providing battery information.  Maybe add a
> > SENSOR_FBATTERY flag?
> You mean apm(8) directly using sensor_find(9) or so to look for
> suitable sensors instead of relaying values throuh apm(4)?

That's a possibility.  But having apm(4) do that might be a useful
middle ground as it would mean you don't have to change the userland
tools just yet.  My main concern with your diff is having to add APM
hooks in all the drivers...

> It sounds simpler in principal but that's just my naive guess;
> I'll take a curious look into whether/how this could work.



Re: arm64: make cwfg(4) report battery information to apm(4)

2021-03-21 Thread Klemens Nanni
On Sun, Mar 21, 2021 at 02:02:00PM +0100, Mark Kettenis wrote:
> > Date: Sun, 21 Mar 2021 01:02:53 +0100
> > From: Klemens Nanni 
> > 
> > apm(4/arm64) merely provides an all zero/unknown stub for those values,
> > e.g. apm(8) output is useless.
> > 
> > Hardware sensors however provide the information:
> > 
> > $ sysctl hw.sensors
> > hw.sensors.rktemp0.temp0=32.22 degC (CPU)
> > hw.sensors.rktemp0.temp1=33.89 degC (GPU)
> > hw.sensors.cwfg0.volt0=3.76 VDC (battery voltage)
> > hw.sensors.cwfg0.raw0=259 (battery remaining minutes)
> > hw.sensors.cwfg0.percent0=58.00% (battery percent)
> > 
> > Diff below simply copies them over using apm_setinfohook()
> > (I've looked at sys/arch/loongson/dev/kb3310.c which does the same):
> > 
> > $ apm
> > Battery state: high, 58% remaining, 259 minutes life estimate
> > A/C adapter state: not known
> > Performance adjustment mode: auto (408 MHz)
> > 
> > Feedback? OK?
> 
> This doesn't scale.
What exactly does not scale?  The way how various drivers hook into
apm(4)?  I'm not familiar enough (yet) with the framework(s) to judge
their overall design and/or interop strategy off hand.

> The whole apm(4) interface is too closely tied to the original APM
> BIOS model.  Even with acpi(4) it is a bit of a square peg for a round
> hole, for example on machines with more than one battery.
Right, there is hardware which doesn't fit this model and our apm* is
not exactly up to speed with those, but I still don't see actual issues
(as per above).

> I'm not even sure apm(8) should bother reporting some sort of battery
> status.
apm* showing battery information seems only naturally to me since that
is the driver/daemon/tool one issues power commands with, often based
on such information - think of `apmd -z 15':  given that I want my box
to safely suspend around 15% remaining battery, it seems only
consequential that apm* is the same tool I query such information with.

> But if it does, my suggestion would be to make it use the
> sensors framework.  That would need some work though such that drivers
> can mark sensors as providing battery information.  Maybe add a
> SENSOR_FBATTERY flag?
You mean apm(8) directly using sensor_find(9) or so to look for
suitable sensors instead of relaying values throuh apm(4)?

It sounds simpler in principal but that's just my naive guess;
I'll take a curious look into whether/how this could work.



Re: arm64: make cwfg(4) report battery information to apm(4)

2021-03-21 Thread Mark Kettenis
> Date: Sun, 21 Mar 2021 01:02:53 +0100
> From: Klemens Nanni 
> 
> apm(4/arm64) merely provides an all zero/unknown stub for those values,
> e.g. apm(8) output is useless.
> 
> Hardware sensors however provide the information:
> 
>   $ sysctl hw.sensors
>   hw.sensors.rktemp0.temp0=32.22 degC (CPU)
>   hw.sensors.rktemp0.temp1=33.89 degC (GPU)
>   hw.sensors.cwfg0.volt0=3.76 VDC (battery voltage)
>   hw.sensors.cwfg0.raw0=259 (battery remaining minutes)
>   hw.sensors.cwfg0.percent0=58.00% (battery percent)
> 
> Diff below simply copies them over using apm_setinfohook()
> (I've looked at sys/arch/loongson/dev/kb3310.c which does the same):
> 
>   $ apm
>   Battery state: high, 58% remaining, 259 minutes life estimate
>   A/C adapter state: not known
>   Performance adjustment mode: auto (408 MHz)
> 
> Feedback? OK?

This doesn't scale.

The whole apm(4) interface is too closely tied to the original APM
BIOS model.  Even with acpi(4) it is a bit of a square peg for a round
hole, for example on machines with more than one battery.

I'm not even sure apm(8) should bother reporting some sort of battery
status.  But if it does, my suggestion would be to make it use the
sensors framework.  That would need some work though such that drivers
can mark sensors as providing battery information.  Maybe add a
SENSOR_FBATTERY flag?


> Index: dev/fdt/cwfg.c
> ===
> RCS file: /cvs/src/sys/dev/fdt/cwfg.c,v
> retrieving revision 1.1
> diff -u -p -r1.1 cwfg.c
> --- dev/fdt/cwfg.c10 Jun 2020 17:51:21 -  1.1
> +++ dev/fdt/cwfg.c20 Mar 2021 23:43:13 -
> @@ -32,12 +32,15 @@
>  #include 
>  #include 
>  
> +#include 
>  #include 
>  
>  #include 
>  
>  #include 
>  
> +#include "apm.h"
> +
>  #define  VERSION_REG 0x00
>  #define  VCELL_HI_REG0x02
>  #define   VCELL_HI_MASK  0x3f
> @@ -119,6 +122,18 @@ struct cfdriver cwfg_cd = {
>   NULL, "cwfg", DV_DULL
>  };
>  
> +int cwfg_apminfo(struct apm_power_info *info);
> +#if NAPM > 0
> +struct apm_power_info cwfg_power;
> +
> +int
> +cwfg_apminfo(struct apm_power_info *info)
> +{
> + bcopy(&cwfg_power, info, sizeof(*info));
> + return 0;
> +}
> +#endif
> +
>  int
>  cwfg_match(struct device *parent, void *match, void *aux)
>  {
> @@ -202,6 +217,12 @@ cwfg_attach(struct device *parent, struc
>  
>   sensor_task_register(sc, cwfg_update_sensors, 5);
>  
> +#if NAPM > 0
> + /* make sure we have the apm state initialized before apm attaches */
> + cwfg_update_sensors(sc);
> + apm_setinfohook(cwfg_apminfo);
> +#endif
> +
>   printf("\n");
>  }
>  
> @@ -324,6 +345,7 @@ cwfg_update_sensors(void *arg)
>   uint32_t vcell, rtt, tmp;
>   uint8_t val;
>   int error, n;
> + u_char bat_percent;
>  
>   if ((error = cwfg_lock(sc)) != 0)
>   return;
> @@ -348,6 +370,7 @@ cwfg_update_sensors(void *arg)
>   if ((error = cwfg_read(sc, SOC_HI_REG, &val)) != 0)
>   goto done;
>   if (val != 0xff) {
> + bat_percent = val;
>   sc->sc_sensor[CWFG_SENSOR_SOC].value = val * 1000;
>   sc->sc_sensor[CWFG_SENSOR_SOC].flags &= ~SENSOR_FINVALID;
>   }
> @@ -363,6 +386,14 @@ cwfg_update_sensors(void *arg)
>   sc->sc_sensor[CWFG_SENSOR_RTT].value = rtt;
>   sc->sc_sensor[CWFG_SENSOR_RTT].flags &= ~SENSOR_FINVALID;
>   }
> +
> +#if NAPM > 0
> + cwfg_power.battery_state = bat_percent > sc->sc_alert_level ?
> + APM_BATT_HIGH : APM_BATT_LOW;
> + cwfg_power.ac_state = APM_AC_UNKNOWN;
> + cwfg_power.battery_life = bat_percent;
> + cwfg_power.minutes_left = sc->sc_sensor[CWFG_SENSOR_RTT].value;
> +#endif
>  
>  done:
>   cwfg_unlock(sc);
> 
> 



arm64: make cwfg(4) report battery information to apm(4)

2021-03-20 Thread Klemens Nanni
apm(4/arm64) merely provides an all zero/unknown stub for those values,
e.g. apm(8) output is useless.

Hardware sensors however provide the information:

$ sysctl hw.sensors
hw.sensors.rktemp0.temp0=32.22 degC (CPU)
hw.sensors.rktemp0.temp1=33.89 degC (GPU)
hw.sensors.cwfg0.volt0=3.76 VDC (battery voltage)
hw.sensors.cwfg0.raw0=259 (battery remaining minutes)
hw.sensors.cwfg0.percent0=58.00% (battery percent)

Diff below simply copies them over using apm_setinfohook()
(I've looked at sys/arch/loongson/dev/kb3310.c which does the same):

$ apm
Battery state: high, 58% remaining, 259 minutes life estimate
A/C adapter state: not known
Performance adjustment mode: auto (408 MHz)

Feedback? OK?

Index: dev/fdt/cwfg.c
===
RCS file: /cvs/src/sys/dev/fdt/cwfg.c,v
retrieving revision 1.1
diff -u -p -r1.1 cwfg.c
--- dev/fdt/cwfg.c  10 Jun 2020 17:51:21 -  1.1
+++ dev/fdt/cwfg.c  20 Mar 2021 23:43:13 -
@@ -32,12 +32,15 @@
 #include 
 #include 
 
+#include 
 #include 
 
 #include 
 
 #include 
 
+#include "apm.h"
+
 #defineVERSION_REG 0x00
 #defineVCELL_HI_REG0x02
 #define VCELL_HI_MASK  0x3f
@@ -119,6 +122,18 @@ struct cfdriver cwfg_cd = {
NULL, "cwfg", DV_DULL
 };
 
+int cwfg_apminfo(struct apm_power_info *info);
+#if NAPM > 0
+struct apm_power_info cwfg_power;
+
+int
+cwfg_apminfo(struct apm_power_info *info)
+{
+   bcopy(&cwfg_power, info, sizeof(*info));
+   return 0;
+}
+#endif
+
 int
 cwfg_match(struct device *parent, void *match, void *aux)
 {
@@ -202,6 +217,12 @@ cwfg_attach(struct device *parent, struc
 
sensor_task_register(sc, cwfg_update_sensors, 5);
 
+#if NAPM > 0
+   /* make sure we have the apm state initialized before apm attaches */
+   cwfg_update_sensors(sc);
+   apm_setinfohook(cwfg_apminfo);
+#endif
+
printf("\n");
 }
 
@@ -324,6 +345,7 @@ cwfg_update_sensors(void *arg)
uint32_t vcell, rtt, tmp;
uint8_t val;
int error, n;
+   u_char bat_percent;
 
if ((error = cwfg_lock(sc)) != 0)
return;
@@ -348,6 +370,7 @@ cwfg_update_sensors(void *arg)
if ((error = cwfg_read(sc, SOC_HI_REG, &val)) != 0)
goto done;
if (val != 0xff) {
+   bat_percent = val;
sc->sc_sensor[CWFG_SENSOR_SOC].value = val * 1000;
sc->sc_sensor[CWFG_SENSOR_SOC].flags &= ~SENSOR_FINVALID;
}
@@ -363,6 +386,14 @@ cwfg_update_sensors(void *arg)
sc->sc_sensor[CWFG_SENSOR_RTT].value = rtt;
sc->sc_sensor[CWFG_SENSOR_RTT].flags &= ~SENSOR_FINVALID;
}
+
+#if NAPM > 0
+   cwfg_power.battery_state = bat_percent > sc->sc_alert_level ?
+   APM_BATT_HIGH : APM_BATT_LOW;
+   cwfg_power.ac_state = APM_AC_UNKNOWN;
+   cwfg_power.battery_life = bat_percent;
+   cwfg_power.minutes_left = sc->sc_sensor[CWFG_SENSOR_RTT].value;
+#endif
 
 done:
cwfg_unlock(sc);