mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2026-05-14 11:08:10 +02:00
validity: Add new driver for Validity/Synaptics VCSFW sensors
Add a new "validity" driver for Validity/Synaptics fingerprint sensors that use the VCSFW protocol (as opposed to BMKT). This is iteration 1 of a multi-phase effort to bring native libfprint support to these widely-deployed sensors found in ThinkPad T480/T480s/T580/X1 Carbon Gen6 and many other laptops. This initial iteration implements: - VCSFW command/response transport layer over USB bulk endpoints - GET_VERSION command parsing (firmware version, product ID, build) - Synchronous probe and async open/close state machines - Stub implementations for enroll/verify/identify (return NOT_SUPPORTED) - umockdev replay test with real hardware capture Supported USB IDs (VCSFW protocol): - 138a:0090 (Validity VFS7500) - 138a:0097 (Validity VFS5011) - 06cb:009a (Synaptics Metallica MIS Touch) - 138a:009d (Validity VFS7552) These were previously (incorrectly) claimed by the synaptics driver which uses the BMKT protocol.
This commit is contained in:
parent
d79f157282
commit
29d6fea0de
12 changed files with 1202 additions and 8 deletions
|
|
@ -319,6 +319,14 @@ usb:v05BAp000A*
|
|||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
# Supported by libfprint driver validity
|
||||
usb:v138Ap0090*
|
||||
usb:v138Ap0097*
|
||||
usb:v06CBp009A*
|
||||
usb:v138Ap009D*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
# Supported by libfprint driver vcom5s
|
||||
usb:v061Ap0110*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
|
@ -388,7 +396,6 @@ usb:v06CBp0051*
|
|||
usb:v06CBp0081*
|
||||
usb:v06CBp0088*
|
||||
usb:v06CBp008A*
|
||||
usb:v06CBp009A*
|
||||
usb:v06CBp009B*
|
||||
usb:v06CBp00A1*
|
||||
usb:v06CBp00A2*
|
||||
|
|
@ -436,11 +443,8 @@ usb:v138Ap003A*
|
|||
usb:v138Ap003C*
|
||||
usb:v138Ap003D*
|
||||
usb:v138Ap003F*
|
||||
usb:v138Ap0090*
|
||||
usb:v138Ap0092*
|
||||
usb:v138Ap0094*
|
||||
usb:v138Ap0097*
|
||||
usb:v138Ap009D*
|
||||
usb:v138Ap00AB*
|
||||
usb:v138Ap00A6*
|
||||
usb:v147Ep1002*
|
||||
|
|
|
|||
410
libfprint/drivers/validity/validity.c
Normal file
410
libfprint/drivers/validity/validity.c
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
/*
|
||||
* Main driver for Validity/Synaptics VCSFW fingerprint sensors
|
||||
*
|
||||
* Copyright (C) 2024 libfprint contributors
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "validity"
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "fpi-byte-reader.h"
|
||||
#include "validity.h"
|
||||
#include "vcsfw_protocol.h"
|
||||
|
||||
G_DEFINE_TYPE (FpiDeviceValidity, fpi_device_validity, FP_TYPE_DEVICE)
|
||||
|
||||
static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x138A, .pid = 0x0090, .driver_data = VALIDITY_DEV_90 },
|
||||
{ .vid = 0x138A, .pid = 0x0097, .driver_data = VALIDITY_DEV_97 },
|
||||
{ .vid = 0x06CB, .pid = 0x009A, .driver_data = VALIDITY_DEV_9A },
|
||||
{ .vid = 0x138A, .pid = 0x009D, .driver_data = VALIDITY_DEV_9D },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||
};
|
||||
|
||||
/* ================================================================
|
||||
* Probe
|
||||
* ================================================================
|
||||
*
|
||||
* Probe is done synchronously (like synaptics driver):
|
||||
* 1) Open USB device
|
||||
* 2) Send GET_VERSION (cmd 0x01)
|
||||
* 3) Read response, parse firmware info
|
||||
* 4) Close USB device
|
||||
* 5) Report probe complete
|
||||
*/
|
||||
|
||||
static void
|
||||
dev_probe (FpDevice *device)
|
||||
{
|
||||
FpiDeviceValidity *self = FPI_DEVICE_VALIDITY (device);
|
||||
GUsbDevice *usb_dev;
|
||||
|
||||
g_autoptr(FpiUsbTransfer) transfer = NULL;
|
||||
GError *error = NULL;
|
||||
FpiByteReader reader;
|
||||
guint16 status;
|
||||
g_autofree gchar *serial = NULL;
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
self->dev_type = fpi_device_get_driver_data (device);
|
||||
|
||||
usb_dev = fpi_device_get_usb_device (device);
|
||||
|
||||
if (!g_usb_device_open (usb_dev, &error))
|
||||
{
|
||||
fpi_device_probe_complete (device, NULL, NULL, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_usb_device_reset (usb_dev, &error))
|
||||
{
|
||||
fp_dbg ("USB reset failed: %s", error->message);
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
|
||||
goto err_close;
|
||||
|
||||
/* Send GET_VERSION (cmd 0x01) */
|
||||
transfer = fpi_usb_transfer_new (device);
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_OUT,
|
||||
VALIDITY_USB_SEND_HEADER_LEN);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->buffer[0] = VCSFW_CMD_GET_VERSION;
|
||||
if (!fpi_usb_transfer_submit_sync (transfer, VALIDITY_USB_TIMEOUT, &error))
|
||||
goto err_close;
|
||||
|
||||
/* Read response */
|
||||
g_clear_pointer (&transfer, fpi_usb_transfer_unref);
|
||||
transfer = fpi_usb_transfer_new (device);
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_IN,
|
||||
VALIDITY_MAX_TRANSFER_LEN);
|
||||
if (!fpi_usb_transfer_submit_sync (transfer, VALIDITY_USB_TIMEOUT, &error))
|
||||
goto err_close;
|
||||
|
||||
/* Parse status */
|
||||
fpi_byte_reader_init (&reader, transfer->buffer, transfer->actual_length);
|
||||
|
||||
if (!fpi_byte_reader_get_uint16_le (&reader, &status))
|
||||
{
|
||||
g_warning ("GET_VERSION response too short");
|
||||
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
if (status != VCSFW_STATUS_OK)
|
||||
{
|
||||
g_warning ("GET_VERSION returned error status: 0x%04x", status);
|
||||
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
/* Parse version info (data after the 2-byte status) */
|
||||
if (!vcsfw_parse_version (transfer->buffer + 2,
|
||||
transfer->actual_length - 2,
|
||||
&self->version_info))
|
||||
{
|
||||
g_warning ("Failed to parse GET_VERSION response");
|
||||
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
fp_dbg ("Validity sensor firmware:");
|
||||
fp_dbg (" Version: %d.%d",
|
||||
self->version_info.version_major,
|
||||
self->version_info.version_minor);
|
||||
fp_dbg (" Product: %d", self->version_info.product);
|
||||
fp_dbg (" Build Num: %d", self->version_info.build_num);
|
||||
fp_dbg (" Build Time: %u", self->version_info.build_time);
|
||||
|
||||
/* Build a serial string from the serial number bytes */
|
||||
serial = g_strdup_printf ("%02x%02x%02x%02x%02x%02x",
|
||||
self->version_info.serial_number[0],
|
||||
self->version_info.serial_number[1],
|
||||
self->version_info.serial_number[2],
|
||||
self->version_info.serial_number[3],
|
||||
self->version_info.serial_number[4],
|
||||
self->version_info.serial_number[5]);
|
||||
|
||||
g_usb_device_release_interface (usb_dev, 0, 0, NULL);
|
||||
g_usb_device_close (usb_dev, NULL);
|
||||
|
||||
fpi_device_probe_complete (device, serial, NULL, NULL);
|
||||
return;
|
||||
|
||||
err_close:
|
||||
g_usb_device_release_interface (usb_dev, 0, 0, NULL);
|
||||
g_usb_device_close (usb_dev, NULL);
|
||||
fpi_device_probe_complete (device, NULL, NULL, error);
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* Open
|
||||
* ================================================================
|
||||
*
|
||||
* Open claims the USB interface and sends the init sequence:
|
||||
* 1) GET_VERSION (0x01)
|
||||
* 2) UNKNOWN_INIT (0x19)
|
||||
* 3) GET_FW_INFO (0x43 0x02) — check if fwext loaded
|
||||
* 4) Send init_hardcoded blob
|
||||
* 5) If no fwext: send init_hardcoded_clean_slate blob
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
OPEN_GET_VERSION = 0,
|
||||
OPEN_RECV_VERSION,
|
||||
OPEN_SEND_CMD19,
|
||||
OPEN_RECV_CMD19,
|
||||
OPEN_SEND_GET_FW_INFO,
|
||||
OPEN_RECV_GET_FW_INFO,
|
||||
OPEN_DONE,
|
||||
OPEN_NUM_STATES,
|
||||
} ValidityOpenSsmState;
|
||||
|
||||
/* Track whether fw extension is loaded */
|
||||
typedef struct
|
||||
{
|
||||
gboolean fwext_loaded;
|
||||
} OpenSsmData;
|
||||
|
||||
static void
|
||||
open_run_state (FpiSsm *ssm,
|
||||
FpDevice *dev)
|
||||
{
|
||||
FpiUsbTransfer *transfer;
|
||||
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case OPEN_GET_VERSION:
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_OUT,
|
||||
VALIDITY_USB_SEND_HEADER_LEN);
|
||||
transfer->buffer[0] = VCSFW_CMD_GET_VERSION;
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
break;
|
||||
|
||||
case OPEN_RECV_VERSION:
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_IN,
|
||||
VALIDITY_MAX_TRANSFER_LEN);
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
break;
|
||||
|
||||
case OPEN_SEND_CMD19:
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_OUT,
|
||||
VALIDITY_USB_SEND_HEADER_LEN);
|
||||
transfer->buffer[0] = VCSFW_CMD_UNKNOWN_INIT;
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
break;
|
||||
|
||||
case OPEN_RECV_CMD19:
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_IN,
|
||||
VALIDITY_MAX_TRANSFER_LEN);
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
break;
|
||||
|
||||
case OPEN_SEND_GET_FW_INFO:
|
||||
{
|
||||
guint8 cmd[] = { VCSFW_CMD_GET_FW_INFO, 0x02 };
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_OUT,
|
||||
sizeof (cmd));
|
||||
memcpy (transfer->buffer, cmd, sizeof (cmd));
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPEN_RECV_GET_FW_INFO:
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_IN,
|
||||
VALIDITY_MAX_TRANSFER_LEN);
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
|
||||
/* Parse result: check if fwext is loaded.
|
||||
* We only need the 2-byte status: 0x0000 = loaded, anything else = not loaded.
|
||||
* This is checked later when we get the actual response. For now, just read. */
|
||||
break;
|
||||
|
||||
case OPEN_DONE:
|
||||
/* All init commands sent. Mark open complete. */
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
open_ssm_done (FpiSsm *ssm,
|
||||
FpDevice *dev,
|
||||
GError *error)
|
||||
{
|
||||
FpiDeviceValidity *self = FPI_DEVICE_VALIDITY (dev);
|
||||
|
||||
self->cmd_ssm = NULL;
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, NULL);
|
||||
fpi_device_open_complete (dev, error);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_info ("Validity sensor opened successfully");
|
||||
fpi_device_open_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_open (FpDevice *device)
|
||||
{
|
||||
FpiDeviceValidity *self = FPI_DEVICE_VALIDITY (device);
|
||||
GError *error = NULL;
|
||||
FpiSsm *ssm;
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
self->interrupt_cancellable = g_cancellable_new ();
|
||||
|
||||
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error))
|
||||
{
|
||||
fpi_device_open_complete (device, error);
|
||||
return;
|
||||
}
|
||||
|
||||
ssm = fpi_ssm_new (device, open_run_state, OPEN_NUM_STATES);
|
||||
self->cmd_ssm = ssm;
|
||||
fpi_ssm_start (ssm, open_ssm_done);
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* Close
|
||||
* ================================================================ */
|
||||
|
||||
static void
|
||||
dev_close (FpDevice *device)
|
||||
{
|
||||
FpiDeviceValidity *self = FPI_DEVICE_VALIDITY (device);
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
g_clear_pointer (&self->cmd_response_data, g_free);
|
||||
self->cmd_response_len = 0;
|
||||
|
||||
g_clear_object (&self->interrupt_cancellable);
|
||||
|
||||
g_usb_device_release_interface (fpi_device_get_usb_device (device), 0, 0, &error);
|
||||
|
||||
fpi_device_close_complete (device, g_steal_pointer (&error));
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* Enroll / Verify / Identify / Delete stubs
|
||||
* ================================================================
|
||||
*
|
||||
* These are stubs for Iteration 1. Real implementations come in
|
||||
* Iteration 5 (Flash/DB Management).
|
||||
*/
|
||||
|
||||
static void
|
||||
enroll (FpDevice *device)
|
||||
{
|
||||
fpi_device_enroll_complete (device, NULL,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
|
||||
}
|
||||
|
||||
static void
|
||||
verify (FpDevice *device)
|
||||
{
|
||||
fpi_device_verify_complete (device,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
|
||||
}
|
||||
|
||||
static void
|
||||
identify (FpDevice *device)
|
||||
{
|
||||
fpi_device_identify_complete (device,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
|
||||
}
|
||||
|
||||
static void
|
||||
delete_print (FpDevice *device)
|
||||
{
|
||||
fpi_device_delete_complete (device,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
|
||||
}
|
||||
|
||||
static void
|
||||
cancel (FpDevice *device)
|
||||
{
|
||||
FpiDeviceValidity *self = FPI_DEVICE_VALIDITY (device);
|
||||
|
||||
g_cancellable_cancel (self->interrupt_cancellable);
|
||||
g_clear_object (&self->interrupt_cancellable);
|
||||
self->interrupt_cancellable = g_cancellable_new ();
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* GObject boilerplate
|
||||
* ================================================================ */
|
||||
|
||||
static void
|
||||
fpi_device_validity_init (FpiDeviceValidity *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_validity_class_init (FpiDeviceValidityClass *klass)
|
||||
{
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
|
||||
dev_class->id = FP_COMPONENT;
|
||||
dev_class->full_name = "Validity VCSFW Fingerprint Sensor";
|
||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
||||
dev_class->id_table = id_table;
|
||||
dev_class->nr_enroll_stages = VALIDITY_ENROLL_STAGES;
|
||||
dev_class->temp_hot_seconds = -1;
|
||||
|
||||
dev_class->probe = dev_probe;
|
||||
dev_class->open = dev_open;
|
||||
dev_class->close = dev_close;
|
||||
dev_class->enroll = enroll;
|
||||
dev_class->verify = verify;
|
||||
dev_class->identify = identify;
|
||||
dev_class->delete = delete_print;
|
||||
dev_class->cancel = cancel;
|
||||
|
||||
fpi_device_class_auto_initialize_features (dev_class);
|
||||
}
|
||||
103
libfprint/drivers/validity/validity.h
Normal file
103
libfprint/drivers/validity/validity.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Validity/Synaptics VCSFW fingerprint sensor driver
|
||||
*
|
||||
* Copyright (C) 2024 libfprint contributors
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-device.h"
|
||||
#include "fpi-ssm.h"
|
||||
|
||||
/* USB Endpoint addresses */
|
||||
#define VALIDITY_EP_CMD_OUT 0x01
|
||||
#define VALIDITY_EP_CMD_IN 0x81
|
||||
#define VALIDITY_EP_DATA_IN 0x82
|
||||
#define VALIDITY_EP_INT_IN 0x83
|
||||
|
||||
/* USB transfer parameters */
|
||||
#define VALIDITY_USB_TIMEOUT 15000
|
||||
#define VALIDITY_USB_INT_TIMEOUT 100
|
||||
#define VALIDITY_MAX_TRANSFER_LEN (100 * 1024)
|
||||
#define VALIDITY_USB_INT_DATA_SIZE 1024
|
||||
#define VALIDITY_USB_SEND_HEADER_LEN 1
|
||||
|
||||
/* Number of enroll stages */
|
||||
#define VALIDITY_ENROLL_STAGES 8
|
||||
|
||||
/* Interrupt response bits */
|
||||
#define VALIDITY_INT_FINGER_DOWN 0x02
|
||||
#define VALIDITY_INT_SCAN_COMPLETE 0x04
|
||||
|
||||
typedef enum {
|
||||
VALIDITY_DEV_90 = 0, /* 138a:0090 */
|
||||
VALIDITY_DEV_97, /* 138a:0097 */
|
||||
VALIDITY_DEV_9A, /* 06cb:009a */
|
||||
VALIDITY_DEV_9D, /* 138a:009d */
|
||||
} ValidityDeviceType;
|
||||
|
||||
/* Firmware version info from GET_VERSION (cmd 0x01) */
|
||||
typedef struct
|
||||
{
|
||||
guint32 build_time;
|
||||
guint32 build_num;
|
||||
guint8 version_major;
|
||||
guint8 version_minor;
|
||||
guint8 target;
|
||||
guint8 product;
|
||||
guint8 silicon_rev;
|
||||
guint8 formal_release;
|
||||
guint8 platform;
|
||||
guint8 patch;
|
||||
guint8 serial_number[6];
|
||||
guint16 security;
|
||||
guint8 iface;
|
||||
guint8 device_type;
|
||||
} ValidityVersionInfo;
|
||||
|
||||
/* Open SSM states */
|
||||
typedef enum {
|
||||
VALIDITY_OPEN_CLAIM_INTERFACE = 0,
|
||||
VALIDITY_OPEN_SEND_INIT,
|
||||
VALIDITY_OPEN_NUM_STATES,
|
||||
} ValidityOpenState;
|
||||
|
||||
/* Close SSM states */
|
||||
typedef enum {
|
||||
VALIDITY_CLOSE_RELEASE_INTERFACE = 0,
|
||||
VALIDITY_CLOSE_NUM_STATES,
|
||||
} ValidityCloseState;
|
||||
|
||||
#define FPI_TYPE_DEVICE_VALIDITY (fpi_device_validity_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceValidity, fpi_device_validity,
|
||||
FPI, DEVICE_VALIDITY, FpDevice)
|
||||
|
||||
struct _FpiDeviceValidity
|
||||
{
|
||||
FpDevice parent;
|
||||
|
||||
ValidityDeviceType dev_type;
|
||||
ValidityVersionInfo version_info;
|
||||
GCancellable *interrupt_cancellable;
|
||||
|
||||
/* Command SSM: manages the send-cmd/recv-response cycle */
|
||||
FpiSsm *cmd_ssm;
|
||||
|
||||
/* Pending response data stashed for higher-level SSM consumption */
|
||||
guint8 *cmd_response_data;
|
||||
gsize cmd_response_len;
|
||||
};
|
||||
248
libfprint/drivers/validity/vcsfw_protocol.c
Normal file
248
libfprint/drivers/validity/vcsfw_protocol.c
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* VCSFW protocol implementation for Validity/Synaptics fingerprint sensors
|
||||
*
|
||||
* Copyright (C) 2024 libfprint contributors
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "validity"
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "fpi-byte-reader.h"
|
||||
#include "vcsfw_protocol.h"
|
||||
|
||||
/* ---- VcsfwCmdData lifecycle ---- */
|
||||
|
||||
VcsfwCmdData *
|
||||
vcsfw_cmd_data_new (const guint8 *cmd,
|
||||
gsize cmd_len,
|
||||
VcsfwCmdCallback callback)
|
||||
{
|
||||
VcsfwCmdData *data = g_new0 (VcsfwCmdData, 1);
|
||||
|
||||
data->cmd_data = g_memdup2 (cmd, cmd_len);
|
||||
data->cmd_len = cmd_len;
|
||||
data->callback = callback;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
vcsfw_cmd_data_free (gpointer data)
|
||||
{
|
||||
VcsfwCmdData *cmd_data = data;
|
||||
|
||||
if (cmd_data == NULL)
|
||||
return;
|
||||
|
||||
g_free (cmd_data->cmd_data);
|
||||
g_free (cmd_data);
|
||||
}
|
||||
|
||||
/* ---- Receive callback ---- */
|
||||
|
||||
static void
|
||||
cmd_receive_cb (FpiUsbTransfer *transfer,
|
||||
FpDevice *device,
|
||||
gpointer user_data,
|
||||
GError *error)
|
||||
{
|
||||
FpiDeviceValidity *self = FPI_DEVICE_VALIDITY (device);
|
||||
VcsfwCmdData *cmd_data = fpi_ssm_get_data (transfer->ssm);
|
||||
guint16 status;
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (cmd_data->callback)
|
||||
cmd_data->callback (self, NULL, 0, 0, error);
|
||||
else
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (transfer->actual_length < 2)
|
||||
{
|
||||
g_warning ("VCSFW response too short: %" G_GSSIZE_FORMAT " bytes",
|
||||
transfer->actual_length);
|
||||
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
||||
if (cmd_data->callback)
|
||||
cmd_data->callback (self, NULL, 0, 0, error);
|
||||
else
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
status = FP_READ_UINT16_LE (transfer->buffer);
|
||||
|
||||
fp_dbg ("VCSFW response: status=0x%04x, len=%" G_GSSIZE_FORMAT,
|
||||
status, transfer->actual_length - 2);
|
||||
|
||||
/* Stash raw response for direct access if needed */
|
||||
g_clear_pointer (&self->cmd_response_data, g_free);
|
||||
if (transfer->actual_length > 2)
|
||||
{
|
||||
self->cmd_response_len = transfer->actual_length - 2;
|
||||
self->cmd_response_data = g_memdup2 (transfer->buffer + 2,
|
||||
self->cmd_response_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->cmd_response_len = 0;
|
||||
self->cmd_response_data = NULL;
|
||||
}
|
||||
|
||||
if (cmd_data->callback)
|
||||
{
|
||||
cmd_data->callback (self,
|
||||
self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
status,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* If the callback didn't fail the SSM, advance it */
|
||||
fpi_ssm_mark_completed (transfer->ssm);
|
||||
}
|
||||
|
||||
/* ---- Command/Response SSM ---- */
|
||||
|
||||
void
|
||||
vcsfw_cmd_run_state (FpiSsm *ssm,
|
||||
FpDevice *dev)
|
||||
{
|
||||
VcsfwCmdData *cmd_data = fpi_ssm_get_data (ssm);
|
||||
FpiUsbTransfer *transfer;
|
||||
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case VCSFW_CMD_STATE_SEND:
|
||||
fp_dbg ("VCSFW send cmd 0x%02x, len=%" G_GSIZE_FORMAT,
|
||||
cmd_data->cmd_data[0], cmd_data->cmd_len);
|
||||
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->short_is_error = TRUE;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_OUT,
|
||||
cmd_data->cmd_len);
|
||||
memcpy (transfer->buffer, cmd_data->cmd_data, cmd_data->cmd_len);
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
break;
|
||||
|
||||
case VCSFW_CMD_STATE_RECV:
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_IN,
|
||||
VALIDITY_MAX_TRANSFER_LEN);
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
cmd_receive_cb, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- High-level command sender ---- */
|
||||
|
||||
static void
|
||||
cmd_ssm_done (FpiSsm *ssm,
|
||||
FpDevice *dev,
|
||||
GError *error)
|
||||
{
|
||||
FpiDeviceValidity *self = FPI_DEVICE_VALIDITY (dev);
|
||||
|
||||
self->cmd_ssm = NULL;
|
||||
|
||||
if (error)
|
||||
fp_dbg ("VCSFW command SSM failed: %s", error->message);
|
||||
|
||||
/* Error is handled by the callback, nothing else to do here */
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
void
|
||||
vcsfw_cmd_send (FpiDeviceValidity *self,
|
||||
FpiSsm *parent_ssm,
|
||||
const guint8 *cmd,
|
||||
gsize cmd_len,
|
||||
VcsfwCmdCallback callback)
|
||||
{
|
||||
FpiSsm *ssm;
|
||||
VcsfwCmdData *cmd_data;
|
||||
|
||||
cmd_data = vcsfw_cmd_data_new (cmd, cmd_len, callback);
|
||||
|
||||
ssm = fpi_ssm_new (FP_DEVICE (self), vcsfw_cmd_run_state,
|
||||
VCSFW_CMD_STATE_NUM_STATES);
|
||||
fpi_ssm_set_data (ssm, cmd_data, vcsfw_cmd_data_free);
|
||||
|
||||
self->cmd_ssm = ssm;
|
||||
|
||||
if (parent_ssm)
|
||||
fpi_ssm_start_subsm (parent_ssm, ssm);
|
||||
else
|
||||
fpi_ssm_start (ssm, cmd_ssm_done);
|
||||
}
|
||||
|
||||
/* ---- GET_VERSION (cmd 0x01) response parser ---- */
|
||||
|
||||
gboolean
|
||||
vcsfw_parse_version (const guint8 *data,
|
||||
gsize data_len,
|
||||
ValidityVersionInfo *info)
|
||||
{
|
||||
FpiByteReader reader;
|
||||
|
||||
g_return_val_if_fail (data != NULL, FALSE);
|
||||
g_return_val_if_fail (info != NULL, FALSE);
|
||||
|
||||
fpi_byte_reader_init (&reader, data, data_len);
|
||||
|
||||
if (!fpi_byte_reader_get_uint32_le (&reader, &info->build_time))
|
||||
return FALSE;
|
||||
if (!fpi_byte_reader_get_uint32_le (&reader, &info->build_num))
|
||||
return FALSE;
|
||||
if (!fpi_byte_reader_get_uint8 (&reader, &info->version_major))
|
||||
return FALSE;
|
||||
if (!fpi_byte_reader_get_uint8 (&reader, &info->version_minor))
|
||||
return FALSE;
|
||||
if (!fpi_byte_reader_get_uint8 (&reader, &info->target))
|
||||
return FALSE;
|
||||
if (!fpi_byte_reader_get_uint8 (&reader, &info->product))
|
||||
return FALSE;
|
||||
if (!fpi_byte_reader_get_uint8 (&reader, &info->silicon_rev))
|
||||
return FALSE;
|
||||
if (!fpi_byte_reader_get_uint8 (&reader, &info->formal_release))
|
||||
return FALSE;
|
||||
if (!fpi_byte_reader_get_uint8 (&reader, &info->platform))
|
||||
return FALSE;
|
||||
if (!fpi_byte_reader_get_uint8 (&reader, &info->patch))
|
||||
return FALSE;
|
||||
|
||||
{
|
||||
const guint8 *serial;
|
||||
if (!fpi_byte_reader_get_data (&reader, sizeof (info->serial_number), &serial))
|
||||
return FALSE;
|
||||
memcpy (info->serial_number, serial, sizeof (info->serial_number));
|
||||
}
|
||||
|
||||
if (!fpi_byte_reader_get_uint16_le (&reader, &info->security))
|
||||
return FALSE;
|
||||
if (!fpi_byte_reader_get_uint8 (&reader, &info->iface))
|
||||
return FALSE;
|
||||
if (!fpi_byte_reader_get_uint8 (&reader, &info->device_type))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
115
libfprint/drivers/validity/vcsfw_protocol.h
Normal file
115
libfprint/drivers/validity/vcsfw_protocol.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* VCSFW protocol definitions for Validity/Synaptics fingerprint sensors
|
||||
*
|
||||
* Copyright (C) 2024 libfprint contributors
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "validity.h"
|
||||
|
||||
/* ---- VCSFW Command IDs (pre-TLS) ---- */
|
||||
#define VCSFW_CMD_GET_VERSION 0x01
|
||||
#define VCSFW_CMD_READ_HW_REG32 0x07
|
||||
#define VCSFW_CMD_WRITE_HW_REG32 0x08
|
||||
#define VCSFW_CMD_UNKNOWN_INIT 0x19
|
||||
#define VCSFW_CMD_GET_FLASH_INFO 0x3E
|
||||
#define VCSFW_CMD_READ_FLASH 0x40
|
||||
#define VCSFW_CMD_WRITE_FLASH 0x41
|
||||
#define VCSFW_CMD_WRITE_FW_SIG 0x42
|
||||
#define VCSFW_CMD_GET_FW_INFO 0x43
|
||||
#define VCSFW_CMD_PARTITION_FLASH 0x4F
|
||||
|
||||
/* ---- VCSFW Command IDs (post-TLS, via tls.app()) ---- */
|
||||
#define VCSFW_CMD_CAPTURE 0x02
|
||||
#define VCSFW_CMD_CAPTURE_STOP 0x04
|
||||
#define VCSFW_CMD_GLOW_START 0x39
|
||||
#define VCSFW_CMD_ERASE_FLASH 0x3F
|
||||
#define VCSFW_CMD_DB_INFO 0x45
|
||||
#define VCSFW_CMD_GET_RECORD_CHILDREN 0x46
|
||||
#define VCSFW_CMD_NEW_RECORD 0x47
|
||||
#define VCSFW_CMD_DEL_RECORD 0x48
|
||||
#define VCSFW_CMD_GET_RECORD_VALUE 0x49
|
||||
#define VCSFW_CMD_GET_USER 0x4A
|
||||
#define VCSFW_CMD_GET_USER_STORAGE 0x4B
|
||||
#define VCSFW_CMD_GET_PRG_STATUS 0x51
|
||||
#define VCSFW_CMD_MATCH_FINGER 0x5E
|
||||
#define VCSFW_CMD_GET_MATCH_RESULT 0x60
|
||||
#define VCSFW_CMD_MATCH_CLEANUP 0x62
|
||||
#define VCSFW_CMD_ENROLLMENT_UPDATE_START 0x68
|
||||
#define VCSFW_CMD_CREATE_ENROLLMENT 0x69
|
||||
#define VCSFW_CMD_ENROLLMENT_UPDATE 0x6B
|
||||
#define VCSFW_CMD_GET_FACTORY_BITS 0x6F
|
||||
#define VCSFW_CMD_IDENTIFY_SENSOR 0x75
|
||||
|
||||
/* ---- VCSFW Response Status Codes ---- */
|
||||
#define VCSFW_STATUS_OK 0x0000
|
||||
#define VCSFW_STATUS_NO_FW 0xB004
|
||||
|
||||
/* ---- Callback types ---- */
|
||||
|
||||
/**
|
||||
* VcsfwCmdCallback:
|
||||
* @self: the validity device
|
||||
* @data: response data (after 2-byte status, NULL on error)
|
||||
* @data_len: length of response data (excluding 2-byte status)
|
||||
* @status: the 2-byte VCSFW status code
|
||||
* @error: a GError if the transfer failed, or NULL
|
||||
*
|
||||
* Callback invoked after a VCSFW command/response exchange completes.
|
||||
*/
|
||||
typedef void (*VcsfwCmdCallback) (FpiDeviceValidity *self,
|
||||
const guint8 *data,
|
||||
gsize data_len,
|
||||
guint16 status,
|
||||
GError *error);
|
||||
|
||||
/* ---- Command/response SSM states ---- */
|
||||
typedef enum {
|
||||
VCSFW_CMD_STATE_SEND = 0,
|
||||
VCSFW_CMD_STATE_RECV,
|
||||
VCSFW_CMD_STATE_NUM_STATES,
|
||||
} VcsfwCmdSsmState;
|
||||
|
||||
/* ---- Context for a single command/response exchange ---- */
|
||||
typedef struct
|
||||
{
|
||||
guint8 *cmd_data;
|
||||
gsize cmd_len;
|
||||
VcsfwCmdCallback callback;
|
||||
} VcsfwCmdData;
|
||||
|
||||
/* ---- Functions ---- */
|
||||
|
||||
void vcsfw_cmd_run_state (FpiSsm *ssm,
|
||||
FpDevice *dev);
|
||||
|
||||
VcsfwCmdData *vcsfw_cmd_data_new (const guint8 *cmd,
|
||||
gsize cmd_len,
|
||||
VcsfwCmdCallback callback);
|
||||
|
||||
void vcsfw_cmd_data_free (gpointer data);
|
||||
|
||||
void vcsfw_cmd_send (FpiDeviceValidity *self,
|
||||
FpiSsm *parent_ssm,
|
||||
const guint8 *cmd,
|
||||
gsize cmd_len,
|
||||
VcsfwCmdCallback callback);
|
||||
|
||||
gboolean vcsfw_parse_version (const guint8 *data,
|
||||
gsize data_len,
|
||||
ValidityVersionInfo *info);
|
||||
|
|
@ -62,7 +62,6 @@ static const FpIdEntry allowlist_id_table[] = {
|
|||
{ .vid = 0x06cb, .pid = 0x0081 },
|
||||
{ .vid = 0x06cb, .pid = 0x0088 },
|
||||
{ .vid = 0x06cb, .pid = 0x008a },
|
||||
{ .vid = 0x06cb, .pid = 0x009a },
|
||||
{ .vid = 0x06cb, .pid = 0x009b },
|
||||
{ .vid = 0x06cb, .pid = 0x00a1 },
|
||||
{ .vid = 0x06cb, .pid = 0x00a2 },
|
||||
|
|
@ -110,11 +109,8 @@ static const FpIdEntry allowlist_id_table[] = {
|
|||
{ .vid = 0x138a, .pid = 0x003c },
|
||||
{ .vid = 0x138a, .pid = 0x003d },
|
||||
{ .vid = 0x138a, .pid = 0x003f },
|
||||
{ .vid = 0x138a, .pid = 0x0090 },
|
||||
{ .vid = 0x138a, .pid = 0x0092 },
|
||||
{ .vid = 0x138a, .pid = 0x0094 },
|
||||
{ .vid = 0x138a, .pid = 0x0097 },
|
||||
{ .vid = 0x138a, .pid = 0x009d },
|
||||
{ .vid = 0x138a, .pid = 0x00ab },
|
||||
{ .vid = 0x138a, .pid = 0x00a6 },
|
||||
{ .vid = 0x147e, .pid = 0x1002 },
|
||||
|
|
|
|||
|
|
@ -153,6 +153,9 @@ driver_sources = {
|
|||
[ 'drivers/realtek/realtek.c' ],
|
||||
'focaltech_moc' :
|
||||
[ 'drivers/focaltech_moc/focaltech_moc.c' ],
|
||||
'validity' :
|
||||
[ 'drivers/validity/validity.c',
|
||||
'drivers/validity/vcsfw_protocol.c' ],
|
||||
}
|
||||
|
||||
helper_sources = {
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ default_drivers = [
|
|||
'fpcmoc',
|
||||
'realtek',
|
||||
'focaltech_moc',
|
||||
'validity',
|
||||
]
|
||||
|
||||
spi_drivers = [
|
||||
|
|
@ -178,6 +179,7 @@ endian_independent_drivers = virtual_drivers + [
|
|||
'vcom5s',
|
||||
'vfs101',
|
||||
'vfs7552',
|
||||
'validity',
|
||||
]
|
||||
|
||||
all_drivers = default_drivers + virtual_drivers
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ drivers_tests = [
|
|||
'realtek',
|
||||
'realtek-5816',
|
||||
'focaltech_moc',
|
||||
'validity',
|
||||
]
|
||||
|
||||
if get_option('introspection')
|
||||
|
|
|
|||
BIN
tests/validity/custom.pcapng
Normal file
BIN
tests/validity/custom.pcapng
Normal file
Binary file not shown.
48
tests/validity/custom.py
Normal file
48
tests/validity/custom.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import traceback
|
||||
import sys
|
||||
import gi
|
||||
|
||||
gi.require_version('FPrint', '2.0')
|
||||
from gi.repository import FPrint
|
||||
|
||||
# Exit with error on any exception, including those happening in callbacks
|
||||
sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1))
|
||||
|
||||
c = FPrint.Context()
|
||||
c.enumerate()
|
||||
devices = c.get_devices()
|
||||
|
||||
assert len(devices) == 1, f"Expected 1 device, got {len(devices)}"
|
||||
|
||||
d = devices[0]
|
||||
del devices
|
||||
|
||||
# Verify driver name
|
||||
assert d.get_driver() == "validity", f"Expected 'validity', got '{d.get_driver()}'"
|
||||
|
||||
# Verify features detected by auto_initialize_features
|
||||
# Since iteration 1 stubs provide verify/identify/delete function pointers,
|
||||
# those features are reported even though they return NOT_SUPPORTED.
|
||||
assert not d.has_feature(FPrint.DeviceFeature.CAPTURE)
|
||||
assert d.has_feature(FPrint.DeviceFeature.VERIFY)
|
||||
assert d.has_feature(FPrint.DeviceFeature.IDENTIFY)
|
||||
assert not d.has_feature(FPrint.DeviceFeature.DUPLICATES_CHECK)
|
||||
assert not d.has_feature(FPrint.DeviceFeature.STORAGE)
|
||||
assert not d.has_feature(FPrint.DeviceFeature.STORAGE_LIST)
|
||||
assert d.has_feature(FPrint.DeviceFeature.STORAGE_DELETE)
|
||||
assert not d.has_feature(FPrint.DeviceFeature.STORAGE_CLEAR)
|
||||
assert d.has_feature(FPrint.DeviceFeature.ALWAYS_ON)
|
||||
|
||||
# Test open (sends GET_VERSION, cmd 0x19, GET_FW_INFO) and close
|
||||
print("opening")
|
||||
d.open_sync()
|
||||
print("open done")
|
||||
|
||||
print("closing")
|
||||
d.close_sync()
|
||||
print("close done")
|
||||
|
||||
del d
|
||||
del c
|
||||
264
tests/validity/device
Normal file
264
tests/validity/device
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
P: /devices/pci0000:00/0000:00:14.0/usb1/1-9
|
||||
N: bus/usb/001/006=12010002FF10FF08CB069A0064010000010109023500010100A0320904000005FF000000070501024000000705810240000007058202400000070583030800040705840310000A
|
||||
E: BUSNUM=001
|
||||
E: DEVNAME=/dev/bus/usb/001/006
|
||||
E: DEVNUM=006
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: ID_AUTOSUSPEND=1
|
||||
E: ID_BUS=usb
|
||||
E: ID_INTEGRATION=internal
|
||||
E: ID_MODEL=009a
|
||||
E: ID_MODEL_ENC=009a
|
||||
E: ID_MODEL_FROM_DATABASE=Metallica MIS Touch Fingerprint Reader
|
||||
E: ID_MODEL_ID=009a
|
||||
E: ID_PATH=pci-0000:00:14.0-usb-0:9
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_9
|
||||
E: ID_PATH_WITH_USB_REVISION=pci-0000:00:14.0-usbv2-0:9
|
||||
E: ID_PERSIST=0
|
||||
E: ID_REVISION=0164
|
||||
E: ID_SERIAL=06cb_009a_c7e2948627cb
|
||||
E: ID_SERIAL_SHORT=c7e2948627cb
|
||||
E: ID_USB_INTERFACES=:ff0000:
|
||||
E: ID_USB_MODEL=009a
|
||||
E: ID_USB_MODEL_ENC=009a
|
||||
E: ID_USB_MODEL_ID=009a
|
||||
E: ID_USB_REVISION=0164
|
||||
E: ID_USB_SERIAL=06cb_009a_c7e2948627cb
|
||||
E: ID_USB_SERIAL_SHORT=c7e2948627cb
|
||||
E: ID_USB_VENDOR=06cb
|
||||
E: ID_USB_VENDOR_ENC=06cb
|
||||
E: ID_USB_VENDOR_ID=06cb
|
||||
E: ID_VENDOR=06cb
|
||||
E: ID_VENDOR_ENC=06cb
|
||||
E: ID_VENDOR_FROM_DATABASE=Synaptics, Inc.
|
||||
E: ID_VENDOR_ID=06cb
|
||||
E: MAJOR=189
|
||||
E: MINOR=5
|
||||
E: PRODUCT=6cb/9a/164
|
||||
E: SUBSYSTEM=usb
|
||||
E: TYPE=255/16/255
|
||||
A: authorized=1\n
|
||||
A: avoid_reset_quirk=0\n
|
||||
A: bConfigurationValue=1\n
|
||||
A: bDeviceClass=ff\n
|
||||
A: bDeviceProtocol=ff\n
|
||||
A: bDeviceSubClass=10\n
|
||||
A: bMaxPacketSize0=8\n
|
||||
A: bMaxPower=100mA\n
|
||||
A: bNumConfigurations=1\n
|
||||
A: bNumInterfaces= 1\n
|
||||
A: bcdDevice=0164\n
|
||||
A: bmAttributes=a0\n
|
||||
A: busnum=1\n
|
||||
A: configuration=
|
||||
H: descriptors=12010002FF10FF08CB069A0064010000010109023500010100A0320904000005FF000000070501024000000705810240000007058202400000070583030800040705840310000A
|
||||
A: dev=189:5\n
|
||||
A: devnum=6\n
|
||||
A: devpath=9\n
|
||||
L: driver=../../../../../bus/usb/drivers/usb
|
||||
L: firmware_node=../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1d/device:1e/device:29
|
||||
A: idProduct=009a\n
|
||||
A: idVendor=06cb\n
|
||||
A: ltm_capable=no\n
|
||||
A: maxchild=0\n
|
||||
A: physical_location/dock=no\n
|
||||
A: physical_location/horizontal_position=left\n
|
||||
A: physical_location/lid=no\n
|
||||
A: physical_location/panel=unknown\n
|
||||
A: physical_location/vertical_position=upper\n
|
||||
L: port=../1-0:1.0/usb1-port9
|
||||
A: power/active_duration=39041\n
|
||||
A: power/autosuspend=2\n
|
||||
A: power/autosuspend_delay_ms=2000\n
|
||||
A: power/connected_duration=8463727\n
|
||||
A: power/control=auto\n
|
||||
A: power/level=auto\n
|
||||
A: power/persist=1\n
|
||||
A: power/runtime_active_time=39927\n
|
||||
A: power/runtime_status=active\n
|
||||
A: power/runtime_suspended_time=8423564\n
|
||||
A: power/wakeup=disabled\n
|
||||
A: power/wakeup_abort_count=\n
|
||||
A: power/wakeup_active=\n
|
||||
A: power/wakeup_active_count=\n
|
||||
A: power/wakeup_count=\n
|
||||
A: power/wakeup_expire_count=\n
|
||||
A: power/wakeup_last_time_ms=\n
|
||||
A: power/wakeup_max_time_ms=\n
|
||||
A: power/wakeup_total_time_ms=\n
|
||||
A: quirks=0x0\n
|
||||
A: removable=fixed\n
|
||||
A: rx_lanes=1\n
|
||||
A: serial=c7e2948627cb\n
|
||||
A: speed=12\n
|
||||
A: tx_lanes=1\n
|
||||
A: urbnum=124\n
|
||||
A: version= 2.00\n
|
||||
|
||||
P: /devices/pci0000:00/0000:00:14.0/usb1
|
||||
N: bus/usb/001/001=12010002090001406B1D020019060302010109021900010100E0000904000001090000000705810304000C
|
||||
E: BUSNUM=001
|
||||
E: CURRENT_TAGS=:seat:
|
||||
E: DEVNAME=/dev/bus/usb/001/001
|
||||
E: DEVNUM=001
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: ID_AUTOSUSPEND=1
|
||||
E: ID_BUS=usb
|
||||
E: ID_FOR_SEAT=usb-pci-0000_00_14_0
|
||||
E: ID_MODEL=xHCI_Host_Controller
|
||||
E: ID_MODEL_ENC=xHCI\x20Host\x20Controller
|
||||
E: ID_MODEL_FROM_DATABASE=2.0 root hub
|
||||
E: ID_MODEL_ID=0002
|
||||
E: ID_PATH=pci-0000:00:14.0
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0
|
||||
E: ID_REVISION=0619
|
||||
E: ID_SERIAL=Linux_6.19.10-zen1-1-zen_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
|
||||
E: ID_SERIAL_SHORT=0000:00:14.0
|
||||
E: ID_USB_INTERFACES=:090000:
|
||||
E: ID_USB_MODEL=xHCI_Host_Controller
|
||||
E: ID_USB_MODEL_ENC=xHCI\x20Host\x20Controller
|
||||
E: ID_USB_MODEL_ID=0002
|
||||
E: ID_USB_REVISION=0619
|
||||
E: ID_USB_SERIAL=Linux_6.19.10-zen1-1-zen_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
|
||||
E: ID_USB_SERIAL_SHORT=0000:00:14.0
|
||||
E: ID_USB_VENDOR=Linux_6.19.10-zen1-1-zen_xhci-hcd
|
||||
E: ID_USB_VENDOR_ENC=Linux\x206.19.10-zen1-1-zen\x20xhci-hcd
|
||||
E: ID_USB_VENDOR_ID=1d6b
|
||||
E: ID_VENDOR=Linux_6.19.10-zen1-1-zen_xhci-hcd
|
||||
E: ID_VENDOR_ENC=Linux\x206.19.10-zen1-1-zen\x20xhci-hcd
|
||||
E: ID_VENDOR_FROM_DATABASE=Linux Foundation
|
||||
E: ID_VENDOR_ID=1d6b
|
||||
E: MAJOR=189
|
||||
E: MINOR=0
|
||||
E: PRODUCT=1d6b/2/619
|
||||
E: SUBSYSTEM=usb
|
||||
E: TAGS=:seat:
|
||||
E: TYPE=9/0/1
|
||||
A: authorized=1\n
|
||||
A: authorized_default=1\n
|
||||
A: avoid_reset_quirk=0\n
|
||||
A: bConfigurationValue=1\n
|
||||
A: bDeviceClass=09\n
|
||||
A: bDeviceProtocol=01\n
|
||||
A: bDeviceSubClass=00\n
|
||||
A: bMaxPacketSize0=64\n
|
||||
A: bMaxPower=0mA\n
|
||||
A: bNumConfigurations=1\n
|
||||
A: bNumInterfaces= 1\n
|
||||
A: bcdDevice=0619\n
|
||||
A: bmAttributes=e0\n
|
||||
A: busnum=1\n
|
||||
A: configuration=
|
||||
H: descriptors=12010002090001406B1D020019060302010109021900010100E0000904000001090000000705810304000C
|
||||
A: dev=189:0\n
|
||||
A: devnum=1\n
|
||||
A: devpath=0\n
|
||||
L: driver=../../../../bus/usb/drivers/usb
|
||||
L: firmware_node=../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1d/device:1e
|
||||
A: idProduct=0002\n
|
||||
A: idVendor=1d6b\n
|
||||
A: interface_authorized_default=1\n
|
||||
A: ltm_capable=no\n
|
||||
A: manufacturer=Linux 6.19.10-zen1-1-zen xhci-hcd\n
|
||||
A: maxchild=12\n
|
||||
A: power/active_duration=8464967\n
|
||||
A: power/autosuspend=0\n
|
||||
A: power/autosuspend_delay_ms=0\n
|
||||
A: power/connected_duration=8464967\n
|
||||
A: power/control=auto\n
|
||||
A: power/level=auto\n
|
||||
A: power/runtime_active_time=8464965\n
|
||||
A: power/runtime_status=active\n
|
||||
A: power/runtime_suspended_time=0\n
|
||||
A: power/wakeup=disabled\n
|
||||
A: power/wakeup_abort_count=\n
|
||||
A: power/wakeup_active=\n
|
||||
A: power/wakeup_active_count=\n
|
||||
A: power/wakeup_count=\n
|
||||
A: power/wakeup_expire_count=\n
|
||||
A: power/wakeup_last_time_ms=\n
|
||||
A: power/wakeup_max_time_ms=\n
|
||||
A: power/wakeup_total_time_ms=\n
|
||||
A: product=xHCI Host Controller\n
|
||||
A: quirks=0x0\n
|
||||
A: removable=unknown\n
|
||||
A: rx_lanes=1\n
|
||||
A: serial=0000:00:14.0\n
|
||||
A: speed=480\n
|
||||
A: tx_lanes=1\n
|
||||
A: urbnum=1481\n
|
||||
A: version= 2.00\n
|
||||
|
||||
P: /devices/pci0000:00/0000:00:14.0
|
||||
E: DRIVER=xhci_hcd
|
||||
E: ID_AUTOSUSPEND=1
|
||||
E: ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller
|
||||
E: ID_PATH=pci-0000:00:14.0
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0
|
||||
E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
|
||||
E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
|
||||
E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
|
||||
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
|
||||
E: MODALIAS=pci:v00008086d00009D2Fsv000017AAsd00002258bc0Csc03i30
|
||||
E: PCI_CLASS=C0330
|
||||
E: PCI_ID=8086:9D2F
|
||||
E: PCI_SLOT_NAME=0000:00:14.0
|
||||
E: PCI_SUBSYS_ID=17AA:2258
|
||||
E: SUBSYSTEM=pci
|
||||
A: ari_enabled=0\n
|
||||
A: broken_parity_status=0\n
|
||||
A: class=0x0c0330\n
|
||||
H: config=86802F9D060490022130030C00008000040032E8000000000000000000000000000000000000000000000000AA175822000000007000000000000000FF010000FD01348088C60F8000000000000000005B6ECE0F000000000000000000000000306000000000000000000000000000000180C2C10800000000000000000000000500B7001803E0FE0000000000000000090014F01000400100000000C10A080000080000001800008F40020000010400010000000200000000000000000000000000000000000000000000000000000001000000020000000000000000000000000000000000000000000000000000000000000000000000B30F410800000000
|
||||
A: consistent_dma_mask_bits=64\n
|
||||
A: d3cold_allowed=1\n
|
||||
A: dbc=disabled\n
|
||||
A: dbc_bInterfaceProtocol=01\n
|
||||
A: dbc_bcdDevice=0010\n
|
||||
A: dbc_idProduct=0010\n
|
||||
A: dbc_idVendor=1d6b\n
|
||||
A: dbc_poll_interval_ms=64\n
|
||||
A: device=0x9d2f\n
|
||||
A: dma_mask_bits=64\n
|
||||
L: driver=../../../bus/pci/drivers/xhci_hcd
|
||||
A: driver_override=(null)\n
|
||||
A: enable=1\n
|
||||
L: firmware_node=../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1d
|
||||
L: iommu=../../virtual/iommu/dmar1
|
||||
L: iommu_group=../../../kernel/iommu_groups/4
|
||||
A: irq=128\n
|
||||
A: local_cpulist=0-7\n
|
||||
A: local_cpus=ff\n
|
||||
A: modalias=pci:v00008086d00009D2Fsv000017AAsd00002258bc0Csc03i30\n
|
||||
A: msi_bus=1\n
|
||||
A: msi_irqs/128=msi\n
|
||||
A: msi_irqs/129=msi\n
|
||||
A: msi_irqs/130=msi\n
|
||||
A: msi_irqs/131=msi\n
|
||||
A: msi_irqs/132=msi\n
|
||||
A: msi_irqs/133=msi\n
|
||||
A: msi_irqs/134=msi\n
|
||||
A: msi_irqs/135=msi\n
|
||||
A: numa_node=-1\n
|
||||
A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 1 32 128 1\nbuffer-32 0 0 32 0\nxHCI 256 port bw ctx arrays 0 0 256 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 12 13 2112 13\nxHCI ring segments 45 45 4096 45\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 3 32 128 1\nbuffer-32 0 0 32 0\n
|
||||
A: power/control=auto\n
|
||||
A: power/runtime_active_time=8465365\n
|
||||
A: power/runtime_status=active\n
|
||||
A: power/runtime_suspended_time=0\n
|
||||
A: power/wakeup=enabled\n
|
||||
A: power/wakeup_abort_count=0\n
|
||||
A: power/wakeup_active=0\n
|
||||
A: power/wakeup_active_count=0\n
|
||||
A: power/wakeup_count=0\n
|
||||
A: power/wakeup_expire_count=0\n
|
||||
A: power/wakeup_last_time_ms=0\n
|
||||
A: power/wakeup_max_time_ms=0\n
|
||||
A: power/wakeup_total_time_ms=0\n
|
||||
A: power_state=D0\n
|
||||
A: resource=0x00000000e8320000 0x00000000e832ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n
|
||||
A: revision=0x21\n
|
||||
A: subsystem_device=0x2258\n
|
||||
A: subsystem_vendor=0x17aa\n
|
||||
A: vendor=0x8086\n
|
||||
|
||||
Loading…
Add table
Reference in a new issue