Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hm1092-linux

A Linux driver for the Himax HM1092, the monochrome near-infrared sensor behind the Windows Hello face-unlock camera on Intel IPU6/IPU7 laptops. There is no support for this part anywhere upstream, in intel/ipu6-drivers, or in intel/ipu7-drivers — the sensor enumerates as an ACPI device, sits there unclaimed, and produces nothing.

Developed and tested on a Lenovo ThinkPad X9-14 Gen 1 (Lunar Lake, IPU7), kernel 7.1.

What you get

hm1092 v4l2 subdev driver: 1296x736 and 648x368, RAW10 mono, exposure / analogue + digital gain / vblank / test pattern
ipu-bridge rebuilt with HM1092 in its sensor table, plus a DMI quirk for the X9-14's inverted module
hm1092-capture one command from cold hardware to a PNG, illuminator included
hm1092-relay publishes the sensor as an 8-bit grayscale v4l2loopback node so OpenCV consumers (howdy, face unlock) can read it, lighting the emitter only while something is attached
NixOS module hardware.hm1092.enable = true;
DKMS for everyone else

Not done yet: no in-kernel driver for the LM3643 IR emitter, so nothing strobes it per-frame. hm1092-capture and hm1092-relay drive it in torch mode over i2c while they are capturing. See Illuminator.

Face unlock

hardware.hm1092 = {
  enable = true;
  relay = {
    enable = true;
    sink = "/dev/video45";   # a v4l2loopback node you allocate
    group = "howdy";         # not "video" — see below
    rotate180 = true;        # if the module is mounted inverted
  };
};

Point howdy's device_path at the sink and enrol. Two things to get right:

  • Re-enrol. Face models are wavelength-specific; anything trained against a visible-light camera will not match an IR frame.
  • Group. Whoever can open the sink's OUTPUT side can inject frames, and an injected frame is a face-unlock bypass needing neither a photo nor physical access. Give the node a group holding only the accounts allowed to authenticate, not video.

dlib's detector is not rotation invariant, which is why rotate180 matters: upside down it finds no face at all rather than a worse one.

Quick start — NixOS

{
  inputs.hm1092.url = "github:meros/hm1092-linux";

  outputs = { nixpkgs, hm1092, ... }: {
    nixosConfigurations.laptop = nixpkgs.lib.nixosSystem {
      modules = [
        hm1092.nixosModules.default
        { hardware.hm1092.enable = true; }
      ];
    };
  };
}

Rebuild and reboot — see ipu-bridge is boot-only. Then:

$ hm1092-capture --list
media device : /dev/media0
sensor       : hm1092 2-0024  (/dev/v4l-subdev5)
receiver     : Intel IPU7 CSI2 1
capture      : Intel IPU7 ISYS Capture 8  (/dev/video8)
i2c bus      : 2

$ sudo hm1092-capture -o face.png --exposure 796 --gain 240
captured 14 frames, 10-bit levels 8..771 -> face.png

Options worth knowing:

flag
--no-torch leave the illuminator off (expect a near-black frame)
--torch-brightness N LM3643 torch level, 0-127, default 40
--no-rotate skip the 180 degree flip
--raw no autoscaling, straight 10-to-8 bit truncation
--keep-raw PATH also keep the undecoded capture

Quick start — any distro

Build and install the sensor driver:

$ make -C src
$ sudo make -C src install

Or via DKMS, so it survives kernel updates:

$ sudo cp -r . /usr/src/hm1092-0.1.0
$ sudo dkms add -m hm1092 -v 0.1.0
$ sudo dkms install -m hm1092 -v 0.1.0

That alone is not enough: ipu-bridge still has to learn the sensor. Either patch and rebuild your kernel with patches/ipu-bridge-hm1092.patch, or build just that one module out of tree against your kernel source and drop it into updates/, where depmod prefers it over the in-tree copy:

$ cp /usr/src/linux/drivers/media/pci/intel/ipu-bridge.c build/
$ patch -d build -p4 < patches/ipu-bridge-hm1092.patch
$ echo 'obj-m += ipu-bridge.o' > build/Makefile
$ make -C /lib/modules/$(uname -r)/build M=$PWD/build modules
$ sudo install -D build/ipu-bridge.ko /lib/modules/$(uname -r)/updates/ipu-bridge.ko
$ sudo depmod -a && sudo reboot

The capture tool needs python3 (standard library only), v4l-utils and i2c-tools.

The hardware

Everything below was measured on the machine or recovered from Intel's Windows driver; nothing is guessed.

Sensor Himax HM1092, 1/9" 720p mono/NIR
ACPI HID HM1092 (HIMX1092 on some Dell machines)
i2c bus 2, address 0x24, 16-bit register addresses, 8-bit data
Chip ID reads 0x1091 from 0x0000/0x0001
CSI-2 link 1, 1 lane, RAW10
Link frequency 180 480 000 Hz (360.96 Mbit/s), pixel rate 36 096 000
Modes 1296x736 @ 30, 648x368 @ 30 and @ 60 (2x2 binned)
Timing full mode LLP 1508, FLL 798
MCLK 19.2 MHz, from INT3472:01-clk
Power avdd regulator plus a privacy LED from INT3472:01; no reset or powerdown GPIO
Illuminator TI LM3643 at 0x63 on the same bus

The link frequency is not documented anywhere; it falls out of the mode timing and cross-checks exactly:

1508 px * 798 lines * 30 fps * 10 bits = 360.96 Mbit/s over 1 lane
                                       = 180.48 MHz DDR clock

and the ACPI SSDB independently reports link 1, lanes 1, mclk 19200000 Hz.

Gotchas

These cost real time, so they are worth stating plainly.

The part has no register auto-increment

In either direction. A 16-bit read of the chip ID at 0x0000 returns 0x10 followed by a bus-idle 0xff; a 16-bit write to 0x0340 is NAKed with -EREMOTEIO. Every 16-bit field — exposure, VTS, digital gain, the chip ID — is therefore two separate 8-bit transactions. This is why the driver uses CCI_REG8 throughout and never CCI_REG16.

ipu-bridge is boot-only

ipu_bridge_init() leaks its struct ipu_bridge on the success path and never unregisters the software nodes it registers — the comment in-tree says as much, "so that it survives if the module is unloaded". Those nodes' property arrays point into the module's .rodata. rmmod ipu_bridge therefore leaves dangling swnodes behind, and the next sensor probe faults in fwnode_property_read_int_array():

BUG: unable to handle page fault for address: ffffffffc0db7530
  software_node_read_int_array+0x83/0xe0
  fwnode_property_read_int_array+0x55/0xe0
  v4l2_fwnode_endpoint_alloc_parse+0x106/0x1c0 [v4l2_fwnode]

There is no way to hot-swap it. Reboot after installing.

Illuminator

The module carries an IR bandpass filter, and modern LED room lighting emits almost no NIR, so ambient frames are close to black — mean level 33 out of 1023 in a lit room here. With the LM3643 in torch mode that goes to 141 and the image is perfectly usable.

Nothing in the kernel claims the LM3643, so hm1092-capture pokes it directly. Its register map is shifted one from the LM3644 many datasheets lead you to expect: 0x00 is a read-only ID and 0x01 is Enable, with mode in bits [3:2] (10 = torch) and LED1/LED2 in the low two bits. Torch brightness is 0x05 and 0x06. Writes to 0x00 are silently dropped.

Doing this properly means a v4l2-flash driver strobed from the sensor, which is how Windows drives it. Patches welcome.

The module is mounted upside down

On the X9-14, both the IR and RGB modules are physically inverted, and the ACPI SSDB still reports degree 0. The bridge patch adds a DMI quirk so the rotation property comes out as 180 and userspace can do the right thing. If your machine is affected, add it to upside_down_sensor_dmi_ids — note that Lenovo puts the useful name in DMI_PRODUCT_VERSION, not DMI_PRODUCT_NAME.

Supported machines

Machine Status
ThinkPad X9-14 Gen 1 (21QA/21QB) tested
Anything else with ACPI HM1092 behind an IPU6/IPU7 should work; the sensor config is not board-specific

Intel's driver package ships tuning for three HM1092 modules — CJFLE26IR, BBG803N3 and CJFOE83 — all sharing one register set, which is a good sign the init sequence generalises. If it works on your machine, or doesn't, please open an issue with dmesg | grep -i hm1092 and the output of hm1092-capture --list.

Provenance

The register sequences in src/hm1092_regs.h and the mode geometry were recovered from hm1092.sys, Intel's Windows driver, shipped in Lenovo package n4dim10w.exe. There is no public datasheet for this part. The method, and how the table format was validated against a known-good driver, is written up in docs/REVERSE-ENGINEERING.md.

Be aware of what that means: these tables are extracted from a proprietary binary, not independently derived. That is fine for running your own hardware, and it is the same position every "recovered from the vendor blob" sensor driver starts from, but it is a real obstacle to merging this upstream as-is. Anyone wanting to take it to linux-media should know that going in.

Licence

GPL-2.0-only, matching the kernel.

About

Linux driver for the Himax HM1092 mono/NIR sensor - the Windows Hello IR camera behind Intel IPU6/IPU7

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages