ThinkPad battery charge control
sghctoma at gmail.com
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
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
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
- 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
bus_set_resource(child, SYS_RES_IOPORT, 0, port, 1);
bus_set_resource(child, SYS_RES_IOPORT, 1, SMAPI_PORT, 1);
if (bus_get_resource_start(dev, SYS_RES_IOPORT, 0) == 0)
if (bus_get_resource_start(dev, SYS_RES_IOPORT, 1) == 0)
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,
SMAPI_PORT, SMAPI_PORT, 1, RF_ACTIVE);
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