SMBus Intel Apollo Lake Driver Information

Hello all,

Anyone have any information on the driver provided by Intel for the Apollo Lake SMBus? It comes with the chipset install, but I am unable to find any documentation or a .h for usage anywhere. I have reached out to them with no luck so far. A board I am working with has a PWM located on the SMBus that I need to access from Windows.

New to the forum, so if this is the wrong place for an inquiry like this please just let me know.


It’s possible someone here knows, but Intel has their own set of forums:

It’s the right place to ask the question, but I’ll be surprised if anybody here can give you then answer.

Does it really have a driver installed? Because that’s pretty rare. In my experience, the SMBus is used for boot-time stuff (like configuring the DDR) and after that, isn’t accessed. The INF typically indicates the infamous “NO_DRV” as the driver.


Thanks for the link Tim.

Upon closer inspection I think you are correct Peter. Thanks for the information.

An SMBus controller driver is reasonably simple to write. The problem is that you don’t really know what’s happening with that control from the BIOS side of the world. The BIOS typically assumes that “nothing else” is using the controller (because there’s NO_DRV loaded). So it may use the SMBus controller without respecting the interlocks that are typically available for this purpose.

So, it’s sort of a problem. In general, it is not a solvable problem, and not “safe” to write your own SMBus driver if you’re targeting general purpose systems. You’re better off connecting your device someplace else. OTOH, if you’re dealing with a closed system of which you have 100% control… that’s a different issue.


Can’t spin the board and move the device to another interface at the moment. I have access to the BIOS on this device. On the fence as far as whether to flesh out the ACPI a little more for the device and create a driver for the ACPI device, or just make sure the BIOS isn’t using the SMBus for anything else and write a Windows SMBus driver.


Everything I write from now on will assume you’re using a system in a “closed” environment – That is, you’re not creating a general-purpose solution.

Your question caused me to look back at some ancient code I wrote 10+ years ago. At that time, I did an R&D project involving a proprietary device on the SMBus, on a closed system. For the project (using a standard white-box machine), the BIOS provided SMBus-specific ACPI methods that allowed me to read/write registers on attached peripheral devices (_SBR and _SBW) – This was all documented in something called the SMBus Control Method Interface (CMI) spec, which is “standardized” and public.

This avoided my having to write a host-side controller driver and gave me the HOPE that the ACPI-side of the world did all the right synchronization.

I wrote a (reasonably simple) driver that exported IOCTLs to user-mode and serviced those IOCTLs by evaluating ACPI methods.

I have no idea if the ACPI BIOS in more modern Windows systems still includes these methods… but I wouldn’t be surprised to discover that it did. You know, once standardized, and somebody’s using it somewhere… it can never disappear :wink:

I hope that helps,


ETA: Comments about modern Windows systems having these same methods in the BIOS.

I will go down the route of exposing ACPI methods via a driver for now. Sounds a bit safer and easier, and there do appear to be methods for the bus already. Thanks for the help Peter!

there do appear to be methods for the bus already

You realize that you probably don’t need to do anything to expose these, right? You can just call them using IOCTL_ACPI_EVAL_METHOD and friends? Just instantiate a driver in the SMBus controller stack.

I just didn’t want to leave that unstated, in case it’s something you missed.


Makes sense. I will utilize those in the driver. Do you know what the difference/s between the regular, v1, and v2 IOCTLS is/are?

Anyone have any thoughts on why IOCTL_ACPI_EVAL_METHOD would return STATUS_NOT_IMPLEMENTED?

NTSTATUS				                                     status = STATUS_SUCCESS;

WDFDEVICE                                                            pDevice = WdfIoQueueGetDevice(Queue);
UCHAR                                                                    brightnessVal = 0;
ACPI_EVAL_OUTPUT_BUFFER                              outputBuf;
WDF_MEMORY_DESCRIPTOR                              inputDesc;
WDF_MEMORY_DESCRIPTOR                              outputDesc;
ULONG_PTR                                                           bytesReturned;

        RtlZeroMemory(&inputBuf, sizeof(inputBuf));

        inputBuf.MethodNameAsUlong = (ULONG)('MLCB'); // BCLM expressed little-endian
        inputBuf.IntegerArgument = (ULONG)brightnessVal;

        WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&inputDesc, &inputBuf, sizeof(inputBuf));

        RtlZeroMemory(&outputBuf, sizeof(outputBuf));
        WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDesc, &outputBuf, sizeof(outputBuf));

        if (WdfDeviceGetIoTarget(pDevice) == NULL)
            KdPrint((DRIVERNAME " +Get PDO target failed\n"));
            WdfRequestComplete(Request, status);


        status = WdfIoTargetSendInternalIoctlSynchronously(WdfDeviceGetIoTarget(pDevice), NULL, 

        if (status)
            KdPrint((DRIVERNAME " +Send Ioctl Failed %x\n", status));

Here is the ACPI code:

Device(BKPW) {
NAME(_HID, “ACPI0004”)
Method (BCLM, 0x1)


The driver is attaching to ACPI0004 without issue. Just not sure why the IOCTL is failing.


Hmmm… while I’m not in a position to compare your code to code that’s “known good” at the moment, my experience has been that these calls “just work”…. I do remember that formatting the input and output buffers was a PITA, though. Don’t know if that applies here. Sorry, I know that’s not optimally helpful (it’s a holiday week).

The only thing I can suggest offhand is to set a breakpoint in the AML and see what’s up. I’ve done this… it can be tedious, but it can also be useful.


1 Like

Ah, you’ve made an error that is very easy to make. IOCTL_ACPI_EVAL_METHOD needs to be sent as a normal ioctl (IRP_MJ_DEVICE_CONTROL), not as an internal ioctl (IRP_MJ_INTERNAL_DEVICE_CONTROL). You need WdfIoTargetSendIoctlSynchronously not WdfIoTargetSendInternalIoctlSynchronously.

I know that because I’ve done the same thing.

1 Like

LOL… excellent pickup, Mr. Roberts. Bravo on your sharp reading.


Thanks Tim! Sadly still getting the STATUS_NOT_IMPLEMENTED error after using WdfIoTargetSendIoctlSynchronously instead, but I’m sure that was going to cause other problems for me down the line.

Perhaps try one of the V1 or V2 sync or a sync variants?


Thanks Peter and Tim for the help! Turned out the STATUS_NOT_IMPLEMENTED issue boiled down to the HID I had chosen for the ACPI device. Changed it in the BIOS and updated my INF, and the IOCTL is working now.