ThinkPad battery charge control

Tamas Szakaly sghctoma at
Wed Nov 2 16:31:22 UTC 2011


Two weaks ago a conversation started at freebsd-mobile about battery charge
limiting. During this weekend I had some time to look up the ThinkPad 770
Technical Reference Manual
(, the
ThinkPad Power Manager for Windows XP, and the tp_smapi Linux driver

I managed to write a kernel module that exposes the ThinkPad SMAPI features
via the following sysctls:
 - hw.thinkpad_smapi.batX.start_threshold: charge start threshold (0-100)
 - hw.thinkpad_smapi.batX.stop_threshold: charge stop threshold (0-100)
 - hw.thinkpad_smapi.batX.force_discharge: enable/disable force discharge (0,1)
 - hw.thinkpad_smapi.batX.inhibit_charge_minutes: inhibit charge for given
   minutes (0-65535)
X can be 0 or 1.

The module works OK, but I have very-very little experience with kernel
programming (added some sysctls to psm.c to control TrackPoint behaviour a year
ago), and I have some concerns about how this functionality should be
implemented correctly:
 - Is the sysctl way OK? Or should I expose those features via ioctl or
   character device read/write functions?
 - To access SMAPI, one have to write two I/O ports, 0xb2 and 0x4f. My problem
   is the following: the code works without mapping/allocating those two I/O
   ports, but I think, they should be mapped/allocated nevertheless. Am I right?
 - I used the term map/allocate, because I don't know what function to use
   to achieve this. At first I was using bus_space_map/bus_space_unmap like
   bus_space_map(X86_BUS_SPACE_IO, port, 1, 0, &bsh1)
   bus_space_map(X86_BUS_SPACE_IO, SMAPI_PORT, 1, 0, &bsh2)
   bus_space_unmap(X86_BUS_SPACE_IO, bsh1, 1)
   bus_space_unmap(X86_BUS_SPACE_IO, bsh2, 2)
   But neither of the drivers I saw use this pair of functions. Every one of
   them uses bus_alloc_resource/bus_release_resource. So I tried those functions
   as well:
   in identify:
   bus_set_resource(child, SYS_RES_IOPORT, 0, port, 1);
   bus_set_resource(child, SYS_RES_IOPORT, 1, SMAPI_PORT, 1);

   in probe:
   if (bus_get_resource_start(dev, SYS_RES_IOPORT, 0) == 0)
   if (bus_get_resource_start(dev, SYS_RES_IOPORT, 1) == 0)

   in attach:
   sc->rid1 = 0;
   sc->res1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid1,
       port, port, 1, RF_ACTIVE);

   sc->rid2 = 1;
   sc->res2 = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid2,
   But the allocation fails. devinfo -r tells me, that I/O port 0xb2 is
   already allocated by acpi. So I tried to make acpi my driver's parent:

   DRIVER_MODULE(thinkpad_smapi, acpi, ...
   After this the allocation works, devinfo -r tells, that 0xb2 and 0x4f is
   allocted by my driver. But when I unload the module, and try to load it
   again, it fails. Please note, that bus_release_resource is called
   upon unloading the module and devinfo -r shows that 0xb2 is allocated
   by acpi again. What am I doing wrong?

Sorry for the overly-long mail, and the possibly newbie questions, but I have
read lots of man(9) pages, mailing list threads, and sources of drivers, and
I am still confused. Any help is well appreciated. 
Thank you in advance!



More information about the freebsd-drivers mailing list