I just recently bought a lenovo X121e laptop. Its a small laptop, but the battery life is great!
I installed Ubuntu Gnome 16.10 on it, and didn’t really notice anything wrong for awhile, because I rarely use bluetooth on my laptop. But I wanted to test the 3G capabilities of the machine, and that is when I fell down the rabbit hole 🙂
So even though I tried enabling the mobile broadband, wwan, 3g, (call it what you like) it just didn’t work.
First thing I tried:
rfkill unblock all
but still I got this:
0: tpacpi_bluetooth_sw: Bluetooth
Soft blocked: no
Hard blocked: yes
1: tpacpi_wwan_sw: Wireless WAN
Soft blocked: no
Hard blocked: yes
2: phy0: Wireless LAN
Soft blocked: no
Hard blocked: no
Reading up on this, it seems others have encountered this problem. The “fix” is upgrading the BIOS to the latest version, then resetting to default values, which will clear the wwan and bluetooth on/off state. Unfortunately if you are using UEFI like me, this will also wipe your boot entries 🙂 While this can be fixed quite easily, the problem is this fix is only temporal. Reboot with low battery and in will get hard-locked again.
This whole problem seems to come from the hotkey utility which is implemented on windows, and controls the state of the “hard locks”. Now these seem to default to locked or something.
Installing windows, and booting into it to “enabled WWAN” all the time, is not a solution for me. Resetting the BIOS and re-enabling my EFI bootloader every few reboots also does not cut it.
I’ve used up all my google skills, and it seems like there is no proper solution. So this means its time to start reverse engineering the hotkey tool, and trying to write something which will implement this functionality on linux. 🙂
There is a long road ahead, but I will keep updating this post as I make progress.
Day 1. Searching far and wide:
Lenovo Hotkey tool on Windows ——– Technical information
The command line control for Wireless switching hot key (Fn+F5) feature. It is available to control the wireless radio using the following command; C:\Program Files\Lenovo\HOTKEY\TpFnF5.exe [PARAMETER]
The following parameters are defined;
/WLON, /WLOFF Turn on/off internal 802.11.
/BTON, /BTOFF Turn on/off internal bluetooth.
/WANON, /WANOFF Turn on/off internal WAN.
/UWBON, /UWBOFF Turn on/off internal UWB.
/ALLON, /ALLOFF Turn on/off any radio at once.
Day 2. Switching from Ubuntu Gnome to default Ubuntu setup:
So this day 2 is actually quite a few days later, I removed the Ubuntu Gnome from my system because it was too buggy for me to use, even though I love the design. Installing in on my system, I reset my bios, and tested out the 3G which did not work on Ubuntu Gnome, and what a suprise! It worked on Ubuntu, because they use a different network manager. So with this happy news, and some freetime on my hands having finished with my exams, I decided to take the plunge and do some more work finding out the source of this problem. So again, every time the bios gets reset things start working again, but then if you remove the battery or the battery level drops down to 0% the 3G and bluetooth will get hardblocked. So with this info I got to work and starting looking into the ACPI modules on the system. I had a thought that the state of these switches must be stored in the BIOS, and might just be exported to the user via UEFI variables. I took a “snapshot” of all the UEFI variables when bluetooth was working, I then removed my battery and took another “snapshot” of the variables to see what had changed. Two entries were different. I had my hopes up, thinking these must hold the values, but then I reset the bios, took another snapshot, and along with lots of other values, these had changed again, and not back to the same values as the first snapshot, but again something completely different. 🙁 So too bad, this will not solve my problems.
At this point I got quite disappointed as I had spent quite a bit of time fixing my system as it would not start after I took my battery out, had to do an
fsck -y on it, to fix the system, as it kept complaining about not being able to connect to
lvmtad (I use lvm). But, no time to stop, so I took a look at the
thinkpad_acpi kernel module in the linux kernel source (drivers/platform/x86/thinkpad_acpi.c) From this, and also later using
modinfo thinkpad_acpi command I got some usefull info about the kernel module. It gives you a list of all the parameters you can specify to customise the way that the kernel module works. Now the cool thing is that this kernel module has a switch emulation, which basically doesn’t really care what the bios says, it will emulate the switch to whatever you specify. If we tell it to be on, it will be on. So if we go to
/etc/modprobe.d/folder, where the conf files are located for the various kernel modules that our system uses, we can add a file called
thinkpad_acpi.confand inside it, we add the following command:
options thinkpad_acpi dbg_bluetoothemul=1 bluetooth_state=1
And here if we reboot our system, when the kernel module gets loaded it will use these parameters.
After booting up the system try doing this:
dmesg | grep thinkpad_acpiwe can see the debug output of the kernel module when it is loaded. Mine says:
ThinkPad ACPI Extras v0.25 and then some model info etc. And if you followed the instructions correctly you will see a line saying:
bluetooth switch emulation enabled Try running
rfkill listyou will now actually see 2 bluetooth devices, one by the name of
hci0 and another one called
tpacpi_bluetooth_sw. Try turning on your system bluetooth 🙂 Magic…
The sad part though, is even though the module has switch emulation for not just bluetooth, but WWAN, WLAN, UWB, etc. It won’t work on the 3G modem (WWAN). Even if you enable the switch, it won’t connect to my mobile network 🙁 So I still have not found a perfect fix, but atleast now bluetooth is working.
What I do now, is carry a usb drive around with my with Refind Linux. This way, if the 3G / Bluetooth stops working, I just reset the BIOS, and boot up from the USB drive, which will find my ubuntu installed on my laptop. Then all I have to type is
apt install --reinstall grub-efi-amd64and the uefi boot option is back in place. The whole process takes less than a minute, so its not a huge deal, and much better than having a windows installed just for doing this.
But, this is still not the best solution, so if I have some more time, I’ll try to look more into the source of the kernel module, and see if I can debug why the switch emulation is not working. But for now, this is the best I can do, hope it helps you guys!