This document describes the protocol currently implemented in this repository for the Focaltech USB fingerprint sensor VID:PID 2808:9e65.
It is based on:
- Reverse-engineering workflow and packet captures in
captures/ - Driver implementation in
driver/focaltech.c - Standalone validator in
test/focaltech_test.c
These notes represent observed/implemented behavior and should be treated as a working protocol specification.
- Bus: USB bulk transfer
- OUT endpoint (host -> device):
0x01 - IN endpoint (device -> host):
0x82 - Default command timeout:
2000 ms
The host performs request/response command transactions:
- Send one framed packet to
EP_OUT - Read one framed packet from
EP_IN - Validate frame checksum before parsing payload
All packets are framed as:
| Byte Offset | Field | Size | Notes |
|---|---|---|---|
| 0 | SOF | 1 | Always 0x02 |
| 1 | Reserved | 1 | Always 0x00 |
| 2 | Payload Length | 1 | Number of bytes in [CMD/RESP + ARGS/DATA] |
| 3 | Command or Response Code | 1 | Command in requests, response code in replies |
| 4..N | Args/Data | variable | Optional command args or response payload |
| Last | Checksum | 1 | XOR checksum (see below) |
Checksum is XOR over bytes starting at offset 2 through the end of payload bytes (excluding the checksum byte itself):
chk = 0
for i in [2 .. len-2]:
chk ^= packet[i]
packet[len-1] = chk
For responses, checksum verification is equivalent to XOR over offsets 2..len-1 resulting in 0.
Known response codes (byte 3 in response frame):
0x04: Success / OK0x09: No match (observed in verify path)
| Command | Code | Direction | Purpose |
|---|---|---|---|
CMD_POWER |
0x80 |
Host->Device | Wake and polling sub-operations |
CMD_INIT |
0x37 |
Host->Device | Device init sequence |
CMD_STATUS |
0xAD |
Host->Device | Query status before enrollment |
CMD_CAPTURE |
0x3B |
Host->Device | Trigger fingerprint capture |
CMD_PROGRESS |
0xA6 |
Host->Device | Enrollment/progress query |
CMD_SECURE |
0x34 |
Host->Device | Secure channel/state check |
CMD_RESET |
0x82 |
Host->Device | Sensor reset between stages |
CMD_ENROLL_KEY |
0xA8 |
Host->Device | Send 32-byte key/template blob |
CMD_FINALIZE |
0xA3 |
Host->Device | Finalize enrollment using key |
CMD_VERIFY |
0xAA |
Host->Device | Retrieve template/match operation |
- Wake args:
[0x01, 0x02] - Poll args:
[0x02, 0x01]
Observed meanings:
- Wake response payload often includes magic bytes
A5 5A - Poll response payload indicates finger presence:
0x01=> finger detected- non-
0x01=> no finger yet
- Args:
[0x01, 0x01, 0x00]
- Args:
[0x02, 0x00]
- Args:
[0x78]
- No args
- Expected success payload includes magic bytes
55 AA
- 32-byte payload
- In current implementation, this carries:
- Enrollment-time generated 32-byte key, or
- Stored 32-byte template/blob during verification flow
- 32-byte payload (same key blob used in enrollment)
- No args
- Used in two contexts:
- Enrollment completion: retrieve 32-byte enrolled template blob
- Verification: request match/verification result
The driver is implemented as asynchronous libfprint state machines (FpiSsm).
CMD_POWER([01 02])- Receive/validate response
CMD_INIT([01 01 00])- Receive/validate response
CMD_RESET([78])- Receive/validate response
- Release USB interface
Pre-check:
CMD_STATUSCMD_SECURECMD_ENROLL_KEY(32-byte key)
Per-stage loop (ENROLL_STAGES = 10):
- Wake:
CMD_POWER([01 02]) - Poll until finger present:
CMD_POWER([02 01]) - Capture:
CMD_CAPTURE([02 00]) - Progress:
CMD_PROGRESS - Reset:
CMD_RESET([78]) - Report stage progress to libfprint
Finalization:
CMD_SECURECMD_FINALIZE(32-byte key)- Wake + poll + capture + progress + reset (final capture cycle)
CMD_SECURECMD_VERIFY-> extract 32-byte enrolled template/blob
Template handling in driver:
- Stored as a 32-byte raw blob
- Wrapped into libfprint print data variant format
(@ay)
- Wake:
CMD_POWER([01 02]) - Init:
CMD_INIT([01 01 00]) - Send stored 32-byte template/blob via
CMD_ENROLL_KEY - Poll until finger present
- Capture
- Progress
- Reset
- Secure check
- Verify:
CMD_VERIFY - Match result from response code (
0x04success, otherwise fail/no match)
Request:
02 00 03 80 01 02 80
Explanation:
03payload length (CMD + 2 args)80command (CMD_POWER)- args
01 02 - checksum
0x80(XOR of03 ^ 80 ^ 01 ^ 02)
Example shape (payload bytes vary by command):
02 00 <len> 04 <payload...> <chk>
Where 04 is success response code.