Jan 262015

FreeBSD battery logo[1] While I’m still using the free HP/Compaq nx6310 notebook a friend has given me, I ran into a little problem during actual productive use with FreeBSD 10.1 UNIX. A problem that also affects more modern HP notebooks like the EliteBook or ProBook series as well as certain Macbooks as I learned only later. The issue lies within the battery status reporting. While the very first state transition will be recognized, as in say you disconnect the AC cable, or the charge drops by 1% or whatever, subsequent changes are completely ignored.

An example: You want to join a meeting with 100% charge. You disconnect the AC cable, an event that is still recognized by the system. The charge may then stand at 99%. It would however not update further, but just stay there until either a reboot or until the lights just go dark. Not good if you intend to actually use the system on the go. The user just needs to be aware of the battery level!

1.) The right direction, but still a fruitless attempt

So I read that HP has quite some share of trouble with Windows-specific and also buggy ACPI BIOS code, and thus, this has been a pain for some time, not just on FreeBSD, but also Linux and in some cases even Windows.

At first I [reported the issue in the FreeBSD forums], after which I was asked to report the problem on the [freebsd-acpi@freebsd.org] mailing list. Problem only was that one can’t post anonymously and the registration never worked for me. So I kept digging in the dirt, and my first attempt was to fix the ACPI code of course, or DSDT as it’s called – the Differentiated System Description Table, written in ASL – the ACPI Source Language. Basically a pretty creepy byte code language providing a bidirectional interface between the operating system and the systems BIOS/UEFI, which in turn controls certain aspects of the hardware. Think display brightness adjustments, WiFi on/off switches, audio volume control via keyboard, sleep buttons etc. – all that is ACPI. You can find the specs [here] if you really want to take a look.

HP compiled the code using [Microsofts ASL compiler], which is known to be rather sloppy and ignore tons of bugs in the code when compiling. So my first step was to dump the active DSDT from the systems memory using acpidump and tell the tool to disassemble it using Intels ASL compiler iasl in the same step:

# acpidump -d > ~/nx6310-stock.asl

Then, I attempted to recompile using the Intel ASL compiler again:

# iasl ~/nx6310-stock.asl

And then came the errors and warnings. Plus some nasty OS-specific code. Since an operating system can and will identify itself to the BIOS via ACPI, one can unfortunately filter by operating system on the BIOS level. Very bad stuff. Like this, taken from the ASL code directly, as written by HP:

expand/collapse source code
  1. Name (C015, Package (0x08)
  2. {
  3.      "Microsoft Windows",
  4.      "Microsoft WindowsME: Millennium Edition",
  5.      "Microsoft Windows NT"
  6. })


  1. If (LOr (LEqual (C014, 0x00), LEqual (C014, 0x03)))
  2. {
  3.      If (CondRefOf (\_OSI, Local0))
  4.      {
  5.           If (\_OSI ("Windows 2001"))
  6.           {
  7.                Store (0x04, C014)
  8.           }
  10.           If (\_OSI ("Windows 2001 SP1"))
  11.           {
  12.                Store (0x04, C014)
  13.           }
  15.           If (\_OSI ("Windows 2001 SP2"))
  16.           {
  17.                Store (0x05, C014)
  18.           }
  20.           If (\_OSI ("Windows 2006"))
  21.           {
  22.                Store (0x06, C014)
  23.           }
  24.      }
  25. }

Next logical step was to fake the OS FreeBSD was reporting to the ACPI subsystem. You can either do that by changing and embedding the ASL (non-MS OS strings are for instance “FreeBSD” or “Linux”), or luckily also by adding something like the following line to /boot/loader.conf, after which you need to reboot:

hw.acpi.osname="Windows 2006"

That didn’t do the trick for me however, so I tried to run my modified ACPI code after all. To do that you need to recompile the ASL, and then have loader pick it up in the early boot sequence of the kernel. First, I compiled the fixed code:

# iasl -tc ~/nx6310.asl

The result will be /tmp/acpidump.aml (for whatever reason). I placed it in /boot/ and added the following to /boot/loader.conf:

  1. acpi_dsdt_load="YES"
  2. acpi_dsdt_name="/boot/nx6310.aml"

Now another reboot. To verify the AML gets loaded, boot the kernel in verbose mode, you can choose that option in the boot loader. It’ll show something like Preloaded acpi_dsdt "/boot/nx6310.aml" at 0xc18dcc34. in /var/log/messages.

In my case however, while the AML was indeed being loaded, the BIOS’ tables were strangely not overwritten. I never found out why. Dumping them again would just give me the bugged code by HP. So that seemed to be dead end.

2.) The solution

Then I discovered that this might actually be a problem with the FreeBSD kernel itself by stumbling over [problem report 162859] in FreeBSDs bugzilla. It seems there was a problematic commit to the kernels ACPI subsystem written by Jung-uk Kim, initially for FreeBSD 9.0 in 2011: [r216942]. By now, he had provided two patches for it, of which I tried the [newer one] unsuccessfully, making the problem even worse. You can see my replies under my real name “Michael Lackner” in that PR.

Luckily, it was seemingly my complaint on top of the others that made Jung-uk Kim revert the [original patch], all back to how it was in FreeBSD 8.0, which some people reported to work just fine. So I got the now reverted/fixed code from [r277579] – a file named acpi_ec.c, and replaced /usr/src/sys/dev/acpica/acpi_ec.c with it. Then, I recompiled the FreeBSD kernel [as described in the FreeBSD handbook] once more (fear not, it’s actually very easy).

Reboot, and everything just worked! No need for a DSDT replacement or operating system faking even. I tested charge, discharge, AC cable dis-/reconnect and full charge states. All ok now! Finally, that book is now 100% ready for production use! :)

I mean, let’s not make any mistake here, the ACPI code from HP is still buggy. But like the Linux kernel, the FreeBSD kernel knows how to sail around the most severe bugs, including Microsoft-specific code in certain cases, at least now that this issue is fixed.

Thanks fly out to Jung-uk Kim for reverting the problematic patch! It should be merged from current any day now. If you want to get it done faster than that, just fetch acpi_ec.c, place it in the right folder and recompile the kernel and with it all of its modules, just like I did.

[1] Original battery icon used for the logo is © Freepik from Flaticon and is licensed under CC BY 3.0

Dec 032014

HP/Compaq nx6310 logoRecently, a friend of mine gave me a free notebook for operating system testing. Well, actually I traded in two DDR-II sticks for it, but that’s still almost free. It’s an older HP/Compaq nx6310 in its low-end configuration with an i940GML chipset, Pentium-M based Celeron M430, a crappy hard drive, 2GB RAM (already upgraded from 512MB) and a DVD±RW burner. The worst part of that laptop was probably the terrible XGA (1024×768) TN+Film LCD panel. The thing came without WiFi too. The antennas were there with properly sealed plugs, but the WiFi module itself was missing in its PCIe mini slot. So I flashed in a nice [hacked Mod BIOS] from [MyDigitalLife] based on the latest Core 2 capable BIOS version F.0E to remove the WiFi card whitelist from the SLIC 2.1 enabled BIOS and plugged in a full-height 4965AGN card from Intel! Then gave it a Crucial m500 SSD which works miracles despite the slow-bandwidth SATA/1.5Gbps interface, and an Intel Core Duo T2450 processor for its Socket M, which is the fastest possible option for this book.

The CPU will only work with a single core on the i940GML chipset/cheapset, and only FSB533 chips will do, as I couldn’t find a way to program the clock generator for the front side bus. Still, given the clock speed of 2GHz and the 2MB L2 cache this is still the best option here, unless you need 64-Bit x86, for which a Core 2 Duo T5300 with 1.73GHz would be available.

If you know which modified BIOS to flash, the WiFi upgrade is very easy, and the CPU upgrade can also be done very quickly and conveniently, which is really nice. But then comes the LCD panel. The ugliest of the ugly in the already pretty ugly field of TN+Film panels with a very coarse grain look and limited space on screen due to the XGA 1024×768 resolution on 15″. An SXGA+ (1400×1050) WVA panel upgrade option identified by the HP part number 413679-001 exists though, which can replace this lower spec one going by the number 413677-001. Just make sure you also get the SXGA+ LVDS cable, as the default LVDS display cable will only work with the XGA screen! Plugging the XGA cable into the SXGA+ panel will yield nothing but an erratic white screen with horizontal lines. I learned that the hard way… Here’s the cables:

nx6310 LVDS display cables, left: SXGA+, right: XGA

nx6310 LVDS display cables, left: SXGA+, right: XGA

So I got the panel and an extra SXGA+ cable from eBay UK, and started with the disassembly, which can be tricky for the first time, as some parts like the display bezel can be prone to breaking. Also, besides a Phillips screwdriver, you will need a size T10 torx screwdriver for this. I would suggest consulting the nx6310s [HP service manual] for display assembly removal. It doesn’t cover everything, only the replacing of an entire display assembly, not the panel in it specifically, but it’s still very helpful. Just don’t disconnect the WiFi antenna cables as they’re asking for, and mind that the switch cover removal sequence is wrong; There is no “LED board cable” to remove for this machine, you can skip that. So let’s assume you followed that manual already for removal of the keyboard and switch cover, and let’s continue from there:

HP nx6310 with keyboard and switch cover removed

HP nx6310 with keyboard and switch cover removed

The copper plate near the middle, just left of the internal memory slot covers the chipset, to the lower left we can see the CPU hotplate from which a heatpipe transfers heat to the cooler/radiator on the top left. All of that is easy to remove and reassemble if you want to replace the processor too. On the display bezel you can already see some screws being visible. All of the screws facing you on the display frame are covered by rubber seals, remove them all. There are also four thin film seals on the sides of the display assembly, two on each side. Get rid of them too.

Now remove all screws on the display assembly and tilt the whole display as far back as possible. Try to stick a flat screwdriver between the two plastic halves (front/back) at the bottom and push the front bezel off the back. Be careful, as the front bezel is especially prone to breaking. The first attempt should be made near the hinges, as it’s easiest and safest there. Then, it might be better not to try and stick the screwdriver in at a 90° angle. Try to do it at a steeper angle, between 20-40°, and push it in a few millimeters deep! Try to lift it up not from the side, but from beneath the bezel frame using leverage. You’ll push against the metal frame of the LCD panel below. There is no electronics there you can damage, so this should be safe. Just work slowly and carefully.

Also, double-check whether you removed all the side screws, or you may break some plastic holders of the front bezel by trying to lift it off with the screws still in place! When you’re at the top side, slide the locking mechanism while pushing the bezel off, or it’ll block you.

Now, with the bezel gone, you’ll see a small white tube on the lower side of the panel. That’s the high-voltage AC inverter board that powers the CCFL lamp for lighting up the display panel. Disconnect both cables attached to it, and just put it away somewhere for now:

The inverter board disconnected

The inverter board disconnected

Also, remove the display cable itself. You can just pull it out, it won’t be too hard, so you can’t really damage the cable. Its beneath the now-removed switch cover, in the area where you’d find the power button:

nx6310 with the old XGA cable still attached

nx6310 with the old XGA cable still attached

After bezel removal, there will be four additional screws that hold the panel frame and the rear cover together, one in each corner of the display assembly, facing you directly. Remove them, and let the rear cover slide away carefully. Don’t use force here, or you may damage the WiFi antennas:

The panel and the rear cover separating

The panel and the rear cover separating

The two cables taped to the rear cover are the WiFi antennas, just leave them alone. Pull the display cable plug out of the LVDS socket carefully, and remove the tapes, then just gently pull the cable out. You may want to remove and save the tapes for later if your SXGA+ doesn’t have its own. Now, there are two frames holding the panel. Tilt the panel so that it stands 90° upright to prevent it from just falling out during the next step. The two frames are screwed to the panel with four small screws on each side. Remove all the screws, then pull out the panel.

Put the new SXGA+ panel in, screw it to the frames, plug in and attach the new LVDS cable and it should look a bit like this:

New panel and cable installed

New panel and cable installed

To make the rear assembly feel stronger to the touch and make the cover less flexible, you might also put some filler material between rear cover and panel, as the new one might be a bit thinner. I used some light foam for that, but you can also just skip that part. Just screw everything back together in reverse order, reconnect the inverter board and push it into its seat in the reattached rear cover below the panel in the middle and don’t forget to attach the new LVDS cable to the system board too:

The new SXGA+ capable LVDS cable attached

The new SXGA+ capable LVDS cable attached

Now, finally: A side-by-side comparison:

Note that the colors look strangely whiteish for the SXGA+ when compared to the XGA. In real life, the white-shift is actually worse for the XGA, no idea why it looks like that on the photograph. Something with the polarization filters on the panels maybe?! Well, frankly, it’s still rather bad with the SXGA+, but not as bad as before. Also, the color space of those two photographs don’t match (again…) because I’m lazy and can’t handle my camera. Oh well. But the new panel is brighter now, which is a nice bonus, and as you can see, there is more space available on the desktop. Since the dpi are now higher, it also looks much more crisp and sharp, and it’s more matte than before, so reflections are reduced and you can work better in bright conditions. Overall, its a sound improvement!

On those pictures you can see FreeBSD 10 UNIX running a terminal emulator window and a Windows XP Pro VirtualBox machine on both panels. All windows were kept at the exact same dimensions, so you can assess the resolution difference properly.

I would also like to add that before learning about the cables, I went on a crazy journey to flash the EDID EEPROM of the panel in an attempt to get it to work, which finally went ok using a hex editor and some [hacked script] for [edid-rw] on Debian 7 Linux, because those panels don’t speak the DDC protocol required by other tools for Windows and DOS. In the end, I managed to write a new vendor string and some other strings to the EDID EEPROM firmware of the panel, which now shows it being manufactured by QDS (QUANTA computer) instead of APP (Apple). Well, just forget about all that. Certain Lenovo Thinkpad upgrade paths might require you to flash the displays’ EDID EEPROM, but this one here doesn’t! It’s all just about the cable.

Now I gotta say, the “free notebook” ain’t so free anymore when it comes to money invested (CPU, WiFi, and LVDS cable were below or around 10€ each, but the SSD was 70€ and the panel 55€ or so), but I’m still quite pleased with my work enhancing the “crappy” book. I’ll also keep FreeBSD for now, I strangely kinda like it after testing a few others natively, like Haiku OS or OpenBSD UNIX 5.6, just for fun. But yeah, with 1400×1050 and an SSD, this is thing feels pretty nice!

I hope this may help somebody other than me, because the EDID flashing suggested by some people leads nowhere for these HP series, and many sellers on ebay just sell you the panel for already SXGA+ equipped books without any mention of the cable, let alone an included cable! So if you can’t get your upgrade to work, the cable is probably why!

PS.: OpenBSD 5.6, you’re damn cool, especially with OpenJDK/Java now being back again! But sadly, I still need wine, so I’ll have to turn the other way again. :(