diff --git a/libfprint/drivers/crfpmoc/crfpmoc.c b/libfprint/drivers/crfpmoc/crfpmoc.c index c2ec9e04..3bbc58dd 100644 --- a/libfprint/drivers/crfpmoc/crfpmoc.c +++ b/libfprint/drivers/crfpmoc/crfpmoc.c @@ -20,7 +20,8 @@ #define FP_COMPONENT "crfpmoc" -#include +#include +#include #include "drivers_api.h" #include "crfpmoc.h" @@ -47,36 +48,36 @@ static const FpIdEntry crfpmoc_id_table[] = { }; static const gchar *const crfpmoc_meanings[] = { - "SUCCESS", - "INVALID_COMMAND", - "ERROR", - "INVALID_PARAM", - "ACCESS_DENIED", - "INVALID_RESPONSE", - "INVALID_VERSION", - "INVALID_CHECKSUM", - "IN_PROGRESS", - "UNAVAILABLE", - "TIMEOUT", - "OVERFLOW", - "INVALID_HEADER", - "REQUEST_TRUNCATED", - "RESPONSE_TOO_BIG", - "BUS_ERROR", - "BUSY", - "INVALID_HEADER_VERSION", - "INVALID_HEADER_CRC", - "INVALID_DATA_CRC", - "DUP_UNAVAILABLE", + "SUCCESS", + "INVALID_COMMAND", + "ERROR", + "INVALID_PARAM", + "ACCESS_DENIED", + "INVALID_RESPONSE", + "INVALID_VERSION", + "INVALID_CHECKSUM", + "IN_PROGRESS", + "UNAVAILABLE", + "TIMEOUT", + "OVERFLOW", + "INVALID_HEADER", + "REQUEST_TRUNCATED", + "RESPONSE_TOO_BIG", + "BUS_ERROR", + "BUSY", + "INVALID_HEADER_VERSION", + "INVALID_HEADER_CRC", + "INVALID_DATA_CRC", + "DUP_UNAVAILABLE", }; static const gchar * crfpmoc_strresult (int i) { int crfpmoc_meanings_len = sizeof (crfpmoc_meanings) / sizeof (crfpmoc_meanings[0]); - if (i < 0 || i >= crfpmoc_meanings_len) - return ""; - return crfpmoc_meanings[i]; + if (i < 0 || i >= crfpmoc_meanings_len) + return ""; + return crfpmoc_meanings[i]; } static char * @@ -145,15 +146,6 @@ crfpmoc_ec_command (FpiDeviceCrfpMoc *self, int command, int version, const void fp_warn ("ioctl %d, errno %d (%s), EC result %d (%s)", r, errno, strerror (errno), s_cmd->result, crfpmoc_strresult (s_cmd->result)); } } - else if (errno == ETIMEDOUT) - { - g_usleep (CRFPMOC_TIMEOUT_RETRY_DELAY_MICROSECONDS); - r = ioctl (self->fd, CRFPMOC_CROS_EC_DEV_IOCXCMD_V2, s_cmd); - if (r < 0) - { - fp_warn ("ioctl %d, errno %d (%s), EC result %d (%s)", r, errno, strerror (errno), s_cmd->result, crfpmoc_strresult (s_cmd->result)); - } - } else { fp_warn ("ioctl %d, errno %d (%s), EC result %d (%s)", r, errno, strerror (errno), s_cmd->result, crfpmoc_strresult (s_cmd->result)); @@ -177,11 +169,37 @@ crfpmoc_ec_command (FpiDeviceCrfpMoc *self, int command, int version, const void return r; } +static int +crfpmoc_ec_pollevent (FpiDeviceCrfpMoc *self, unsigned long mask, void *buffer, size_t buf_size, int timeout) +{ + int rv; + struct pollfd pf = { .fd = self->fd, .events = POLLIN }; + + rv = ioctl (self->fd, CRFPMOC_CROS_EC_DEV_IOCEVENTMASK_V2, mask); + if (rv < 0) + { + return -rv; + } + + rv = poll (&pf, 1, timeout); + if (rv != 1) + { + return rv; + } + + if (pf.revents != POLLIN) + { + return -pf.revents; + } + + return read (self->fd, buffer, buf_size); +} + static int crfpmoc_cmd_fp_mode (FpiDeviceCrfpMoc *self, guint32 inmode, guint32 *outmode, const gchar **error_msg) { struct crfpmoc_ec_params_fp_mode p; - struct crfpmoc_ec_response_fp_mode r; + struct crfpmoc_ec_response_fp_mode r; int rv; p.mode = inmode; @@ -240,6 +258,30 @@ crfpmoc_cmd_fp_stats (FpiDeviceCrfpMoc *self, gint8 *template, const gchar **err return 0; } +static int +crfpmoc_cmd_wait_event_fingerprint (FpiDeviceCrfpMoc *self) +{ + int rv; + struct crfpmoc_ec_response_get_next_event_v1 buffer; + long timeout = 5000; + long event_type = CRFPMOC_EC_MKBP_EVENT_FINGERPRINT; + + rv = crfpmoc_ec_pollevent (self, 1 << event_type, &buffer, sizeof (buffer), timeout); + if (rv == 0) + { + fp_warn ("Timeout waiting for MKBP event"); + return -ETIMEDOUT; + } + else if (rv < 0) + { + fp_warn ("Error polling for MKBP event"); + return -EIO; + } + + fp_dbg ("MKBP event %d data", buffer.event_type); + return 0; +} + static void crfpmoc_task_ssm_done (FpiSsm *ssm, FpDevice *device, GError *error) { @@ -345,7 +387,22 @@ crfpmoc_enroll_run_state (FpiSsm *ssm, FpDevice *device) case ENROLL_WAIT_FINGER: fpi_device_report_finger_status (device, FP_FINGER_STATUS_NEEDED); - fpi_ssm_next_state (ssm); + r = crfpmoc_cmd_wait_event_fingerprint (self); + if (r < 0) + { + if (r == -ETIMEDOUT) + { + fpi_ssm_jump_to_state (ssm, ENROLL_WAIT_FINGER); + } + else + { + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + } + } + else + { + fpi_ssm_next_state (ssm); + } break; case ENROLL_SENSOR_CHECK: @@ -454,7 +511,22 @@ crfpmoc_verify_run_state (FpiSsm *ssm, FpDevice *device) case VERIFY_WAIT_FINGER: fpi_device_report_finger_status (device, FP_FINGER_STATUS_NEEDED); - fpi_ssm_next_state (ssm); + r = crfpmoc_cmd_wait_event_fingerprint (self); + if (r < 0) + { + if (r == -ETIMEDOUT) + { + fpi_ssm_jump_to_state (ssm, VERIFY_WAIT_FINGER); + } + else + { + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + } + } + else + { + fpi_ssm_next_state (ssm); + } break; case VERIFY_SENSOR_CHECK: diff --git a/libfprint/drivers/crfpmoc/crfpmoc.h b/libfprint/drivers/crfpmoc/crfpmoc.h index 64475f70..5cf55c6a 100644 --- a/libfprint/drivers/crfpmoc/crfpmoc.h +++ b/libfprint/drivers/crfpmoc/crfpmoc.h @@ -37,8 +37,6 @@ G_DECLARE_FINAL_TYPE (FpiDeviceCrfpMoc, fpi_device_crfpmoc, FPI, DEVICE_CRFPMOC, #define CRFPMOC_NR_ENROLL_STAGES 5 -#define CRFPMOC_TIMEOUT_RETRY_DELAY_MICROSECONDS 100000 - /* crfpmoc_ec_command return value for non-success result from EC */ #define CRFPMOC_EECRESULT 1000 @@ -62,45 +60,96 @@ G_DECLARE_FINAL_TYPE (FpiDeviceCrfpMoc, fpi_device_crfpmoc, FPI, DEVICE_CRFPMOC, #define CRFPMOC_FPSTATS_MATCHING_INV (1U << 1) +/* New Fingerprint sensor event, the event data is fp_events bitmap. */ +#define CRFPMOC_EC_MKBP_EVENT_FINGERPRINT 5 + struct crfpmoc_ec_params_fp_mode { - guint32 mode; /* as defined by CRFPMOC_FP_MODE_ constants */ + guint32 mode; /* as defined by CRFPMOC_FP_MODE_ constants */ } __attribute__((packed)); struct crfpmoc_ec_response_fp_mode { - guint32 mode; /* as defined by CRFPMOC_FP_MODE_ constants */ + guint32 mode; /* as defined by CRFPMOC_FP_MODE_ constants */ } __attribute__((packed)); struct crfpmoc_ec_response_fp_stats { - guint32 capture_time_us; - guint32 matching_time_us; - guint32 overall_time_us; - struct { - guint32 lo; - guint32 hi; - } overall_t0; - guint8 timestamps_invalid; - gint8 template_matched; + guint32 capture_time_us; + guint32 matching_time_us; + guint32 overall_time_us; + struct { + guint32 lo; + guint32 hi; + } overall_t0; + guint8 timestamps_invalid; + gint8 template_matched; } __attribute__((packed)); struct crfpmoc_ec_response_fp_info { - /* Sensor identification */ - guint32 vendor_id; - guint32 product_id; - guint32 model_id; - guint32 version; - /* Image frame characteristics */ - guint32 frame_size; - guint32 pixel_format; - guint16 width; - guint16 height; - guint16 bpp; - guint16 errors; - /* Template/finger current information */ - guint32 template_size; /* max template size in bytes */ - guint16 template_max; /* maximum number of fingers/templates */ - guint16 template_valid; /* number of valid fingers/templates */ - guint32 template_dirty; /* bitmap of templates with MCU side changes */ - guint32 template_version; /* version of the template format */ + /* Sensor identification */ + guint32 vendor_id; + guint32 product_id; + guint32 model_id; + guint32 version; + /* Image frame characteristics */ + guint32 frame_size; + guint32 pixel_format; + guint16 width; + guint16 height; + guint16 bpp; + guint16 errors; + /* Template/finger current information */ + guint32 template_size; /* max template size in bytes */ + guint16 template_max; /* maximum number of fingers/templates */ + guint16 template_valid; /* number of valid fingers/templates */ + guint32 template_dirty; /* bitmap of templates with MCU side changes */ + guint32 template_version; /* version of the template format */ +} __attribute__((packed)); + +/* Note: used in crfpmoc_ec_response_get_next_data_v1 */ +struct crfpmoc_ec_response_motion_sense_fifo_info { + /* Size of the fifo */ + guint16 size; + /* Amount of space used in the fifo */ + guint16 count; + /* Timestamp recorded in us. + * aka accurate timestamp when host event was triggered. + */ + guint32 timestamp; + /* Total amount of vector lost */ + guint16 total_lost; + /* Lost events since the last fifo_info, per sensors */ + guint16 lost[0]; +}; + +union __attribute__((packed)) crfpmoc_ec_response_get_next_data_v1 { + guint8 key_matrix[16]; + + /* Unaligned */ + guint32 host_event; + guint64 host_event64; + + struct { + /* For aligning the fifo_info */ + guint8 reserved[3]; + struct crfpmoc_ec_response_motion_sense_fifo_info info; + } sensor_fifo; + + guint32 buttons; + + guint32 switches; + + guint32 fp_events; + + guint32 sysrq; + + guint32 cec_events; + + guint8 cec_message[16]; +}; + +struct crfpmoc_ec_response_get_next_event_v1 { + guint8 event_type; + /* Followed by event data if any */ + union crfpmoc_ec_response_get_next_data_v1 data; } __attribute__((packed)); /* @@ -112,47 +161,48 @@ struct crfpmoc_ec_response_fp_info { * @data: Where to put the incoming data from EC and outgoing data to EC */ struct crfpmoc_cros_ec_command_v2 { - guint32 version; - guint32 command; - guint32 outsize; - guint32 insize; - guint32 result; - guint8 data[0]; + guint32 version; + guint32 command; + guint32 outsize; + guint32 insize; + guint32 result; + guint8 data[0]; }; #define CRFPMOC_CROS_EC_DEV_IOC_V2 0xEC #define CRFPMOC_CROS_EC_DEV_IOCXCMD_V2 \ - _IOWR(CRFPMOC_CROS_EC_DEV_IOC_V2, 0, struct crfpmoc_cros_ec_command_v2) + _IOWR(CRFPMOC_CROS_EC_DEV_IOC_V2, 0, struct crfpmoc_cros_ec_command_v2) +#define CRFPMOC_CROS_EC_DEV_IOCEVENTMASK_V2 _IO(CRFPMOC_CROS_EC_DEV_IOC_V2, 2) /* * Host command response codes (16-bit). */ enum crfpmoc_ec_status { - EC_RES_SUCCESS = 0, - EC_RES_INVALID_COMMAND = 1, - EC_RES_ERROR = 2, - EC_RES_INVALID_PARAM = 3, - EC_RES_ACCESS_DENIED = 4, - EC_RES_INVALID_RESPONSE = 5, - EC_RES_INVALID_VERSION = 6, - EC_RES_INVALID_CHECKSUM = 7, - EC_RES_IN_PROGRESS = 8, /* Accepted, command in progress */ - EC_RES_UNAVAILABLE = 9, /* No response available */ - EC_RES_TIMEOUT = 10, /* We got a timeout */ - EC_RES_OVERFLOW = 11, /* Table / data overflow */ - EC_RES_INVALID_HEADER = 12, /* Header contains invalid data */ - EC_RES_REQUEST_TRUNCATED = 13, /* Didn't get the entire request */ - EC_RES_RESPONSE_TOO_BIG = 14, /* Response was too big to handle */ - EC_RES_BUS_ERROR = 15, /* Communications bus error */ - EC_RES_BUSY = 16, /* Up but too busy. Should retry */ - EC_RES_INVALID_HEADER_VERSION = 17, /* Header version invalid */ - EC_RES_INVALID_HEADER_CRC = 18, /* Header CRC invalid */ - EC_RES_INVALID_DATA_CRC = 19, /* Data CRC invalid */ - EC_RES_DUP_UNAVAILABLE = 20, /* Can't resend response */ + EC_RES_SUCCESS = 0, + EC_RES_INVALID_COMMAND = 1, + EC_RES_ERROR = 2, + EC_RES_INVALID_PARAM = 3, + EC_RES_ACCESS_DENIED = 4, + EC_RES_INVALID_RESPONSE = 5, + EC_RES_INVALID_VERSION = 6, + EC_RES_INVALID_CHECKSUM = 7, + EC_RES_IN_PROGRESS = 8, /* Accepted, command in progress */ + EC_RES_UNAVAILABLE = 9, /* No response available */ + EC_RES_TIMEOUT = 10, /* We got a timeout */ + EC_RES_OVERFLOW = 11, /* Table / data overflow */ + EC_RES_INVALID_HEADER = 12, /* Header contains invalid data */ + EC_RES_REQUEST_TRUNCATED = 13, /* Didn't get the entire request */ + EC_RES_RESPONSE_TOO_BIG = 14, /* Response was too big to handle */ + EC_RES_BUS_ERROR = 15, /* Communications bus error */ + EC_RES_BUSY = 16, /* Up but too busy. Should retry */ + EC_RES_INVALID_HEADER_VERSION = 17, /* Header version invalid */ + EC_RES_INVALID_HEADER_CRC = 18, /* Header CRC invalid */ + EC_RES_INVALID_DATA_CRC = 19, /* Data CRC invalid */ + EC_RES_DUP_UNAVAILABLE = 20, /* Can't resend response */ - EC_RES_COUNT, + EC_RES_COUNT, - EC_RES_MAX = UINT16_MAX, /**< Force enum to be 16 bits */ + EC_RES_MAX = UINT16_MAX, /**< Force enum to be 16 bits */ } __attribute__((packed)); /* SSM task states and various status enums */ diff --git a/tests/crfpmoc/custom.ioctl b/tests/crfpmoc/custom.ioctl index b844abf0..b673acff 100644 --- a/tests/crfpmoc/custom.ioctl +++ b/tests/crfpmoc/custom.ioctl @@ -13,9 +13,9 @@ CROS_EC_DEV_IOCXCMD_V2 4 000000000204000004000000040000000000000000000000 CROS_EC_DEV_IOCXCMD_V2 48 010000000304000000000000300000000000000046504320090000001B020000010000009466000047524559A000A0000800FF0324140000050001000100000004000000 CROS_EC_DEV_IOCXCMD_V2 4 000000000204000004000000040000000000000040000000 CROS_EC_DEV_IOCXCMD_V2 4 000000000204000004000000040000000000000000000000 -CROS_EC_DEV_IOCXCMD_V2 22 000000000704000000000000160000000000000065630100B44A020007B30300DC33505A070000000000 +CROS_EC_DEV_IOCXCMD_V2 22 00000000070400000000000016000000000000007B630100C746020033AF0300FA095D6D040000000000 CROS_EC_DEV_IOCXCMD_V2 4 000000000204000004000000040000000000000040000000 CROS_EC_DEV_IOCXCMD_V2 4 000000000204000004000000040000000000000000000000 -CROS_EC_DEV_IOCXCMD_V2 22 000000000704000000000000160000000000000060630100874E0200D6B6030027289A5A070000000000 +CROS_EC_DEV_IOCXCMD_V2 22 00000000070400000000000016000000000000007F630100A949020019B20300FBAA6D6D040000000000 CROS_EC_DEV_IOCXCMD_V2 4 000000000204000004000000040000000000000080000000 CROS_EC_DEV_IOCXCMD_V2 4 000000000204000004000000040000000000000000000000 diff --git a/tests/crfpmoc/device b/tests/crfpmoc/device index 719b38e6..4da1d29f 100644 --- a/tests/crfpmoc/device +++ b/tests/crfpmoc/device @@ -60,9 +60,9 @@ E: SUBSYSTEM=serial-base L: driver=../../../../../bus/serial-base/drivers/port A: power/autosuspend_delay_ms=500\n A: power/control=auto\n -A: power/runtime_active_time=31736669\n +A: power/runtime_active_time=19045089\n A: power/runtime_status=active\n -A: power/runtime_suspended_time=5190\n +A: power/runtime_suspended_time=1840\n P: /devices/platform/AMDI0020:01/AMDI0020:01:0 E: DEVTYPE=ctrl @@ -70,9 +70,9 @@ E: DRIVER=ctrl E: SUBSYSTEM=serial-base L: driver=../../../../bus/serial-base/drivers/ctrl A: power/control=auto\n -A: power/runtime_active_time=31736676\n +A: power/runtime_active_time=19045095\n A: power/runtime_status=active\n -A: power/runtime_suspended_time=5190\n +A: power/runtime_suspended_time=1840\n P: /devices/platform/AMDI0020:01 E: DRIVER=dw-apb-uart @@ -86,8 +86,8 @@ A: driver_override=(null)\n L: firmware_node=../../LNXSYSTM:00/LNXSYBUS:00/AMDI0020:01 A: modalias=acpi:AMDI0020:\n A: power/control=auto\n -A: power/runtime_active_time=31736687\n +A: power/runtime_active_time=19045115\n A: power/runtime_status=active\n -A: power/runtime_suspended_time=5189\n +A: power/runtime_suspended_time=1826\n L: software_node=../../../kernel/software_nodes/node1