diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3f0925b8..e6f736cd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -109,6 +109,15 @@ test_indent: - git diff - "! git status -s | grep -q ." +test_unsupported_list: + stage: check-source + except: + variables: + - $CI_PIPELINE_SOURCE == "schedule" + allow_failure: true + script: + - tests/hwdb-check-unsupported.py + flatpak: stage: flatpak extends: .flatpak diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb new file mode 100644 index 00000000..14f45187 --- /dev/null +++ b/data/autosuspend.hwdb @@ -0,0 +1,264 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# This file has been generated using fprint-list-udev-hwdb with all drivers enabled + +# Supported by libfprint driver aes1610 +usb:v08FFp1600* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver aes1660 +usb:v08FFp1660* +usb:v08FFp1680* +usb:v08FFp1681* +usb:v08FFp1682* +usb:v08FFp1683* +usb:v08FFp1684* +usb:v08FFp1685* +usb:v08FFp1686* +usb:v08FFp1687* +usb:v08FFp1688* +usb:v08FFp1689* +usb:v08FFp168A* +usb:v08FFp168B* +usb:v08FFp168C* +usb:v08FFp168D* +usb:v08FFp168E* +usb:v08FFp168F* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver aes2501 +usb:v08FFp2500* +usb:v08FFp2580* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver aes2550 +usb:v08FFp2550* +usb:v08FFp2810* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver aes2660 +usb:v08FFp2660* +usb:v08FFp2680* +usb:v08FFp2681* +usb:v08FFp2682* +usb:v08FFp2683* +usb:v08FFp2684* +usb:v08FFp2685* +usb:v08FFp2686* +usb:v08FFp2687* +usb:v08FFp2688* +usb:v08FFp2689* +usb:v08FFp268A* +usb:v08FFp268B* +usb:v08FFp268C* +usb:v08FFp268D* +usb:v08FFp268E* +usb:v08FFp268F* +usb:v08FFp2691* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver aes3500 +usb:v08FFp5731* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver aes4000 +usb:v5501p08FF* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver elan +usb:v04F3p0903* +usb:v04F3p0907* +usb:v04F3p0C01* +usb:v04F3p0C02* +usb:v04F3p0C03* +usb:v04F3p0C04* +usb:v04F3p0C05* +usb:v04F3p0C06* +usb:v04F3p0C07* +usb:v04F3p0C08* +usb:v04F3p0C09* +usb:v04F3p0C0A* +usb:v04F3p0C0B* +usb:v04F3p0C0C* +usb:v04F3p0C0D* +usb:v04F3p0C0E* +usb:v04F3p0C0F* +usb:v04F3p0C10* +usb:v04F3p0C11* +usb:v04F3p0C12* +usb:v04F3p0C13* +usb:v04F3p0C14* +usb:v04F3p0C15* +usb:v04F3p0C16* +usb:v04F3p0C17* +usb:v04F3p0C18* +usb:v04F3p0C19* +usb:v04F3p0C1A* +usb:v04F3p0C1B* +usb:v04F3p0C1C* +usb:v04F3p0C1D* +usb:v04F3p0C1E* +usb:v04F3p0C1F* +usb:v04F3p0C20* +usb:v04F3p0C21* +usb:v04F3p0C22* +usb:v04F3p0C23* +usb:v04F3p0C24* +usb:v04F3p0C25* +usb:v04F3p0C26* +usb:v04F3p0C27* +usb:v04F3p0C28* +usb:v04F3p0C29* +usb:v04F3p0C2A* +usb:v04F3p0C2B* +usb:v04F3p0C2C* +usb:v04F3p0C2D* +usb:v04F3p0C2E* +usb:v04F3p0C2F* +usb:v04F3p0C30* +usb:v04F3p0C31* +usb:v04F3p0C32* +usb:v04F3p0C33* +usb:v04F3p0C42* +usb:v04F3p0C4D* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver etes603 +usb:v1C7Ap0603* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver goodixmoc +usb:v27C6p5840* +usb:v27C6p6496* +usb:v27C6p60A2* +usb:v27C6p63AC* +usb:v27C6p639C* +usb:v27C6p6594* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver synaptics +usb:v06CBp00BD* +usb:v06CBp00E9* +usb:v06CBp00DF* +usb:v06CBp00F9* +usb:v06CBp00FC* +usb:v06CBp00C2* +usb:v06CBp00C9* +usb:v06CBp00E7* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver upeksonly +usb:v147Ep2016* +usb:v147Ep1000* +usb:v147Ep1001* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver upektc +usb:v0483p2015* +usb:v147Ep3001* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver upektc_img +usb:v147Ep2020* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver uru4000 +usb:v045Ep00BC* +usb:v045Ep00BD* +usb:v045Ep00CA* +usb:v05BAp0007* +usb:v05BAp0008* +usb:v05BAp000A* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver vcom5s +usb:v061Ap0110* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver vfs0050 +usb:v138Ap0050* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver vfs101 +usb:v138Ap0001* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver vfs301 +usb:v138Ap0005* +usb:v138Ap0008* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver vfs5011 +usb:v138Ap0010* +usb:v138Ap0011* +usb:v138Ap0015* +usb:v138Ap0017* +usb:v138Ap0018* + ID_AUTOSUSPEND=1 + +# Known unsupported devices +usb:v04F3p036B* +usb:v04F3p0C00* +usb:v04F3p0C4B* +usb:v04F3p0C4C* +usb:v04F3p0C4F* +usb:v04F3p0C57* +usb:v04F3p2706* +usb:v06CBp0081* +usb:v06CBp0088* +usb:v06CBp008A* +usb:v06CBp009A* +usb:v06CBp009B* +usb:v06CBp00A2* +usb:v06CBp00B7* +usb:v06CBp00BB* +usb:v06CBp00BE* +usb:v06CBp00CB* +usb:v06CBp00D8* +usb:v06CBp00DA* +usb:v0A5Cp5801* +usb:v0A5Cp5805* +usb:v0A5Cp5834* +usb:v0A5Cp5843* +usb:v10A5p0007* +usb:v1188p9545* +usb:v138Ap0007* +usb:v138Ap003A* +usb:v138Ap003C* +usb:v138Ap003D* +usb:v138Ap003F* +usb:v138Ap0090* +usb:v138Ap0091* +usb:v138Ap0092* +usb:v138Ap0094* +usb:v138Ap0097* +usb:v138Ap009D* +usb:v138Ap00AB* +usb:v147Ep1002* +usb:v1491p0088* +usb:v16D1p1027* +usb:v1C7Ap0300* +usb:v1C7Ap0570* +usb:v1C7Ap0575* +usb:v27C6p5042* +usb:v27C6p5110* +usb:v27C6p5117* +usb:v27C6p5201* +usb:v27C6p521D* +usb:v27C6p5301* +usb:v27C6p530C* +usb:v27C6p532D* +usb:v27C6p533C* +usb:v27C6p5381* +usb:v27C6p5385* +usb:v27C6p538C* +usb:v27C6p538D* +usb:v27C6p5395* +usb:v27C6p5584* +usb:v27C6p55A2* +usb:v27C6p55A4* +usb:v27C6p55B4* +usb:v27C6p5740* +usb:v2808p9338* +usb:v298Dp2033* +usb:v3538p0930* + ID_AUTOSUSPEND=1 diff --git a/data/meson.build b/data/meson.build new file mode 100644 index 00000000..99adf5d7 --- /dev/null +++ b/data/meson.build @@ -0,0 +1,9 @@ +if get_option('udev_rules') + # This file has to be updated using + # ninja -C libfprint/sync-udev-hwdb + + install_data('autosuspend.hwdb', + rename: '60-autosuspend-@0@.hwdb'.format(versioned_libname), + install_dir: udev_hwdb_dir, + ) +endif diff --git a/libfprint/drivers/aes1660.h b/libfprint/drivers/aes1660.h index 18e4e0c9..452582d1 100644 --- a/libfprint/drivers/aes1660.h +++ b/libfprint/drivers/aes1660.h @@ -22,6 +22,8 @@ #define AES1660_FRAME_SIZE 0x244 +/* *INDENT-OFF* */ + /* First init sequence, 0x07 cmd returns following before INIT1: * { 0x07, 0x05, 0x00, 0x8f, 0x16, 0x25, 0x01, 0x00 } */ diff --git a/libfprint/drivers/aes2660.h b/libfprint/drivers/aes2660.h index 5427c80a..485b5809 100644 --- a/libfprint/drivers/aes2660.h +++ b/libfprint/drivers/aes2660.h @@ -21,6 +21,8 @@ #define AES2660_FRAME_SIZE 0x354 +/* *INDENT-OFF* */ + /* First init sequence, 0x07 cmd returns following before INIT1: * { 0x07, 0x05, 0x00, 0x91, 0x26, 0x21, 0x00, 0x00 } */ diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c index af64d814..77278c6e 100644 --- a/libfprint/drivers/goodixmoc/goodix.c +++ b/libfprint/drivers/goodixmoc/goodix.c @@ -58,6 +58,7 @@ struct _FpiDeviceGoodixMoc GPtrArray *list_result; guint8 template_id[TEMPLATE_ID_SIZE]; gboolean is_enroll_identify; + gboolean is_power_button_shield_on; }; @@ -127,7 +128,7 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer, } gx_proto_crc32_calc (transfer->buffer, PACKAGE_HEADER_SIZE + header.len, (uint8_t *) &crc32_calc); - if(crc32_calc != *(uint32_t *) (transfer->buffer + PACKAGE_HEADER_SIZE + header.len)) + if(crc32_calc != GUINT32_FROM_LE (*(uint32_t *) (transfer->buffer + PACKAGE_HEADER_SIZE + header.len))) { fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, @@ -309,6 +310,35 @@ goodix_sensor_cmd (FpiDeviceGoodixMoc *self, } + +/****************************************************************************** + * + * fp_pwr_btn_shield_cb Function + * + *****************************************************************************/ +static void +fp_pwr_btn_shield_cb (FpiDeviceGoodixMoc *self, + gxfp_cmd_response_t *resp, + GError *error) +{ + if (error) + { + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + if (resp->result >= GX_FAILED) + { + fp_dbg ("Setting power button shield failed, result: 0x%x", resp->result); + fpi_ssm_mark_failed (self->task_ssm, + fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); + return; + } + if (resp->power_button_shield_resp.resp_cmd1 == MOC_CMD1_PWR_BTN_SHIELD_ON) + self->is_power_button_shield_on = true; + else + self->is_power_button_shield_on = false; + fpi_ssm_next_state (self->task_ssm); +} /****************************************************************************** * * fp_verify_xxxx Function @@ -419,7 +449,7 @@ fp_verify_cb (FpiDeviceGoodixMoc *self, fpi_device_identify_report (device, NULL, NULL, error); } - fpi_ssm_mark_completed (self->task_ssm); + fpi_ssm_next_state (self->task_ssm); } @@ -436,6 +466,14 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device) switch (fpi_ssm_get_cur_state (ssm)) { + case FP_VERIFY_PWR_BTN_SHIELD_ON: + goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_ON, + false, + NULL, + 0, + fp_pwr_btn_shield_cb); + break; + case FP_VERIFY_CAPTURE: fpi_device_report_finger_status_changes (device, FP_FINGER_STATUS_NEEDED, @@ -454,6 +492,14 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device) TEMPLATE_ID_SIZE, fp_verify_cb); break; + + case FP_VERIFY_PWR_BTN_SHIELD_OFF: + goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_OFF, + false, + NULL, + 0, + fp_pwr_btn_shield_cb); + break; } } @@ -468,9 +514,9 @@ fp_verify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) if (error && error->domain == FP_DEVICE_RETRY) { if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY) - fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, error); + fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, g_steal_pointer (&error)); else - fpi_device_identify_report (dev, NULL, NULL, error); + fpi_device_identify_report (dev, NULL, NULL, g_steal_pointer (&error)); } if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY) @@ -812,6 +858,16 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device) } break; + case FP_ENROLL_PWR_BTN_SHIELD_ON: + { + goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_ON, + false, + NULL, + 0, + fp_pwr_btn_shield_cb); + } + break; + case FP_ENROLL_IDENTIFY: { dummy[0] = 0x01; @@ -926,9 +982,17 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device) } break; + + case FP_ENROLL_PWR_BTN_SHIELD_OFF: + { + goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_OFF, + false, + NULL, + 0, + fp_pwr_btn_shield_cb); + } + break; } - - } static void @@ -1282,6 +1346,7 @@ gx_fp_init (FpDevice *device) int ret = 0; self->max_stored_prints = FP_MAX_FINGERNUM; + self->is_power_button_shield_on = false; self->cancellable = g_cancellable_new (); @@ -1317,20 +1382,59 @@ gx_fp_init (FpDevice *device) } static void -gx_fp_exit (FpDevice *device) +gx_fp_release_interface (FpiDeviceGoodixMoc *self, + GError *error) { - FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); - GError *error = NULL; + g_autoptr(GError) release_error = NULL; g_clear_object (&self->cancellable); g_clear_pointer (&self->sensorcfg, g_free); /* Release usb interface */ - g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (device)), - 0, 0, &error); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), + 0, 0, &release_error); + /* Retain passed error if set, otherwise propagate error from release. */ + if (error == NULL) + error = g_steal_pointer (&release_error); /* Notify close complete */ fpi_device_close_complete (FP_DEVICE (self), error); + +} + +static void +gx_fp_exit_cb (FpiDeviceGoodixMoc *self, + gxfp_cmd_response_t *resp, + GError *error) +{ + + + if (resp->result >= GX_FAILED) + fp_dbg ("Setting power button shield failed, result: 0x%x", resp->result); + self->is_power_button_shield_on = false; + gx_fp_release_interface (self, error); +} + +static void +gx_fp_exit (FpDevice *device) +{ + FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); + + if (self->is_power_button_shield_on) + { + goodix_sensor_cmd (self, + MOC_CMD0_PWR_BTN_SHIELD, + MOC_CMD1_PWR_BTN_SHIELD_OFF, + false, + NULL, + 0, + gx_fp_exit_cb); + } + else + { + gx_fp_release_interface (self, NULL); + } + } @@ -1432,7 +1536,6 @@ fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self) static void gx_fp_cancel (FpDevice *device) { - FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); /* Cancel any current interrupt transfer (resulting us to go into @@ -1450,6 +1553,7 @@ static const FpIdEntry id_table[] = { { .vid = 0x27c6, .pid = 0x60A2, }, { .vid = 0x27c6, .pid = 0x63AC, }, { .vid = 0x27c6, .pid = 0x639C, }, + { .vid = 0x27c6, .pid = 0x6594, }, { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ }; diff --git a/libfprint/drivers/goodixmoc/goodix.h b/libfprint/drivers/goodixmoc/goodix.h index c38bf9b9..23e142ac 100644 --- a/libfprint/drivers/goodixmoc/goodix.h +++ b/libfprint/drivers/goodixmoc/goodix.h @@ -40,7 +40,8 @@ typedef enum { typedef enum { - FP_ENROLL_ENUM = 0, + FP_ENROLL_PWR_BTN_SHIELD_ON = 0, + FP_ENROLL_ENUM, FP_ENROLL_IDENTIFY, FP_ENROLL_CREATE, FP_ENROLL_CAPTURE, @@ -48,11 +49,14 @@ typedef enum { FP_ENROLL_WAIT_FINGER_UP, FP_ENROLL_CHECK_DUPLICATE, FP_ENROLL_COMMIT, + FP_ENROLL_PWR_BTN_SHIELD_OFF, FP_ENROLL_NUM_STATES, } FpEnrollState; typedef enum { - FP_VERIFY_CAPTURE = 0, + FP_VERIFY_PWR_BTN_SHIELD_ON = 0, + FP_VERIFY_CAPTURE, FP_VERIFY_IDENTIFY, + FP_VERIFY_PWR_BTN_SHIELD_OFF, FP_VERIFY_NUM_STATES, } FpVerifyState; diff --git a/libfprint/drivers/goodixmoc/goodix_proto.c b/libfprint/drivers/goodixmoc/goodix_proto.c index e30d23df..01044a94 100644 --- a/libfprint/drivers/goodixmoc/goodix_proto.c +++ b/libfprint/drivers/goodixmoc/goodix_proto.c @@ -141,8 +141,11 @@ crc32_update (gf_crc32_context *ctx, const uint8_t *message, uint32_t n_bytes) static void crc32_final (gf_crc32_context *ctx, uint8_t *md) { + uint32_t crc = 0; + ctx->crc = (REFLECT_REMAINDER (ctx->crc) ^ FINAL_XOR_VALUE); - memcpy (md, &ctx->crc, 4); + crc = GUINT32_TO_LE (ctx->crc); + memcpy (md, &crc, 4); } uint8_t @@ -184,7 +187,7 @@ init_pack_header ( pheader->cmd1 = LOBYTE (cmd); pheader->packagenum = packagenum; pheader->reserved = dump_seq++; - pheader->len = len + PACKAGE_CRC_SIZE; + pheader->len = GUINT16_TO_LE (len + PACKAGE_CRC_SIZE); pheader->crc8 = gx_proto_crc8_calc ((uint8_t *) pheader, 6); pheader->rev_crc8 = ~pheader->crc8; } @@ -224,14 +227,14 @@ gx_proto_parse_header ( { if (!buffer || !pheader) return -1; - if (buffer_len < PACKAGE_HEADER_SIZE) + if (buffer_len < PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE) return -1; memcpy (pheader, buffer, sizeof (pack_header)); - - pheader->len = GUINT16_FROM_LE ( *(uint16_t *) (buffer + 4)); + pheader->len = GUINT16_FROM_LE (pheader->len); + if (buffer_len < pheader->len + PACKAGE_HEADER_SIZE) + return -1; pheader->len -= PACKAGE_CRC_SIZE; - return 0; } @@ -248,7 +251,7 @@ gx_proto_parse_fingerid ( if (!template || !fid_buffer) return -1; - if (fid_buffer_size < 70) + if (fid_buffer_size < G_STRUCT_OFFSET (template_format_t, payload) + sizeof (uint32_t)) return -1; buffer = fid_buffer; @@ -256,28 +259,30 @@ gx_proto_parse_fingerid ( if (buffer[Offset++] != 67) return -1; + fid_buffer_size--; template->type = buffer[Offset++]; + fid_buffer_size--; template->finger_index = buffer[Offset++]; + fid_buffer_size--; Offset++; - - memcpy (template->accountid, &buffer[Offset], 32); - Offset += 32; - - memcpy (template->tid, &buffer[Offset], 32); - Offset += 32; // Offset == 68 - + memcpy (template->accountid, &buffer[Offset], sizeof (template->accountid)); + Offset += sizeof (template->accountid); + memcpy (template->tid, &buffer[Offset], sizeof (template->tid)); + Offset += sizeof (template->tid); // Offset == 68 template->payload.size = buffer[Offset++]; - memset (template->payload.data, 0, 56); + if (template->payload.size > sizeof (template->payload.data)) + return -1; + memset (template->payload.data, 0, template->payload.size); memcpy (template->payload.data, &buffer[Offset], template->payload.size); return 0; } int -gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_cmd_response_t presp) +gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint16_t buffer_len, pgxfp_cmd_response_t presp) { - uint32_t offset = 0; + uint16_t offset = 0; uint8_t *fingerlist = NULL; if (!buffer || !presp) @@ -289,6 +294,8 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_c { case RESPONSE_PACKAGE_CMD: { + if (buffer_len < sizeof (gxfp_parse_msg_t) + 1) + return -1; presp->parse_msg.ack_cmd = buffer[1]; } break; @@ -296,32 +303,56 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_c case MOC_CMD0_UPDATE_CONFIG: { presp->finger_config.status = buffer[0]; - presp->finger_config.max_stored_prints = buffer[2]; + if (buffer_len >= 3) + presp->finger_config.max_stored_prints = buffer[2]; + else + /* to compatiable old version firmware */ + presp->finger_config.max_stored_prints = FP_MAX_FINGERNUM; + } break; case MOC_CMD0_COMMITENROLLMENT: case MOC_CMD0_DELETETEMPLATE: + /* just check result */ + break; + + case MOC_CMD0_PWR_BTN_SHIELD: + presp->power_button_shield_resp.resp_cmd1 = LOBYTE (cmd); + if (buffer_len >= 2) + { + uint8_t support_pwr_shield = buffer[1]; + if (support_pwr_shield == 0xFF) + g_debug ("Power button shield feature not supported!\n"); + } break; case MOC_CMD0_GET_VERSION: + if (buffer_len < sizeof (gxfp_version_info_t) + 1) + return -1; memcpy (&presp->version_info, buffer + 1, sizeof (gxfp_version_info_t)); break; case MOC_CMD0_CAPTURE_DATA: if (LOBYTE (cmd) == MOC_CMD1_DEFAULT) { + if (buffer_len < sizeof (gxfp_capturedata_t) + 1) + return -1; presp->capture_data_resp.img_quality = buffer[1]; presp->capture_data_resp.img_coverage = buffer[2]; } break; case MOC_CMD0_ENROLL_INIT: + if (buffer_len < sizeof (gxfp_enroll_init_t) + 1) + return -1; if (presp->result == GX_SUCCESS) memcpy (&presp->enroll_init.tid, &buffer[1], TEMPLATE_ID_SIZE); break; case MOC_CMD0_ENROLL: + if (buffer_len < sizeof (gxfp_enroll_update_t)) + return -1; presp->enroll_update.rollback = (buffer[0] < 0x80) ? false : true; presp->enroll_update.img_overlay = buffer[1]; presp->enroll_update.img_preoverlay = buffer[2]; @@ -331,7 +362,11 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_c presp->check_duplicate_resp.duplicate = (presp->result == 0) ? false : true; if (presp->check_duplicate_resp.duplicate) { - uint16_t tid_size = GUINT16_FROM_LE (*(buffer + 1)); + if (buffer_len < 3) + return -1; + uint16_t tid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + 1)); + if ((buffer_len < tid_size + 3) || (buffer_len > sizeof (template_format_t)) + 3) + return -1; memcpy (&presp->check_duplicate_resp.template, buffer + 3, tid_size); } break; @@ -339,18 +374,16 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_c case MOC_CMD0_GETFINGERLIST: if (presp->result != GX_SUCCESS) break; + if (buffer_len < 2) + return -1; presp->finger_list_resp.finger_num = buffer[1]; - if (presp->finger_list_resp.finger_num > FP_MAX_FINGERNUM) - { - presp->finger_list_resp.finger_num = 0; - presp->result = GX_ERROR_NO_AVAILABLE_SPACE; - break; - } fingerlist = buffer + 2; for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++) { - uint16_t fingerid_length = GUINT16_FROM_LE (*(fingerlist + offset)); + uint16_t fingerid_length = GUINT16_FROM_LE (*(uint16_t *) (fingerlist + offset)); offset += 2; + if (buffer_len < fingerid_length + offset + 2) + return -1; if (gx_proto_parse_fingerid (fingerlist + offset, fingerid_length, &presp->finger_list_resp.finger_list[num]) != 0) @@ -372,14 +405,16 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_c presp->verify.match = (buffer[0] == 0) ? true : false; if (presp->verify.match) { + if (buffer_len < sizeof (template_format_t) + 10) + return -1; offset += 1; - presp->verify.rejectdetail = GUINT16_FROM_LE (*(buffer + offset)); + presp->verify.rejectdetail = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset)); offset += 2; - score = GUINT32_FROM_LE (*(buffer + offset)); + score = GUINT32_FROM_LE (*(uint32_t *) (buffer + offset)); offset += 4; - study = GUINT16_FROM_LE (*(buffer + offset)); + study = buffer[offset]; offset += 1; - fingerid_size = GUINT16_FROM_LE (*(buffer + offset)); + fingerid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset)); offset += 2; if (gx_proto_parse_fingerid (buffer + offset, fingerid_size, &presp->verify.template) != 0) { diff --git a/libfprint/drivers/goodixmoc/goodix_proto.h b/libfprint/drivers/goodixmoc/goodix_proto.h index 53eea046..bcd1cdd0 100644 --- a/libfprint/drivers/goodixmoc/goodix_proto.h +++ b/libfprint/drivers/goodixmoc/goodix_proto.h @@ -75,6 +75,11 @@ #define MOC_CMD1_GET_FINGER_MODE 0x00 #define MOC_CMD1_SET_FINGER_DOWN 0x01 #define MOC_CMD1_SET_FINGER_UP 0x02 + +#define MOC_CMD0_PWR_BTN_SHIELD 0xE0 +#define MOC_CMD1_PWR_BTN_SHIELD_OFF 0x00 +#define MOC_CMD1_PWR_BTN_SHIELD_ON 0x01 + /* */ typedef struct _gxfp_version_info @@ -89,7 +94,7 @@ typedef struct _gxfp_version_info uint8_t interface[GX_VERSION_LEN]; uint8_t protocol[GX_VERSION_LEN]; uint8_t flashVersion[GX_VERSION_LEN]; - uint8_t reserved[62]; + uint8_t reserved[38]; } gxfp_version_info_t, *pgxfp_version_info_t; @@ -173,6 +178,11 @@ typedef struct _fp_finger_config uint8_t max_stored_prints; } fp_finger_config_t, *pfp_finger_config_t; +typedef struct _fp_pwr_btn_shield +{ + uint8_t resp_cmd1; +} fp_pwr_btn_shield_t, *pfp_pwr_btn_shield_t; + typedef struct _fp_cmd_response { uint8_t result; @@ -189,6 +199,7 @@ typedef struct _fp_cmd_response gxfp_version_info_t version_info; fp_finger_status_t finger_status; fp_finger_config_t finger_config; + fp_pwr_btn_shield_t power_button_shield_resp; }; } gxfp_cmd_response_t, *pgxfp_cmd_response_t; @@ -225,7 +236,7 @@ int gx_proto_parse_header (uint8_t *buffer, int gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, - uint32_t buffer_len, + uint16_t buffer_len, pgxfp_cmd_response_t presponse); int gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig); diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index b4711faf..b2db9bde 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -348,7 +348,7 @@ synaptics_sensor_cmd (FpiDeviceSynaptics *self, * may only be a cancellation currently). */ if (seq_num <= 0) { - self->last_seq_num = MAX (1, self->last_seq_num + 1); + self->last_seq_num = MAX (1, (self->last_seq_num + 1) & 0xff); real_seq_num = self->last_seq_num; if (seq_num == 0) self->cmd_seq_num = self->last_seq_num; diff --git a/libfprint/drivers/upektc.h b/libfprint/drivers/upektc.h index a1f9a231..58c4a0cc 100644 --- a/libfprint/drivers/upektc.h +++ b/libfprint/drivers/upektc.h @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/* *INDENT-OFF* */ + #pragma once #define UPEKTC_CMD_LEN 0x40 diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c index 0e67b2dc..f5d5d85b 100644 --- a/libfprint/drivers/uru4000.c +++ b/libfprint/drivers/uru4000.c @@ -375,6 +375,10 @@ stop_irq_handler (FpImageDevice *dev, irqs_stopped_cb_fn cb) g_cancellable_cancel (self->irq_cancellable); self->irqs_stopped_cb = cb; } + else + { + cb (dev); + } } /***** STATE CHANGING *****/ diff --git a/libfprint/drivers/vfs301_proto_fragments.h b/libfprint/drivers/vfs301_proto_fragments.h index 6decbc79..9691bc8f 100644 --- a/libfprint/drivers/vfs301_proto_fragments.h +++ b/libfprint/drivers/vfs301_proto_fragments.h @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/* *INDENT-OFF* */ + /* There are many similar blocks in the data below, also the data are * self-similar (looks like some config blocks? pokes like in vfs101?) */ @@ -1621,56 +1623,56 @@ static const unsigned char vfs301_24[] = { /* 119 B */ #define vfs301_02D0_ALIGNED_BLOB \ PACKET ("0200", "8005", \ "FF830720" "5F820720" "FF830720" \ - "5F820720" "FF830720" "5F820720" "FF830720" \ - "5F820720" "FF830720" "5F820720" "FF8B0720" \ - "608A0720" "FF930720" "61920720" "FF9B0720" \ - "629A0720" "FFA30720" "63A20720" "FFAB0720" \ - "64AA0720" "FFB30720" "65B20720" "FFBB0720" \ - "66BA0720" "FFC30720" "67C20720" "FFCB0720" \ - "68CA0720" "FFD30720" "69D20720" "FFDB0720" \ - "6ADA0720" "FFE30720" "6BE20720" "FFEB0720" \ - "6CEA0720" "FFF30720" "6DF20720" "FFFB0720" \ - "6EFA0720" "FF850720" "6F840720" "FF8D0720" \ - "708C0720" "FF950720" "71940720" "FF9D0720" \ - "729C0720" "FFA50720" "73A40720" "FFAD0720" \ - "74AC0720" "FFB50720" "75B40720" "FFBD0720" \ - "76BC0720" "FFC50720" "77C40720" "FFCD0720" \ - "78CC0720" "FFD50720" "79D40720" "FFDD0720" \ - "7ADC0720" "FFE50720" "7BE40720" "FFED0720" \ - "7CEC0720" "FFF50720" "7DF40720" "FFFD0720" \ - "7EFC0720" "FF870720" "7F860720" "FF8F0720" \ - "808E0720" "FF970720" "81960720" "FF9F0720" \ - "829E0720" "FFA70720" "83A60720" "FFAF0720" \ - "84AE0720" "FFB70720" "85B60720" "FFBF0720" \ - "86BE0720" "FFC70720" "87C60720" "FFCF0720" \ - "88CE0720" "FFD70720" "89D60720" "FFDF0720" \ - "8ADE0720" "FFE70720" "8BE60720" "FFEF0720" \ - "8CEE0720" "FFF70720" "8DF60720" "FFFF0720" \ - "8EFE0720" \ - "FFFF0720" "8EFE0720" "FFF70720" "8DF60720" \ - "FFEF0720" "8CEE0720" "FFE70720" "8BE60720" \ - "FFDF0720" "8ADE0720" "FFD70720" "89D60720" \ - "FFCF0720" "88CE0720" "FFC70720" "87C60720" \ - "FFBF0720" "86BE0720" "FFB70720" "85B60720" \ - "FFAF0720" "84AE0720" "FFA70720" "83A60720" \ - "FF9F0720" "829E0720" "FF970720" "81960720" \ - "FF8F0720" "808E0720" "FF870720" "7F860720" \ - "FFFD0720" "7EFC0720" "FFF50720" "7DF40720" \ - "FFED0720" "7CEC0720" "FFE50720" "7BE40720" \ - "FFDD0720" "7ADC0720" "FFD50720" "79D40720" \ - "FFCD0720" "78CC0720" "FFC50720" "77C40720" \ - "FFBD0720" "76BC0720" "FFB50720" "75B40720" \ - "FFAD0720" "74AC0720" "FFA50720" "73A40720" \ - "FF9D0720" "729C0720" "FF950720" "71940720" \ - "FF8D0720" "708C0720" "FF850720" "6F840720" \ - "FFFB0720" "6EFA0720" "FFF30720" "6DF20720" \ - "FFEB0720" "6CEA0720" "FFE30720" "6BE20720" \ - "FFDB0720" "6ADA0720" "FFD30720" "69D20720" \ - "FFCB0720" "68CA0720" "FFC30720" "67C20720" \ - "FFBB0720" "66BA0720" "FFB30720" "65B20720" \ - "FFAB0720" "64AA0720" "FFA30720" "63A20720" \ - "FF9B0720" "629A0720" "FF930720" "61920720" \ - "FF8B0720" "608A0720" "FF830720" "5F820720" \ + "5F820720" "FF830720" "5F820720" "FF830720" \ + "5F820720" "FF830720" "5F820720" "FF8B0720" \ + "608A0720" "FF930720" "61920720" "FF9B0720" \ + "629A0720" "FFA30720" "63A20720" "FFAB0720" \ + "64AA0720" "FFB30720" "65B20720" "FFBB0720" \ + "66BA0720" "FFC30720" "67C20720" "FFCB0720" \ + "68CA0720" "FFD30720" "69D20720" "FFDB0720" \ + "6ADA0720" "FFE30720" "6BE20720" "FFEB0720" \ + "6CEA0720" "FFF30720" "6DF20720" "FFFB0720" \ + "6EFA0720" "FF850720" "6F840720" "FF8D0720" \ + "708C0720" "FF950720" "71940720" "FF9D0720" \ + "729C0720" "FFA50720" "73A40720" "FFAD0720" \ + "74AC0720" "FFB50720" "75B40720" "FFBD0720" \ + "76BC0720" "FFC50720" "77C40720" "FFCD0720" \ + "78CC0720" "FFD50720" "79D40720" "FFDD0720" \ + "7ADC0720" "FFE50720" "7BE40720" "FFED0720" \ + "7CEC0720" "FFF50720" "7DF40720" "FFFD0720" \ + "7EFC0720" "FF870720" "7F860720" "FF8F0720" \ + "808E0720" "FF970720" "81960720" "FF9F0720" \ + "829E0720" "FFA70720" "83A60720" "FFAF0720" \ + "84AE0720" "FFB70720" "85B60720" "FFBF0720" \ + "86BE0720" "FFC70720" "87C60720" "FFCF0720" \ + "88CE0720" "FFD70720" "89D60720" "FFDF0720" \ + "8ADE0720" "FFE70720" "8BE60720" "FFEF0720" \ + "8CEE0720" "FFF70720" "8DF60720" "FFFF0720" \ + "8EFE0720" \ + "FFFF0720" "8EFE0720" "FFF70720" "8DF60720" \ + "FFEF0720" "8CEE0720" "FFE70720" "8BE60720" \ + "FFDF0720" "8ADE0720" "FFD70720" "89D60720" \ + "FFCF0720" "88CE0720" "FFC70720" "87C60720" \ + "FFBF0720" "86BE0720" "FFB70720" "85B60720" \ + "FFAF0720" "84AE0720" "FFA70720" "83A60720" \ + "FF9F0720" "829E0720" "FF970720" "81960720" \ + "FF8F0720" "808E0720" "FF870720" "7F860720" \ + "FFFD0720" "7EFC0720" "FFF50720" "7DF40720" \ + "FFED0720" "7CEC0720" "FFE50720" "7BE40720" \ + "FFDD0720" "7ADC0720" "FFD50720" "79D40720" \ + "FFCD0720" "78CC0720" "FFC50720" "77C40720" \ + "FFBD0720" "76BC0720" "FFB50720" "75B40720" \ + "FFAD0720" "74AC0720" "FFA50720" "73A40720" \ + "FF9D0720" "729C0720" "FF950720" "71940720" \ + "FF8D0720" "708C0720" "FF850720" "6F840720" \ + "FFFB0720" "6EFA0720" "FFF30720" "6DF20720" \ + "FFEB0720" "6CEA0720" "FFE30720" "6BE20720" \ + "FFDB0720" "6ADA0720" "FFD30720" "69D20720" \ + "FFCB0720" "68CA0720" "FFC30720" "67C20720" \ + "FFBB0720" "66BA0720" "FFB30720" "65B20720" \ + "FFAB0720" "64AA0720" "FFA30720" "63A20720" \ + "FF9B0720" "629A0720" "FF930720" "61920720" \ + "FF8B0720" "608A0720" "FF830720" "5F820720" \ Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ @@ -1871,49 +1873,49 @@ const char *vfs301_0220_01[] = { "A46C0420" "A46C0400" "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () @@ -2268,55 +2270,55 @@ const char *vfs301_02D0_04[] = { * any troubles. */ PACKET ("0200", "8005", "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () @@ -2437,55 +2439,55 @@ const char *vfs301_02D0_05[] = { * any troubles. */ PACKET ("0200", "8005", "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () diff --git a/libfprint/drivers/vfs5011_proto.h b/libfprint/drivers/vfs5011_proto.h index 5b2f8f41..e49cd800 100644 --- a/libfprint/drivers/vfs5011_proto.h +++ b/libfprint/drivers/vfs5011_proto.h @@ -1,5 +1,7 @@ #pragma once +/* *INDENT-OFF* */ + #define VFS5011_LINE_SIZE 240 #define VFS5011_IMAGE_WIDTH 160 diff --git a/libfprint/drivers/virtual-device-listener.c b/libfprint/drivers/virtual-device-listener.c new file mode 100644 index 00000000..50fe95fa --- /dev/null +++ b/libfprint/drivers/virtual-device-listener.c @@ -0,0 +1,355 @@ +/* + * Socket utilities for "simple" device debugging + * + * Copyright (C) 2019 Benjamin Berg + * Copyright (C) 2020 Marco Trevisan + * + * 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 "virtual_device_connection" + +#include "fpi-log.h" + +#include +#include + +#include "virtual-device-private.h" + +struct _FpDeviceVirtualListener +{ + GSocketListener parent_instance; + + GSocketConnection *connection; + GCancellable *cancellable; + guint cancellable_id; + + FpDeviceVirtualListenerConnectionCb ready_cb; + gpointer ready_cb_data; + + gint socket_fd; + gint client_fd; +}; + +G_DEFINE_TYPE (FpDeviceVirtualListener, fp_device_virtual_listener, G_TYPE_SOCKET_LISTENER) + +static void start_listen (FpDeviceVirtualListener *self); + +FpDeviceVirtualListener * +fp_device_virtual_listener_new (void) +{ + return g_object_new (fp_device_virtual_listener_get_type (), NULL); +} + +static void +fp_device_virtual_listener_dispose (GObject *object) +{ + FpDeviceVirtualListener *self = FP_DEVICE_VIRTUAL_LISTENER (object); + + if (self->cancellable_id) + { + g_cancellable_disconnect (self->cancellable, self->cancellable_id); + self->cancellable_id = 0; + } + + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->cancellable); + g_clear_object (&self->connection); + + self->ready_cb = NULL; + + G_OBJECT_CLASS (fp_device_virtual_listener_parent_class)->dispose (object); +} + +static void +fp_device_virtual_listener_class_init (FpDeviceVirtualListenerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = fp_device_virtual_listener_dispose; +} + +static void +fp_device_virtual_listener_init (FpDeviceVirtualListener *self) +{ +} + +static void +new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GError) error = NULL; + FpDeviceVirtualListener *self = user_data; + GSocketConnection *connection; + + connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object), + res, + NULL, + &error); + if (!connection) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + g_warning ("Error accepting a new connection: %s", error->message); + start_listen (self); + return; + } + + /* Always allow further connections. + * If we get a new one, we generally just close the old connection. */ + start_listen (self); + if (self->connection) + { + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); + g_clear_object (&self->connection); + } + + self->connection = connection; + fp_dbg ("Got a new connection!"); + + self->ready_cb (self, self->ready_cb_data); +} + +static void +start_listen (FpDeviceVirtualListener *self) +{ + g_socket_listener_accept_async (G_SOCKET_LISTENER (self), + self->cancellable, + new_connection_cb, + self); +} + +static void +on_cancelled (GCancellable *cancellable, + FpDeviceVirtualListener *self) +{ + fp_device_virtual_listener_connection_close (self); + g_socket_listener_close (G_SOCKET_LISTENER (self)); + g_clear_object (&self->cancellable); + self->ready_cb = NULL; +} + +gboolean +fp_device_virtual_listener_start (FpDeviceVirtualListener *self, + const char *address, + GCancellable *cancellable, + FpDeviceVirtualListenerConnectionCb cb, + gpointer user_data, + GError **error) +{ + g_autoptr(GSocketAddress) addr = NULL; + G_DEBUG_HERE (); + + g_return_val_if_fail (FP_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE); + g_return_val_if_fail (cb != NULL, FALSE); + g_return_val_if_fail (self->ready_cb == NULL, FALSE); + + self->client_fd = -1; + + g_socket_listener_set_backlog (G_SOCKET_LISTENER (self), 1); + + /* Remove any left over socket. */ + g_unlink (address); + + addr = g_unix_socket_address_new (address); + + if (!g_socket_listener_add_address (G_SOCKET_LISTENER (self), + addr, + G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_DEFAULT, + NULL, + NULL, + error)) + { + g_warning ("Could not listen on unix socket: %s", (*error)->message); + return FALSE; + } + + self->ready_cb = cb; + self->ready_cb_data = user_data; + self->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + + if (self->cancellable) + self->cancellable_id = g_cancellable_connect (self->cancellable, + G_CALLBACK (on_cancelled), self, NULL); + + start_listen (self); + + return TRUE; +} + +gboolean +fp_device_virtual_listener_connection_close (FpDeviceVirtualListener *self) +{ + g_return_val_if_fail (FP_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE); + + if (!self->connection) + return FALSE; + + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); + g_clear_object (&self->connection); + + return TRUE; +} + +static void +on_stream_read_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = user_data; + FpDeviceVirtualListener *self = g_task_get_source_object (task); + gboolean all; + gboolean success; + gsize bytes; + + all = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "all")); + + if (all) + { + success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error); + } + else + { + gssize sbytes; + + sbytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error); + bytes = sbytes; + success = (sbytes >= 0); + } + + if (g_task_return_error_if_cancelled (task)) + return; + + /* If we are cancelled, just return immediately. */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)) + { + g_task_return_int (task, 0); + return; + } + + /* If this error is for an old connection (that should be closed already), + * then just give up immediately with a CLOSED error. + */ + if (self->connection && + g_io_stream_get_input_stream (G_IO_STREAM (self->connection)) != G_INPUT_STREAM (source_object)) + { + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_CLOSED, + "Error on old connection, ignoring."); + return; + } + + if (!success || bytes == 0) + { + /* We accept it if someone tries to read twice and just return that error. */ + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING)) + { + if (self->connection) + { + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); + g_clear_object (&self->connection); + } + } + + if (error) + { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + else + { + // g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Got empty data"); + return; + } + } + + g_task_return_int (task, bytes); +} + +void +fp_device_virtual_listener_read (FpDeviceVirtualListener *self, + gboolean all, + void *buffer, + gsize count, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + GInputStream *stream; + + g_return_if_fail (FP_IS_DEVICE_VIRTUAL_LISTENER (self)); + + task = g_task_new (self, self->cancellable, callback, user_data); + g_object_set_data (G_OBJECT (task), "all", GINT_TO_POINTER (all)); + + if (!self->connection || g_io_stream_is_closed (G_IO_STREAM (self->connection))) + { + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED, + "Listener not connected to any stream"); + return; + } + + stream = g_io_stream_get_input_stream (G_IO_STREAM (self->connection)); + if (all) + { + g_input_stream_read_all_async (stream, buffer, count, + G_PRIORITY_DEFAULT, + self->cancellable, + on_stream_read_cb, + g_steal_pointer (&task)); + } + else + { + g_input_stream_read_async (stream, buffer, count, + G_PRIORITY_DEFAULT, + self->cancellable, + on_stream_read_cb, + g_steal_pointer (&task)); + } +} + +gsize +fp_device_virtual_listener_read_finish (FpDeviceVirtualListener *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, self), 0); + + return g_task_propagate_int (G_TASK (result), error); +} + +gboolean +fp_device_virtual_listener_write_sync (FpDeviceVirtualListener *self, + const char *buffer, + gsize count, + GError **error) +{ + if (!self->connection || g_io_stream_is_closed (G_IO_STREAM (self->connection))) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED, + "Listener not connected to any stream"); + return FALSE; + } + + return g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (self->connection)), + buffer, + count, + NULL, + self->cancellable, + error); +} diff --git a/libfprint/drivers/virtual-device-private.h b/libfprint/drivers/virtual-device-private.h new file mode 100644 index 00000000..5a9a6baa --- /dev/null +++ b/libfprint/drivers/virtual-device-private.h @@ -0,0 +1,109 @@ +/* + * Virtual driver for "simple" device debugging + * + * Copyright (C) 2019 Benjamin Berg + * Copyright (C) 2020 Bastien Nocera + * + * 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 + */ + +/* + * This is a virtual driver to debug the non-image based drivers. A small + * python script is provided to connect to it via a socket, allowing + * prints to registered programmatically. + * Using this, it is possible to test libfprint and fprintd. + */ + +#include + +#include "fpi-device.h" + +#define MAX_LINE_LEN 1024 + +G_DECLARE_FINAL_TYPE (FpDeviceVirtualListener, fp_device_virtual_listener, FP, DEVICE_VIRTUAL_LISTENER, GSocketListener) + +typedef void (*FpDeviceVirtualListenerConnectionCb) (FpDeviceVirtualListener *listener, + gpointer user_data); + +FpDeviceVirtualListener * fp_device_virtual_listener_new (void); + +gboolean fp_device_virtual_listener_start (FpDeviceVirtualListener *listener, + const char *address, + GCancellable *cancellable, + FpDeviceVirtualListenerConnectionCb cb, + gpointer user_data, + GError **error); + +gboolean fp_device_virtual_listener_connection_close (FpDeviceVirtualListener *listener); + +void fp_device_virtual_listener_read (FpDeviceVirtualListener *listener, + gboolean all, + void *buffer, + gsize count, + GAsyncReadyCallback callback, + gpointer user_data); +gsize fp_device_virtual_listener_read_finish (FpDeviceVirtualListener *listener, + GAsyncResult *result, + GError **error); + +gboolean fp_device_virtual_listener_write_sync (FpDeviceVirtualListener *self, + const char *buffer, + gsize count, + GError **error); + + +struct _FpDeviceVirtualDevice +{ + FpDevice parent; + + FpDeviceVirtualListener *listener; + GCancellable *cancellable; + + char recv_buf[MAX_LINE_LEN]; + + GPtrArray *pending_commands; + + GHashTable *prints_storage; + + guint wait_command_id; + guint sleep_timeout_id; + guint enroll_stages_passed; + gboolean match_reported; + gboolean supports_cancellation; + gboolean injected_synthetic_cmd; + gboolean ignore_wait; + gboolean keep_alive; +}; + +/* Not really final here, but we can do this to share the FpDeviceVirtualDevice + * contents without having to use a shared private struct instead. */ +G_DECLARE_FINAL_TYPE (FpDeviceVirtualDevice, fpi_device_virtual_device, FP, DEVICE_VIRTUAL_DEVICE, FpDevice) + +struct _FpDeviceVirtualDeviceStorage +{ + FpDeviceVirtualDevice parent; +}; + +G_DECLARE_FINAL_TYPE (FpDeviceVirtualDeviceStorage, fpi_device_virtual_device_storage, FP, DEVICE_VIRTUAL_DEVICE_STORAGE, FpDeviceVirtualDevice) + + +char * process_cmds (FpDeviceVirtualDevice * self, gboolean scan, GError **error); +char * start_scan_command (FpDeviceVirtualDevice *self, + GError **error); +gboolean should_wait_for_command (FpDeviceVirtualDevice *self, + GError *error); +gboolean should_wait_to_sleep (FpDeviceVirtualDevice *self, + const char *scan_id, + GError *error); diff --git a/libfprint/drivers/virtual-device-storage.c b/libfprint/drivers/virtual-device-storage.c new file mode 100644 index 00000000..34e89718 --- /dev/null +++ b/libfprint/drivers/virtual-device-storage.c @@ -0,0 +1,247 @@ +/* + * Virtual driver for "simple" device debugging with storage + * + * Copyright (C) 2020 Bastien Nocera + * Copyright (C) 2020 Marco Trevisan + * + * 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 + */ + +/* + * This is a virtual driver to debug the non-image based drivers. A small + * python script is provided to connect to it via a socket, allowing + * prints to registered programmatically. + * Using this, it is possible to test libfprint and fprintd. + */ + +#define FP_COMPONENT "virtual_device_storage" + +#include "virtual-device-private.h" +#include "fpi-log.h" + +G_DEFINE_TYPE (FpDeviceVirtualDeviceStorage, fpi_device_virtual_device_storage, fpi_device_virtual_device_get_type ()) + +static GPtrArray * get_stored_prints (FpDeviceVirtualDevice * self); + +static void +dev_identify (FpDevice *dev) +{ + g_autoptr(GError) error = NULL; + FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); + g_autofree char *scan_id = NULL; + + scan_id = start_scan_command (self, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING)) + return; + + if (scan_id) + { + g_autoptr(GPtrArray) stored = get_stored_prints (self); + GPtrArray *prints; + GVariant *data = NULL; + FpPrint *new_scan; + FpPrint *match = NULL; + guint idx; + + new_scan = fp_print_new (dev); + fpi_print_set_type (new_scan, FPI_PRINT_RAW); + fpi_print_set_device_stored (new_scan, TRUE); + data = g_variant_new_string (scan_id); + g_object_set (new_scan, "fpi-data", data, NULL); + + fpi_device_get_identify_data (dev, &prints); + g_debug ("Trying to identify print '%s' against a gallery of %u prints", scan_id, prints->len); + + if (!g_ptr_array_find_with_equal_func (stored, + new_scan, + (GEqualFunc) fp_print_equal, + NULL)) + error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND); + else if (g_ptr_array_find_with_equal_func (prints, + new_scan, + (GEqualFunc) fp_print_equal, + &idx)) + match = g_ptr_array_index (prints, idx); + + if (!self->match_reported) + { + self->match_reported = TRUE; + fpi_device_identify_report (dev, + match, + new_scan, + NULL); + } + } + else if (error && error->domain == FP_DEVICE_RETRY) + { + fpi_device_identify_report (dev, NULL, NULL, g_steal_pointer (&error)); + } + + fpi_device_report_finger_status_changes (FP_DEVICE (self), + FP_FINGER_STATUS_NONE, + FP_FINGER_STATUS_PRESENT); + + if (should_wait_to_sleep (self, scan_id, error)) + return; + + self->match_reported = FALSE; + fpi_device_identify_complete (dev, g_steal_pointer (&error)); +} + +struct ListData +{ + FpDevice *dev; + GPtrArray *res; +}; + +static void +dev_list_insert_print (gpointer key, + gpointer value, + gpointer user_data) +{ + struct ListData *data = user_data; + FpPrint *print = fp_print_new (data->dev); + GVariant *var = NULL; + + fpi_print_fill_from_user_id (print, key); + fpi_print_set_type (print, FPI_PRINT_RAW); + var = g_variant_new_string (key); + g_object_set (print, "fpi-data", var, NULL); + g_object_ref_sink (print); + + g_ptr_array_add (data->res, print); +} + +static GPtrArray * +get_stored_prints (FpDeviceVirtualDevice *self) +{ + GPtrArray * prints_list; + struct ListData data; + + prints_list = g_ptr_array_new_full (g_hash_table_size (self->prints_storage), + g_object_unref); + data.dev = FP_DEVICE (self); + data.res = prints_list; + + g_hash_table_foreach (self->prints_storage, dev_list_insert_print, &data); + + return prints_list; +} + +static void +dev_list (FpDevice *dev) +{ + g_autoptr(GPtrArray) prints_list = NULL; + g_autoptr(GError) error = NULL; + FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev); + + process_cmds (vdev, FALSE, &error); + if (should_wait_for_command (vdev, error)) + return; + + if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + fpi_device_list_complete (dev, NULL, g_steal_pointer (&error)); + return; + } + + fpi_device_list_complete (dev, get_stored_prints (vdev), NULL); +} + +static void +dev_delete (FpDevice *dev) +{ + g_autoptr(GVariant) data = NULL; + g_autoptr(GError) error = NULL; + FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev); + FpPrint *print = NULL; + const char *id = NULL; + + process_cmds (vdev, FALSE, &error); + if (should_wait_for_command (vdev, error)) + return; + + if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + fpi_device_delete_complete (dev, g_steal_pointer (&error)); + return; + } + + fpi_device_get_delete_data (dev, &print); + + g_object_get (print, "fpi-data", &data, NULL); + if (data == NULL) + { + fpi_device_delete_complete (dev, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return; + } + + id = g_variant_get_string (data, NULL); + + fp_dbg ("Deleting print %s for user %s", + id, + fp_print_get_username (print)); + + if (g_hash_table_remove (vdev->prints_storage, id)) + fpi_device_delete_complete (dev, NULL); + else + fpi_device_delete_complete (dev, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND)); +} + +static void +fpi_device_virtual_device_storage_init (FpDeviceVirtualDeviceStorage *self) +{ + FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (self); + + vdev->prints_storage = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + NULL); +} + +static void +fpi_device_virtual_device_storage_finalize (GObject *object) +{ + FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (object); + + G_DEBUG_HERE (); + g_clear_pointer (&vdev->prints_storage, g_hash_table_destroy); + G_OBJECT_CLASS (fpi_device_virtual_device_storage_parent_class)->finalize (object); +} + +static const FpIdEntry driver_ids[] = { + { .virtual_envvar = "FP_VIRTUAL_DEVICE_STORAGE" }, + { .virtual_envvar = "FP_VIRTUAL_DEVICE_IDENT" }, + { .virtual_envvar = NULL } +}; + +static void +fpi_device_virtual_device_storage_class_init (FpDeviceVirtualDeviceStorageClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = fpi_device_virtual_device_storage_finalize; + + dev_class->id = FP_COMPONENT; + dev_class->full_name = "Virtual device with storage and identification for debugging"; + dev_class->id_table = driver_ids; + + dev_class->identify = dev_identify; + dev_class->list = dev_list; + dev_class->delete = dev_delete; +} diff --git a/libfprint/drivers/virtual-device.c b/libfprint/drivers/virtual-device.c new file mode 100644 index 00000000..f39df4ea --- /dev/null +++ b/libfprint/drivers/virtual-device.c @@ -0,0 +1,779 @@ +/* + * Virtual driver for "simple" device debugging + * + * Copyright (C) 2019 Benjamin Berg + * Copyright (C) 2020 Bastien Nocera + * Copyright (C) 2020 Marco Trevisan + * + * 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 + */ + +/* + * This is a virtual driver to debug the non-image based drivers. A small + * python script is provided to connect to it via a socket, allowing + * prints to registered programmatically. + * Using this, it is possible to test libfprint and fprintd. + */ + +#define FP_COMPONENT "virtual_device" + +#include "virtual-device-private.h" +#include "fpi-log.h" + +G_DEFINE_TYPE (FpDeviceVirtualDevice, fpi_device_virtual_device, FP_TYPE_DEVICE) + +#define INSERT_CMD_PREFIX "INSERT " +#define REMOVE_CMD_PREFIX "REMOVE " +#define SCAN_CMD_PREFIX "SCAN " +#define ERROR_CMD_PREFIX "ERROR " +#define RETRY_CMD_PREFIX "RETRY " +#define FINGER_CMD_PREFIX "FINGER " +#define SLEEP_CMD_PREFIX "SLEEP " +#define SET_ENROLL_STAGES_PREFIX "SET_ENROLL_STAGES " +#define SET_SCAN_TYPE_PREFIX "SET_SCAN_TYPE " +#define SET_CANCELLATION_PREFIX "SET_CANCELLATION_ENABLED " +#define SET_KEEP_ALIVE_PREFIX "SET_KEEP_ALIVE " + +#define LIST_CMD "LIST" +#define UNPLUG_CMD "UNPLUG" + +static void +maybe_continue_current_action (FpDeviceVirtualDevice *self) +{ + FpDevice *dev = FP_DEVICE (self); + + if (self->sleep_timeout_id) + return; + + switch (fpi_device_get_current_action (dev)) + { + case FPI_DEVICE_ACTION_ENROLL: + FP_DEVICE_GET_CLASS (self)->enroll (dev); + break; + + case FPI_DEVICE_ACTION_VERIFY: + FP_DEVICE_GET_CLASS (self)->verify (dev); + break; + + case FPI_DEVICE_ACTION_IDENTIFY: + FP_DEVICE_GET_CLASS (self)->identify (dev); + break; + + case FPI_DEVICE_ACTION_LIST: + FP_DEVICE_GET_CLASS (self)->list (dev); + break; + + case FPI_DEVICE_ACTION_DELETE: + FP_DEVICE_GET_CLASS (self)->delete (dev); + break; + + case FPI_DEVICE_ACTION_OPEN: + FP_DEVICE_GET_CLASS (self)->open (dev); + break; + + case FPI_DEVICE_ACTION_CLOSE: + FP_DEVICE_GET_CLASS (self)->close (dev); + break; + + default: + break; + } +} + +static gboolean +sleep_timeout_cb (gpointer data) +{ + FpDeviceVirtualDevice *self = data; + + self->sleep_timeout_id = 0; + + if (g_cancellable_is_cancelled (self->cancellable)) + return FALSE; + + g_debug ("Sleeping completed"); + maybe_continue_current_action (self); + + return FALSE; +} + +char * +process_cmds (FpDeviceVirtualDevice * self, + gboolean scan, + GError **error) +{ + if (g_cancellable_is_cancelled (self->cancellable) || + (fpi_device_get_current_action (FP_DEVICE (self)) != FPI_DEVICE_ACTION_NONE && + g_cancellable_is_cancelled (fpi_device_get_cancellable (FP_DEVICE (self))))) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, + "Operation was cancelled"); + return NULL; + } + + while (self->pending_commands->len > 0) + { + gchar *cmd = g_ptr_array_index (self->pending_commands, 0); + + g_debug ("Processing command %s", cmd); + + /* These are always processed. */ + if (g_str_has_prefix (cmd, INSERT_CMD_PREFIX)) + { + g_assert (self->prints_storage); + g_hash_table_add (self->prints_storage, + g_strdup (cmd + strlen (INSERT_CMD_PREFIX))); + + g_ptr_array_remove_index (self->pending_commands, 0); + continue; + } + else if (g_str_has_prefix (cmd, REMOVE_CMD_PREFIX)) + { + g_assert (self->prints_storage); + if (!g_hash_table_remove (self->prints_storage, + cmd + strlen (REMOVE_CMD_PREFIX))) + g_warning ("ID %s was not found in storage", cmd + strlen (REMOVE_CMD_PREFIX)); + + g_ptr_array_remove_index (self->pending_commands, 0); + continue; + } + else if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX)) + { + guint64 sleep_ms = g_ascii_strtoull (cmd + strlen (SLEEP_CMD_PREFIX), NULL, 10); + + g_debug ("Sleeping %lums", sleep_ms); + self->sleep_timeout_id = g_timeout_add (sleep_ms, sleep_timeout_cb, self); + g_ptr_array_remove_index (self->pending_commands, 0); + + return NULL; + } + else if (g_str_has_prefix (cmd, ERROR_CMD_PREFIX)) + { + g_propagate_error (error, + fpi_device_error_new (g_ascii_strtoull (cmd + strlen (ERROR_CMD_PREFIX), NULL, 10))); + + g_ptr_array_remove_index (self->pending_commands, 0); + return NULL; + } + + /* If we are not scanning, then we have to stop here. */ + if (!scan) + { + g_warning ("Could not process command: %s", cmd); + g_ptr_array_remove_index (self->pending_commands, 0); + break; + } + + if (g_str_has_prefix (cmd, SCAN_CMD_PREFIX)) + { + char *res = g_strdup (cmd + strlen (SCAN_CMD_PREFIX)); + + g_ptr_array_remove_index (self->pending_commands, 0); + return res; + } + else if (g_str_has_prefix (cmd, RETRY_CMD_PREFIX)) + { + g_propagate_error (error, + fpi_device_retry_new (g_ascii_strtoull (cmd + strlen (RETRY_CMD_PREFIX), NULL, 10))); + + g_ptr_array_remove_index (self->pending_commands, 0); + return NULL; + } + else if (g_str_has_prefix (cmd, FINGER_CMD_PREFIX)) + { + gboolean finger_present; + + finger_present = g_ascii_strtoull (cmd + strlen (FINGER_CMD_PREFIX), NULL, 10) != 0; + fpi_device_report_finger_status_changes (FP_DEVICE (self), + finger_present ? FP_FINGER_STATUS_PRESENT : FP_FINGER_STATUS_NONE, + finger_present ? FP_FINGER_STATUS_NONE : FP_FINGER_STATUS_PRESENT); + + g_ptr_array_remove_index (self->pending_commands, 0); + continue; + } + else + { + g_warning ("Could not process command: %s", cmd); + g_ptr_array_remove_index (self->pending_commands, 0); + } + } + + /* No commands left, throw a timeout error. */ + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "No commands left that can be run!"); + return NULL; +} + +static void +write_key_to_listener (void *key, void *val, void *user_data) +{ + FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (user_data); + + if (!fp_device_virtual_listener_write_sync (listener, key, strlen (key), NULL) || + !fp_device_virtual_listener_write_sync (listener, "\n", 1, NULL)) + g_warning ("Error writing reply to LIST command"); +} + +static void +recv_instruction_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GError) error = NULL; + FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (source_object); + gsize bytes; + + bytes = fp_device_virtual_listener_read_finish (listener, res, &error); + fp_dbg ("Got instructions of length %ld", bytes); + + if (error) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + g_warning ("Error receiving instruction data: %s", error->message); + return; + } + + if (bytes > 0) + { + FpDeviceVirtualDevice *self; + g_autofree char *cmd = NULL; + + self = FP_DEVICE_VIRTUAL_DEVICE (user_data); + + cmd = g_strndup (self->recv_buf, bytes); + fp_dbg ("Received command %s", cmd); + + if (g_str_has_prefix (cmd, LIST_CMD)) + { + if (self->prints_storage) + g_hash_table_foreach (self->prints_storage, write_key_to_listener, listener); + } + else if (g_str_has_prefix (cmd, UNPLUG_CMD)) + { + fpi_device_remove (FP_DEVICE (self)); + } + else if (g_str_has_prefix (cmd, SET_ENROLL_STAGES_PREFIX)) + { + guint stages; + + stages = g_ascii_strtoull (cmd + strlen (SET_ENROLL_STAGES_PREFIX), NULL, 10); + fpi_device_set_nr_enroll_stages (FP_DEVICE (self), stages); + } + else if (g_str_has_prefix (cmd, SET_SCAN_TYPE_PREFIX)) + { + const char *scan_type = cmd + strlen (SET_SCAN_TYPE_PREFIX); + g_autoptr(GEnumClass) scan_types = g_type_class_ref (fp_scan_type_get_type ()); + GEnumValue *value = g_enum_get_value_by_nick (scan_types, scan_type); + + if (value) + fpi_device_set_scan_type (FP_DEVICE (self), value->value); + else + g_warning ("Scan type '%s' not found", scan_type); + } + else if (g_str_has_prefix (cmd, SET_CANCELLATION_PREFIX)) + { + self->supports_cancellation = g_ascii_strtoull ( + cmd + strlen (SET_CANCELLATION_PREFIX), NULL, 10) != 0; + + g_debug ("Cancellation support toggled: %d", + self->supports_cancellation); + } + else if (g_str_has_prefix (cmd, SET_KEEP_ALIVE_PREFIX)) + { + self->keep_alive = g_ascii_strtoull ( + cmd + strlen (SET_KEEP_ALIVE_PREFIX), NULL, 10) != 0; + + g_debug ("Keep alive toggled: %d", self->keep_alive); + } + else + { + g_ptr_array_add (self->pending_commands, g_steal_pointer (&cmd)); + g_clear_handle_id (&self->wait_command_id, g_source_remove); + + maybe_continue_current_action (self); + } + } + + fp_device_virtual_listener_connection_close (listener); +} + +static void +recv_instruction (FpDeviceVirtualDevice *self) +{ + fp_device_virtual_listener_read (self->listener, + FALSE, + self->recv_buf, + sizeof (self->recv_buf), + recv_instruction_cb, + self); +} + +static void +on_listener_connected (FpDeviceVirtualListener *listener, + gpointer user_data) +{ + FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (user_data); + + recv_instruction (self); +} + +static void +dev_init (FpDevice *dev) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GCancellable) cancellable = NULL; + g_autoptr(FpDeviceVirtualListener) listener = NULL; + FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); + + G_DEBUG_HERE (); + + process_cmds (self, FALSE, &error); + if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + fpi_device_open_complete (dev, g_steal_pointer (&error)); + return; + } + else if (self->sleep_timeout_id) + { + return; + } + else if (self->listener) + { + fpi_device_open_complete (dev, NULL); + return; + } + + listener = fp_device_virtual_listener_new (); + cancellable = g_cancellable_new (); + + if (!fp_device_virtual_listener_start (listener, + fpi_device_get_virtual_env (FP_DEVICE (self)), + cancellable, + on_listener_connected, + self, + &error)) + { + fpi_device_open_complete (dev, g_steal_pointer (&error)); + return; + } + + self->listener = g_steal_pointer (&listener); + self->cancellable = g_steal_pointer (&cancellable); + + fpi_device_open_complete (dev, NULL); +} + +static gboolean +wait_for_command_timeout (gpointer data) +{ + FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (data); + GError *error = NULL; + + self->wait_command_id = 0; + + switch (fpi_device_get_current_action (FP_DEVICE (self))) + { + case FPI_DEVICE_ACTION_LIST: + case FPI_DEVICE_ACTION_DELETE: + self->ignore_wait = TRUE; + maybe_continue_current_action (self); + self->ignore_wait = FALSE; + return FALSE; + + default: + break; + } + + error = g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "No commands arrived in time to run!"); + fpi_device_action_error (FP_DEVICE (self), error); + + return FALSE; +} + +gboolean +should_wait_for_command (FpDeviceVirtualDevice *self, + GError *error) +{ + if (!error && self->sleep_timeout_id) + return TRUE; + + if (self->ignore_wait) + return FALSE; + + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + return FALSE; + + if (self->wait_command_id) + return FALSE; + + self->wait_command_id = g_timeout_add (500, wait_for_command_timeout, self); + return TRUE; +} + +char * +start_scan_command (FpDeviceVirtualDevice *self, + GError **error) +{ + g_autoptr(GError) local_error = NULL; + g_autofree char *scan_id = NULL; + + if (fp_device_get_finger_status (FP_DEVICE (self)) == FP_FINGER_STATUS_NONE) + self->injected_synthetic_cmd = FALSE; + + scan_id = process_cmds (self, TRUE, &local_error); + + if (!self->sleep_timeout_id) + { + fpi_device_report_finger_status_changes (FP_DEVICE (self), + FP_FINGER_STATUS_NEEDED, + FP_FINGER_STATUS_NONE); + } + + if (should_wait_for_command (self, local_error)) + { + g_assert (!scan_id); + + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING, + "Still waiting for command"); + return NULL; + } + + if (local_error) + g_propagate_error (error, g_steal_pointer (&local_error)); + else + fpi_device_report_finger_status_changes (FP_DEVICE (self), + FP_FINGER_STATUS_PRESENT, + FP_FINGER_STATUS_NONE); + + return g_steal_pointer (&scan_id); +} + +gboolean +should_wait_to_sleep (FpDeviceVirtualDevice *self, + const char *scan_id, + GError *error) +{ + const gchar *cmd; + + if (self->sleep_timeout_id) + return TRUE; + + if (!self->pending_commands->len) + return FALSE; + + cmd = g_ptr_array_index (self->pending_commands, 0); + + if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX)) + { + g_autoptr(GError) local_error = NULL; + g_free (process_cmds (self, FALSE, &local_error)); + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return FALSE; + + g_assert (!self->injected_synthetic_cmd); + g_assert (self->sleep_timeout_id != 0); + + if (!self->pending_commands->len) + { + g_autofree char *injected_cmd = NULL; + + if (scan_id) + injected_cmd = g_strconcat (SCAN_CMD_PREFIX, scan_id, NULL); + else if (error && error->domain == FP_DEVICE_ERROR) + injected_cmd = g_strdup_printf (ERROR_CMD_PREFIX " %d", error->code); + else if (error && error->domain == FP_DEVICE_RETRY) + injected_cmd = g_strdup_printf (RETRY_CMD_PREFIX " %d", error->code); + else + return TRUE; + + g_debug ("Sleeping now, command queued for later: %s", injected_cmd); + + g_ptr_array_insert (self->pending_commands, 0, g_steal_pointer (&injected_cmd)); + self->injected_synthetic_cmd = TRUE; + } + } + + return self->sleep_timeout_id != 0; +} + +static void +dev_verify (FpDevice *dev) +{ + g_autoptr(GError) error = NULL; + FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); + g_autofree char *scan_id = NULL; + + scan_id = start_scan_command (self, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING)) + return; + + if (scan_id) + { + GVariant *data = NULL; + FpPrint *new_scan; + FpPrint *print; + gboolean success; + + g_debug ("Virtual device scanned print %s", scan_id); + fpi_device_get_verify_data (dev, &print); + + new_scan = fp_print_new (dev); + fpi_print_set_type (new_scan, FPI_PRINT_RAW); + if (self->prints_storage) + fpi_print_set_device_stored (new_scan, TRUE); + data = g_variant_new_string (scan_id); + g_object_set (new_scan, "fpi-data", data, NULL); + + if (self->prints_storage && !g_hash_table_contains (self->prints_storage, scan_id)) + { + error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND); + success = FALSE; + } + else + { + success = fp_print_equal (print, new_scan); + } + + if (!self->match_reported) + { + self->match_reported = TRUE; + fpi_device_verify_report (dev, + success ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL, + new_scan, + NULL); + } + } + else if (error) + { + g_debug ("Virtual device scan failed with error: %s", error->message); + } + + fpi_device_report_finger_status_changes (FP_DEVICE (self), + FP_FINGER_STATUS_NONE, + FP_FINGER_STATUS_PRESENT); + + if (error && error->domain == FP_DEVICE_RETRY) + fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, g_steal_pointer (&error)); + + if (should_wait_to_sleep (self, scan_id, error)) + return; + + self->match_reported = FALSE; + fpi_device_verify_complete (dev, g_steal_pointer (&error)); +} + +static void +dev_enroll (FpDevice *dev) +{ + g_autoptr(GError) error = NULL; + FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); + FpPrint *print = NULL; + g_autofree char *id = NULL; + + id = start_scan_command (self, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING)) + return; + + fpi_device_get_enroll_data (dev, &print); + + if (id) + { + GVariant *data; + gboolean completed; + + if (self->prints_storage && g_hash_table_contains (self->prints_storage, id)) + { + if (should_wait_to_sleep (self, id, error)) + return; + + fpi_device_enroll_complete (dev, NULL, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_DUPLICATE)); + return; + } + + if (self->enroll_stages_passed == 0) + { + fpi_print_set_type (print, FPI_PRINT_RAW); + data = g_variant_new_string (id); + g_object_set (print, "fpi-data", data, NULL); + } + else + { + gboolean changed; + + g_object_get (print, "fpi-data", &data, NULL); + changed = !g_str_equal (id, g_variant_get_string (data, NULL)); + g_variant_unref (data); + + if (changed) + { + g_set_error (&error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL, "ID Mismatch"); + fpi_device_enroll_progress (dev, self->enroll_stages_passed, NULL, + g_steal_pointer (&error)); + + if (!should_wait_to_sleep (self, id, error)) + self->sleep_timeout_id = g_idle_add (sleep_timeout_cb, self); + return; + } + } + + self->enroll_stages_passed++; + completed = self->enroll_stages_passed == fp_device_get_nr_enroll_stages (FP_DEVICE (self)); + fpi_device_report_finger_status_changes (FP_DEVICE (self), + completed ? + FP_FINGER_STATUS_NEEDED : + FP_FINGER_STATUS_NONE, + FP_FINGER_STATUS_PRESENT); + + fpi_device_enroll_progress (dev, self->enroll_stages_passed, print, NULL); + + if (completed) + { + if (self->prints_storage) + { + fpi_print_set_device_stored (print, TRUE); + g_hash_table_add (self->prints_storage, g_strdup (id)); + } + + fpi_device_enroll_complete (dev, g_object_ref (print), NULL); + self->enroll_stages_passed = 0; + } + else if (!should_wait_to_sleep (self, id, error)) + { + self->sleep_timeout_id = g_idle_add (sleep_timeout_cb, self); + } + } + else + { + fpi_device_report_finger_status_changes (FP_DEVICE (self), + FP_FINGER_STATUS_NONE, + FP_FINGER_STATUS_PRESENT); + + if (error && error->domain == FP_DEVICE_RETRY) + { + fpi_device_enroll_progress (dev, self->enroll_stages_passed, NULL, g_steal_pointer (&error)); + + if (!should_wait_to_sleep (self, id, error)) + self->sleep_timeout_id = g_idle_add (sleep_timeout_cb, self); + } + else + { + if (should_wait_to_sleep (self, id, error)) + return; + + self->enroll_stages_passed = 0; + fpi_device_enroll_complete (dev, NULL, g_steal_pointer (&error)); + } + } +} + +static void +dev_cancel (FpDevice *dev) +{ + FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); + + if (self->injected_synthetic_cmd) + { + self->injected_synthetic_cmd = FALSE; + g_ptr_array_remove_index (self->pending_commands, 0); + } + + if (!self->supports_cancellation) + return; + + g_debug ("Got cancellation!"); + g_clear_handle_id (&self->sleep_timeout_id, g_source_remove); + + maybe_continue_current_action (self); +} + +static void +stop_listener (FpDeviceVirtualDevice *self) +{ + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->cancellable); + g_clear_object (&self->listener); +} + +static void +dev_deinit (FpDevice *dev) +{ + g_autoptr(GError) error = NULL; + FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); + + process_cmds (self, FALSE, &error); + if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + fpi_device_close_complete (dev, g_steal_pointer (&error)); + return; + } + else if (self->sleep_timeout_id) + { + return; + } + + g_clear_handle_id (&self->wait_command_id, g_source_remove); + g_clear_handle_id (&self->sleep_timeout_id, g_source_remove); + + if (!self->keep_alive) + stop_listener (self); + + fpi_device_close_complete (dev, NULL); +} + +static void +fpi_device_virtual_device_finalize (GObject *object) +{ + FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (object); + + G_DEBUG_HERE (); + stop_listener (self); + g_clear_pointer (&self->pending_commands, g_ptr_array_unref); + G_OBJECT_CLASS (fpi_device_virtual_device_parent_class)->finalize (object); +} + +static void +fpi_device_virtual_device_init (FpDeviceVirtualDevice *self) +{ + self->supports_cancellation = TRUE; + self->pending_commands = g_ptr_array_new_with_free_func (g_free); +} + +static const FpIdEntry driver_ids[] = { + { .virtual_envvar = "FP_VIRTUAL_DEVICE", }, + { .virtual_envvar = NULL } +}; + +static void +fpi_device_virtual_device_class_init (FpDeviceVirtualDeviceClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = fpi_device_virtual_device_finalize; + + dev_class->id = FP_COMPONENT; + dev_class->full_name = "Virtual device for debugging"; + dev_class->type = FP_DEVICE_TYPE_VIRTUAL; + dev_class->id_table = driver_ids; + dev_class->nr_enroll_stages = 5; + + dev_class->open = dev_init; + dev_class->close = dev_deinit; + dev_class->verify = dev_verify; + dev_class->enroll = dev_enroll; + dev_class->cancel = dev_cancel; +} diff --git a/libfprint/drivers/virtual-image.c b/libfprint/drivers/virtual-image.c index b92a3327..222f022e 100644 --- a/libfprint/drivers/virtual-image.c +++ b/libfprint/drivers/virtual-image.c @@ -29,36 +29,27 @@ #include "fpi-log.h" +#include "virtual-device-private.h" + #include "../fpi-image.h" #include "../fpi-image-device.h" -#include -#include -#include - struct _FpDeviceVirtualImage { - FpImageDevice parent; + FpImageDevice parent; - GSocketListener *listener; - GSocketConnection *connection; - GCancellable *listen_cancellable; - GCancellable *cancellable; + FpDeviceVirtualListener *listener; + GCancellable *cancellable; - gint socket_fd; - gint client_fd; - - gboolean automatic_finger; - FpImage *recv_img; - gint recv_img_hdr[2]; + gboolean automatic_finger; + FpImage *recv_img; + gint recv_img_hdr[2]; }; G_DECLARE_FINAL_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FPI, DEVICE_VIRTUAL_IMAGE, FpImageDevice) G_DEFINE_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FP_TYPE_IMAGE_DEVICE) -static void start_listen (FpDeviceVirtualImage *dev); -static void recv_image (FpDeviceVirtualImage *dev, - GInputStream *stream); +static void recv_image (FpDeviceVirtualImage *self); static void recv_image_img_recv_cb (GObject *source_object, @@ -66,35 +57,20 @@ recv_image_img_recv_cb (GObject *source_object, gpointer user_data) { g_autoptr(GError) error = NULL; + FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (source_object); FpDeviceVirtualImage *self; FpImageDevice *device; - gboolean success; - gsize bytes = 0; + gsize bytes; - success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error); + bytes = fp_device_virtual_listener_read_finish (listener, res, &error); - /* Can't use self if the operation was cancelled. */ - if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + if (!bytes || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) || + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED)) return; self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); device = FP_IMAGE_DEVICE (self); - /* Consider success if we received the right amount of data, otherwise - * an error must have happened. */ - if (bytes < self->recv_img->width * self->recv_img->height) - { - if (!success) - g_warning ("Error receiving image data: %s", error->message); - else - g_warning ("Error receiving image data: end of stream before all data was read"); - - self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); - g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); - g_clear_object (&self->connection); - return; - } - if (self->automatic_finger) fpi_image_device_report_finger_status (device, TRUE); fpi_image_device_image_captured (device, g_steal_pointer (&self->recv_img)); @@ -102,7 +78,7 @@ recv_image_img_recv_cb (GObject *source_object, fpi_image_device_report_finger_status (device, FALSE); /* And, listen for more images from the same client. */ - recv_image (self, G_INPUT_STREAM (source_object)); + recv_image (self); } static void @@ -112,37 +88,30 @@ recv_image_hdr_recv_cb (GObject *source_object, { g_autoptr(GError) error = NULL; FpDeviceVirtualImage *self; - gboolean success; + FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (source_object); gsize bytes; - success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error); + bytes = fp_device_virtual_listener_read_finish (listener, res, &error); - if (!success || bytes != sizeof (self->recv_img_hdr)) + if (error) { - if (!success) - { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) || - g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)) - return; - g_warning ("Error receiving header for image data: %s", error->message); - } - else if (bytes != 0) - { - g_warning ("Received incomplete header before end of stream."); - } + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) || + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED) || + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING)) + return; - self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); - g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); - g_clear_object (&self->connection); + g_warning ("Error receiving header for image data: %s", error->message); return; } + if (!bytes) + return; + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000) { g_warning ("Image header suggests an unrealistically large image, disconnecting client."); - g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); - g_clear_object (&self->connection); + fp_device_virtual_listener_connection_close (listener); } if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0) @@ -178,161 +147,87 @@ recv_image_hdr_recv_cb (GObject *source_object, default: /* disconnect client, it didn't play fair */ - g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); - g_clear_object (&self->connection); + fp_device_virtual_listener_connection_close (listener); } /* And, listen for more images from the same client. */ - recv_image (self, G_INPUT_STREAM (source_object)); + recv_image (self); return; } self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]); g_debug ("image data: %p", self->recv_img->data); - g_input_stream_read_all_async (G_INPUT_STREAM (source_object), - (guint8 *) self->recv_img->data, - self->recv_img->width * self->recv_img->height, - G_PRIORITY_DEFAULT, - self->cancellable, - recv_image_img_recv_cb, - self); + fp_device_virtual_listener_read (listener, + TRUE, + (guint8 *) self->recv_img->data, + self->recv_img->width * self->recv_img->height, + recv_image_img_recv_cb, + self); } static void -recv_image (FpDeviceVirtualImage *self, GInputStream *stream) +recv_image (FpDeviceVirtualImage *self) { + fp_device_virtual_listener_read (self->listener, + TRUE, + self->recv_img_hdr, + sizeof (self->recv_img_hdr), + recv_image_hdr_recv_cb, + self); +} + +static void +on_listener_connected (FpDeviceVirtualListener *listener, + gpointer user_data) +{ + FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); FpiImageDeviceState state; - g_object_get (self, "fpi-image-device-state", &state, NULL); + self->automatic_finger = TRUE; - g_debug ("Starting image receive (if active), state is: %i", state); + g_object_get (self, + "fpi-image-device-state", &state, + NULL); - /* Only register if the state is active. */ switch (state) { case FPI_IMAGE_DEVICE_STATE_IDLE: case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: case FPI_IMAGE_DEVICE_STATE_CAPTURE: case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: - g_input_stream_read_all_async (stream, - self->recv_img_hdr, - sizeof (self->recv_img_hdr), - G_PRIORITY_DEFAULT, - self->cancellable, - recv_image_hdr_recv_cb, - self); - /* fallthrough */ + recv_image (self); default: break; } } -static void -new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - g_autoptr(GError) error = NULL; - GSocketConnection *connection; - GInputStream *stream; - FpDeviceVirtualImage *dev = user_data; - - connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object), - res, - NULL, - &error); - if (!connection) - { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - g_warning ("Error accepting a new connection: %s", error->message); - start_listen (dev); - } - - /* Always accept further connections (but we disconnect them immediately - * if we already have a connection). */ - start_listen (dev); - - if (dev->connection) - { - /* We may not have noticed that the stream was closed, - * if the device is deactivated. - * Cancel any ongoing operation on the old connection. */ - g_cancellable_cancel (dev->cancellable); - g_clear_object (&dev->cancellable); - dev->cancellable = g_cancellable_new (); - - g_clear_object (&dev->connection); - } - - if (dev->connection) - { - g_warning ("Rejecting new connection"); - g_io_stream_close (G_IO_STREAM (connection), NULL, NULL); - g_object_unref (connection); - return; - } - - dev->connection = connection; - dev->automatic_finger = TRUE; - stream = g_io_stream_get_input_stream (G_IO_STREAM (connection)); - - fp_dbg ("Got a new connection!"); - recv_image (dev, stream); -} - -static void -start_listen (FpDeviceVirtualImage *dev) -{ - g_socket_listener_accept_async (dev->listener, - dev->listen_cancellable, - new_connection_cb, - dev); -} - static void dev_init (FpImageDevice *dev) { g_autoptr(GError) error = NULL; - g_autoptr(GSocketListener) listener = NULL; + g_autoptr(FpDeviceVirtualListener) listener = NULL; + g_autoptr(GCancellable) cancellable = NULL; FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); - const char *env; - g_autoptr(GSocketAddress) addr = NULL; G_DEBUG_HERE (); - self->client_fd = -1; + listener = fp_device_virtual_listener_new (); + cancellable = g_cancellable_new (); - env = fpi_device_get_virtual_env (FP_DEVICE (self)); - - listener = g_socket_listener_new (); - g_socket_listener_set_backlog (listener, 1); - - /* Remove any left over socket. */ - g_unlink (env); - - addr = g_unix_socket_address_new (env); - - if (!g_socket_listener_add_address (listener, - addr, - G_SOCKET_TYPE_STREAM, - G_SOCKET_PROTOCOL_DEFAULT, - NULL, - NULL, - &error)) + if (!fp_device_virtual_listener_start (listener, + fpi_device_get_virtual_env (FP_DEVICE (self)), + cancellable, + on_listener_connected, + self, + &error)) { - g_warning ("Could not listen on unix socket: %s", error->message); - - fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), g_steal_pointer (&error)); - + fpi_image_device_open_complete (dev, g_steal_pointer (&error)); return; } self->listener = g_steal_pointer (&listener); - self->cancellable = g_cancellable_new (); - self->listen_cancellable = g_cancellable_new (); - - start_listen (self); + self->cancellable = g_steal_pointer (&cancellable); /* Delay result to open up the possibility of testing race conditions. */ fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_open_complete, NULL, NULL); @@ -346,11 +241,8 @@ dev_deinit (FpImageDevice *dev) G_DEBUG_HERE (); g_cancellable_cancel (self->cancellable); - g_cancellable_cancel (self->listen_cancellable); g_clear_object (&self->cancellable); - g_clear_object (&self->listen_cancellable); g_clear_object (&self->listener); - g_clear_object (&self->connection); /* Delay result to open up the possibility of testing race conditions. */ fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_close_complete, NULL, NULL); @@ -361,23 +253,16 @@ dev_activate (FpImageDevice *dev) { FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); - fpi_image_device_activate_complete (dev, NULL); + /* Start reading (again). */ + recv_image (self); - if (self->connection) - recv_image (self, g_io_stream_get_input_stream (G_IO_STREAM (self->connection))); + fpi_image_device_activate_complete (dev, NULL); } static void dev_deactivate (FpImageDevice *dev) { - FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); - - g_cancellable_cancel (self->cancellable); - g_clear_object (&self->cancellable); - self->cancellable = g_cancellable_new (); - - /* XXX: Need to wait for the operation to be cancelled. */ - fpi_device_add_timeout (FP_DEVICE (dev), 10, (FpTimeoutFunc) fpi_image_device_deactivate_complete, NULL, NULL); + fpi_image_device_deactivate_complete (dev, NULL); } static void diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index f752a487..fedaa335 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -185,7 +185,7 @@ fp_device_get_property (GObject *object, switch (prop_id) { case PROP_NR_ENROLL_STAGES: - g_value_set_int (value, priv->nr_enroll_stages); + g_value_set_uint (value, priv->nr_enroll_stages); break; case PROP_SCAN_TYPE: @@ -197,7 +197,7 @@ fp_device_get_property (GObject *object, break; case PROP_DRIVER: - g_value_set_static_string (value, FP_DEVICE_GET_CLASS (priv)->id); + g_value_set_static_string (value, FP_DEVICE_GET_CLASS (self)->id); break; case PROP_DEVICE_ID: @@ -979,7 +979,7 @@ fp_device_verify_finish (FpDevice *device, data = g_task_get_task_data (G_TASK (result)); - *print = data->print; + *print = data ? data->print : NULL; if (*print) g_object_ref (*print); } @@ -1092,13 +1092,13 @@ fp_device_identify_finish (FpDevice *device, if (print) { - *print = data->print; + *print = data ? data->print : NULL; if (*print) g_object_ref (*print); } if (match) { - *match = data->match; + *match = data ? data->match : NULL; if (*match) g_object_ref (*match); } diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index de511920..231dde95 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -216,6 +216,7 @@ fpi_device_set_nr_enroll_stages (FpDevice *device, FpDevicePrivate *priv = fp_device_get_instance_private (device); g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (enroll_stages > 0); priv->nr_enroll_stages = enroll_stages; g_object_notify (G_OBJECT (device), "nr-enroll-stages"); @@ -751,6 +752,21 @@ fp_device_task_return_in_idle_cb (gpointer user_data) priv->current_action = FPI_DEVICE_ACTION_NONE; priv->current_task_idle_return_source = NULL; + if (action == FPI_DEVICE_ACTION_OPEN && + data->type != FP_DEVICE_TASK_RETURN_ERROR) + { + priv->is_open = TRUE; + g_object_notify (G_OBJECT (data->device), "open"); + } + else if (action == FPI_DEVICE_ACTION_CLOSE) + { + /* Always consider the device closed. Drivers should try hard to close the + * device. Generally, e.g. cancellations should be ignored. + */ + priv->is_open = FALSE; + g_object_notify (G_OBJECT (data->device), "open"); + } + /* Return FP_DEVICE_ERROR_REMOVED if the device is removed, * with the exception of a successful open, which is an odd corner case. */ if (priv->is_removed && @@ -920,12 +936,6 @@ fpi_device_open_complete (FpDevice *device, GError *error) clear_device_cancel_action (device); fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE); - if (!error) - { - priv->is_open = TRUE; - g_object_notify (G_OBJECT (device), "open"); - } - if (!error) fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, GUINT_TO_POINTER (TRUE)); @@ -976,12 +986,6 @@ fpi_device_close_complete (FpDevice *device, GError *error) return; } - /* Always consider the device closed. Drivers should try hard to close the - * device. Generally, e.g. cancellations should be ignored. - */ - priv->is_open = FALSE; - g_object_notify (G_OBJECT (device), "open"); - if (!error) fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, GUINT_TO_POINTER (TRUE)); @@ -1529,7 +1533,7 @@ fpi_device_report_finger_status (FpDevice *device, * fpi_device_report_finger_status_changes: * @device: The #FpDevice * @added_status: The #FpFingerStatusFlags to add - * @added_status: The #FpFingerStatusFlags to remove + * @removed_status: The #FpFingerStatusFlags to remove * * Report the finger status for the @device adding the @added_status flags * and removing the @removed_status flags. diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c index 25728d18..6264d407 100644 --- a/libfprint/fpi-ssm.c +++ b/libfprint/fpi-ssm.c @@ -130,6 +130,7 @@ fpi_ssm_new_full (FpDevice *dev, { FpiSsm *machine; + BUG_ON (dev == NULL); BUG_ON (nr_states < 1); BUG_ON (handler == NULL); @@ -155,6 +156,8 @@ fpi_ssm_set_data (FpiSsm *machine, gpointer ssm_data, GDestroyNotify ssm_data_destroy) { + g_return_if_fail (machine); + if (machine->ssm_data_destroy && machine->ssm_data) machine->ssm_data_destroy (machine->ssm_data); @@ -173,12 +176,16 @@ fpi_ssm_set_data (FpiSsm *machine, void * fpi_ssm_get_data (FpiSsm *machine) { + g_return_val_if_fail (machine, NULL); + return machine->ssm_data; } static void fpi_ssm_clear_delayed_action (FpiSsm *machine) { + g_return_if_fail (machine); + if (machine->cancellable_id) { g_cancellable_disconnect (machine->cancellable, machine->cancellable_id); @@ -235,6 +242,8 @@ fpi_ssm_set_delayed_action_timeout (FpiSsm *machine, gpointer user_data, GDestroyNotify destroy_func) { + g_return_if_fail (machine); + BUG_ON (machine->completed); BUG_ON (machine->timeout != NULL); @@ -302,6 +311,8 @@ __ssm_call_handler (FpiSsm *machine) void fpi_ssm_start (FpiSsm *ssm, FpiSsmCompletedCallback callback) { + g_return_if_fail (ssm != NULL); + BUG_ON (!ssm->completed); ssm->callback = callback; ssm->cur_state = 0; @@ -336,6 +347,9 @@ __subsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) void fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child) { + g_return_if_fail (parent != NULL); + g_return_if_fail (child != NULL); + BUG_ON (parent->timeout); child->parentsm = parent; @@ -355,6 +369,8 @@ fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child) void fpi_ssm_mark_completed (FpiSsm *machine) { + g_return_if_fail (machine != NULL); + BUG_ON (machine->completed); BUG_ON (machine->timeout != NULL); @@ -427,6 +443,7 @@ fpi_ssm_mark_completed_delayed (FpiSsm *machine, void fpi_ssm_mark_failed (FpiSsm *machine, GError *error) { + g_return_if_fail (machine != NULL); g_assert (error); if (machine->error) { @@ -534,6 +551,8 @@ fpi_ssm_next_state_delayed (FpiSsm *machine, void fpi_ssm_jump_to_state (FpiSsm *machine, int state) { + g_return_if_fail (machine != NULL); + BUG_ON (machine->completed); BUG_ON (state < 0 || state >= machine->nr_states); BUG_ON (machine->timeout != NULL); @@ -610,6 +629,8 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine, int fpi_ssm_get_cur_state (FpiSsm *machine) { + g_return_val_if_fail (machine != NULL, 0); + return machine->cur_state; } @@ -624,6 +645,8 @@ fpi_ssm_get_cur_state (FpiSsm *machine) GError * fpi_ssm_get_error (FpiSsm *machine) { + g_return_val_if_fail (machine != NULL, NULL); + return machine->error; } @@ -638,6 +661,8 @@ fpi_ssm_get_error (FpiSsm *machine) GError * fpi_ssm_dup_error (FpiSsm *machine) { + g_return_val_if_fail (machine != NULL, NULL); + if (machine->error) return g_error_copy (machine->error); diff --git a/libfprint/fpi-usb-transfer.c b/libfprint/fpi-usb-transfer.c index fe491685..784aa59d 100644 --- a/libfprint/fpi-usb-transfer.c +++ b/libfprint/fpi-usb-transfer.c @@ -187,7 +187,7 @@ fpi_usb_transfer_fill_bulk (FpiUsbTransfer *transfer, * fpi_usb_transfer_fill_bulk_full: * @transfer: The #FpiUsbTransfer * @endpoint: The endpoint to send the transfer to - * @buffer: The data to send. A buffer will be created and managed for you if you pass NULL. + * @buffer: The data to send. * @length: The size of @buffer * @free_func: (destroy buffer): Destroy notify for @buffer * @@ -275,7 +275,7 @@ fpi_usb_transfer_fill_interrupt (FpiUsbTransfer *transfer, * fpi_usb_transfer_fill_interrupt_full: * @transfer: The #FpiUsbTransfer * @endpoint: The endpoint to send the transfer to - * @buffer: The data to send. A buffer will be created and managed for you if you pass NULL. + * @buffer: The data to send. * @length: The size of @buffer * @free_func: (destroy buffer): Destroy notify for @buffer * diff --git a/libfprint/fprint-list-udev-rules.c b/libfprint/fprint-list-udev-hwdb.c similarity index 83% rename from libfprint/fprint-list-udev-rules.c rename to libfprint/fprint-list-udev-hwdb.c index d6c884cb..2a78e81f 100644 --- a/libfprint/fprint-list-udev-rules.c +++ b/libfprint/fprint-list-udev-hwdb.c @@ -45,12 +45,9 @@ static const FpIdEntry whitelist_id_table[] = { { .vid = 0x06cb, .pid = 0x00b7 }, { .vid = 0x06cb, .pid = 0x00bb }, { .vid = 0x06cb, .pid = 0x00be }, - { .vid = 0x06cb, .pid = 0x00c2 }, - { .vid = 0x06cb, .pid = 0x00c9 }, { .vid = 0x06cb, .pid = 0x00cb }, { .vid = 0x06cb, .pid = 0x00d8 }, { .vid = 0x06cb, .pid = 0x00da }, - { .vid = 0x06cb, .pid = 0x00e7 }, { .vid = 0x0a5c, .pid = 0x5801 }, { .vid = 0x0a5c, .pid = 0x5805 }, { .vid = 0x0a5c, .pid = 0x5834 }, @@ -110,6 +107,7 @@ static const FpIdEntry blacklist_id_table[] = { static const FpDeviceClass whitelist = { .type = FP_DEVICE_TYPE_USB, .id_table = whitelist_id_table, + .id = "whitelist", .full_name = "Hardcoded whitelist" }; @@ -140,33 +138,56 @@ print_driver (const FpDeviceClass *cls) if (g_hash_table_lookup (printed, key) != NULL) { + if (cls == &whitelist) + g_warning ("%s implemented by driver %s", + key, (const char *) g_hash_table_lookup (printed, key)); g_free (key); continue; } - g_hash_table_insert (printed, key, GINT_TO_POINTER (1)); + g_hash_table_insert (printed, key, (void *) cls->id); if (num_printed == 0) - g_print ("# %s\n", cls->full_name); + { + if (cls != &whitelist) + g_print ("\n# Supported by libfprint driver %s\n", cls->id); + else + g_print ("\n# Known unsupported devices\n"); + } - g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n", + g_print ("usb:v%04Xp%04X*\n", entry->vid, entry->pid); - g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n", - entry->vid, entry->pid, cls->full_name); num_printed++; } if (num_printed > 0) - g_print ("\n"); + g_print (" ID_AUTOSUSPEND=1\n"); +} + +static int +driver_compare (gconstpointer p1, gconstpointer p2) +{ + g_autoptr(FpDeviceClass) cls1 = g_type_class_ref (*(GType *) p1); + g_autoptr(FpDeviceClass) cls2 = g_type_class_ref (*(GType *) p2); + + return g_strcmp0 (cls1->id, cls2->id); } int main (int argc, char **argv) { g_autoptr(GArray) drivers = fpi_get_driver_types (); + g_autofree char *program_name = NULL; guint i; + program_name = g_path_get_basename (argv[0]); + + g_print ("# SPDX-License-Identifier: LGPL-2.1-or-later\n"); + g_print ("# This file has been generated using %s with all drivers enabled\n", + program_name); + printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_array_sort (drivers, driver_compare); for (i = 0; i < drivers->len; i++) { diff --git a/libfprint/meson.build b/libfprint/meson.build index 030e1e6b..5cada6c0 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -155,6 +155,15 @@ foreach driver: drivers if driver == 'virtual_image' drivers_sources += [ 'drivers/virtual-image.c' ] endif + if driver == 'virtual_device' + drivers_sources += [ 'drivers/virtual-device.c' ] + endif + if driver == 'virtual_device_storage' + drivers_sources += [ 'drivers/virtual-device-storage.c' ] + endif + if driver.startswith('virtual_') + drivers_sources += [ 'drivers/virtual-device-listener.c' ] + endif if driver == 'synaptics' drivers_sources += [ 'drivers/synaptics/synaptics.c', @@ -262,7 +271,7 @@ libfprint_drivers = static_library('fprint-drivers', mapfile = files('libfprint.ver') vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0]) -libfprint = library(versioned_libname.split('lib')[1], +libfprint = shared_library(versioned_libname.split('lib')[1], sources: [ fp_enums, libfprint_sources, @@ -299,20 +308,30 @@ libfprint_private_dep = declare_dependency( ] ) -udev_rules = executable('fprint-list-udev-rules', - 'fprint-list-udev-rules.c', +udev_hwdb = executable('fprint-list-udev-hwdb', + 'fprint-list-udev-hwdb.c', dependencies: libfprint_private_dep, link_with: libfprint_drivers, install: false) -if get_option('udev_rules') - custom_target('udev-rules', - output: '60-@0@-autosuspend.rules'.format(versioned_libname), - capture: true, - command: [ udev_rules ], - install: true, - install_dir: udev_rules_dir) -endif +udev_hwdb_generator = custom_target('udev-hwdb', + output: 'autosuspend.hwdb', + depend_files: drivers_sources, + capture: true, + command: [ udev_hwdb ], + install: false, +) + +custom_target('sync-udev-hwdb', + depends: udev_hwdb_generator, + output: 'sync-udev-hwdb', + install: false, + command: [ + 'cp', '-v', + udev_hwdb_generator.full_path(), + meson.source_root() / 'data' + ] +) supported_devices = executable('fprint-list-supported-devices', 'fprint-list-supported-devices.c', diff --git a/meson.build b/meson.build index 6d379e1a..b93c316f 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('libfprint', [ 'c', 'cpp' ], - version: '1.90.7', + version: '1.90.7+git20210222+tod1', license: 'LGPLv2.1+', default_options: [ 'buildtype=debugoptimized', @@ -88,7 +88,12 @@ cairo_dep = dependency('cairo', required: false) # Drivers drivers = get_option('drivers').split(',') -virtual_drivers = [ 'virtual_image' ] +virtual_drivers = [ + 'virtual_image', + 'virtual_device', + 'virtual_device_storage', +] + default_drivers = [ 'upektc_img', 'vfs5011', @@ -113,6 +118,13 @@ default_drivers = [ 'goodixmoc', ] +# FIXME: All the drivers should be fixed by adjusting the byte order. +# See https://gitlab.freedesktop.org/libfprint/libfprint/-/issues/236 +endian_independent_drivers = virtual_drivers + [ + 'aes3500', + 'synaptics', +] + all_drivers = default_drivers + virtual_drivers if drivers == [ 'all' ] @@ -127,6 +139,18 @@ if drivers.length() == 0 or drivers[0] == '' error('Cannot build libfprint without drivers, please specify a valid value for the drivers option') endif +if drivers == all_drivers or drivers == default_drivers + default_drivers_are_enabled = true +else + default_drivers_are_enabled = true + foreach driver: default_drivers + if driver not in drivers + default_drivers_are_enabled = false + break + endif + endforeach +endif + nss_dep = dependency('', required: false) imaging_dep = dependency('', required: false) libfprint_conf.set10('HAVE_PIXMAN', false) @@ -150,6 +174,20 @@ foreach driver: drivers endif endforeach +supported_drivers = [] +foreach driver: drivers + if build_machine.endian() == 'little' or driver in endian_independent_drivers + supported_drivers += driver + else + warning('Driver @0@ is not supported by big endian cpu @1@. Please, fix it!'.format( + driver, build_machine.cpu())) + endif +endforeach + +if default_drivers_are_enabled and supported_drivers != drivers + default_drivers_are_enabled = false +endif + # Export the drivers' types to the core code drivers_type_list = [] drivers_type_func = [] @@ -162,7 +200,7 @@ drivers_type_func += '{' drivers_type_func += ' GArray *drivers = g_array_new (TRUE, FALSE, sizeof (GType));' drivers_type_func += ' GType t;' drivers_type_func += '' -foreach driver: drivers +foreach driver: supported_drivers drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);' drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();' drivers_type_func += ' g_array_append_val (drivers, t);' @@ -175,12 +213,14 @@ drivers_type_func += '}' root_inc = include_directories('.') if get_option('udev_rules') - udev_rules_dir = get_option('udev_rules_dir') + udev_hwdb_dir = get_option('udev_hwdb_dir') - if udev_rules_dir == 'auto' + if udev_hwdb_dir == 'auto' udev_dep = dependency('udev') - udev_rules_dir = udev_dep.get_pkgconfig_variable('udevdir') + '/rules.d' + udev_hwdb_dir = udev_dep.get_pkgconfig_variable('udevdir') + '/hwdb.d' endif +else + udev_hwdb_dir = false endif if get_option('gtk-examples') @@ -206,6 +246,7 @@ if get_option('gtk-examples') subdir('demo') endif +subdir('data') subdir('tests') pkgconfig = import('pkgconfig') diff --git a/meson_options.txt b/meson_options.txt index d059ae59..be2adbca 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -10,8 +10,8 @@ option('udev_rules', description: 'Whether to create a udev rules file', type: 'boolean', value: true) -option('udev_rules_dir', - description: 'Installation path for udev rules', +option('udev_hwdb_dir', + description: 'Installation path for udev hwdb', type: 'string', value: 'auto') option('gtk-examples', diff --git a/tests/aes3500/device b/tests/aes3500/device index 4a2a9037..c662cc8f 100644 --- a/tests/aes3500/device +++ b/tests/aes3500/device @@ -35,11 +35,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0000 A: bmAttributes=80 -A: busnum=3 +A: busnum=3\n A: configuration= H: descriptors=12011001FFFFFF08FF0831570000000100010902200001010080320904000002FFFFFF000705810240000007050202080000 A: dev=189:259 -A: devnum=4 +A: devnum=4\n A: devpath=1.1.3 L: driver=../../../../../../../../../../bus/usb/drivers/usb A: idProduct=5731 @@ -106,11 +106,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=9100 A: bmAttributes=e0 -A: busnum=3 +A: busnum=3\n A: configuration= H: descriptors=12011002090001403022060000910102000109021900010100E0000904000001090000000705810301000C A: dev=189:258 -A: devnum=3 +A: devnum=3\n A: devpath=1.1 L: driver=../../../../../../../../../bus/usb/drivers/usb A: idProduct=0006 @@ -186,11 +186,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=9100 A: bmAttributes=e0 -A: busnum=3 +A: busnum=3\n A: configuration= H: descriptors=12011002090001403022060000910102000109021900010100E0000904000001090000000705810301000C A: dev=189:257 -A: devnum=2 +A: devnum=2\n A: devpath=1 L: driver=../../../../../../../../bus/usb/drivers/usb A: idProduct=0006 @@ -270,11 +270,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0415 A: bmAttributes=e0 -A: busnum=3 +A: busnum=3\n A: configuration= H: descriptors=12010002090001406B1D020015040302010109021900010100E0000904000001090000000705810304000C A: dev=189:256 -A: devnum=1 +A: devnum=1\n A: devpath=0 L: driver=../../../../../../../bus/usb/drivers/usb A: idProduct=0002 diff --git a/tests/elan/device b/tests/elan/device index 7374dc24..6e1e421e 100644 --- a/tests/elan/device +++ b/tests/elan/device @@ -36,11 +36,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0140 A: bmAttributes=80 -A: busnum=1 +A: busnum=1\n A: configuration= H: descriptors=1201000200000008F304260C40010102000109023E0001010080320904000005FF0000000921100100012215000705810240000107050102400001070582024000010705830240000107050302400001 A: dev=189:93 -A: devnum=94 +A: devnum=94\n A: devpath=4.4 L: driver=../../../../../../bus/usb/drivers/usb A: idProduct=0c26 @@ -107,11 +107,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=5284 A: bmAttributes=e0 -A: busnum=1 +A: busnum=1\n A: configuration= H: descriptors=1201100209000140EF17181084520102000109021900010100E0000904000001090000000705810301000C A: dev=189:82 -A: devnum=83 +A: devnum=83\n A: devpath=4 L: driver=../../../../../bus/usb/drivers/usb A: idProduct=1018 @@ -189,11 +189,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0503 A: bmAttributes=e0 -A: busnum=1 +A: busnum=1\n A: configuration= H: descriptors=12010002090001406B1D020003050302010109021900010100E0000904000001090000000705810304000C A: dev=189:0 -A: devnum=1 +A: devnum=1\n A: devpath=0 L: driver=../../../../bus/usb/drivers/usb A: idProduct=0002 diff --git a/tests/goodixmoc/custom.ioctl b/tests/goodixmoc/custom.ioctl index 21c85316..496b43c4 100644 --- a/tests/goodixmoc/custom.ioctl +++ b/tests/goodixmoc/custom.ioctl @@ -1,307 +1,217 @@ -@DEV /dev/bus/usb/001/003 +@DEV /dev/bus/usb/003/008 USBDEVFS_GET_CAPABILITIES 0 FD010000 USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 D00000000500BA4500611A297F USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000008009D6200D00001B5A57582000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000008009D6200D00000239572F5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 192 0 D0000001850067980001FE415050000000000030313030303232384C454E4F564F0000474D3138384230004746333230360000312E30322E30310055534200000000005642530000000000303030303030303300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000051239DE6303030303033000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 140 140 0 C001000184008E71000064500F410C0A1800002300000101000101010100010105050100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B737316F3EB36C6A + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 192 0 D0000001850067980002FE4150500000000000303130303032343744454C4C00000000474D3138384230004746353238380000312E30342E30352E31302E3530000000000000000000000000000000000000005553420000000000564253000000000030303030303030330000000000000000000000000000000000000000000000000000000000003B5CB43C000000000000555342000000000056425300000000003030303030303033000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 140 140 0 C001000184008E71000064500F41080A1800002300000101000101010100010105050100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B737316F0558B152 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000208004BB400C00101C96A6C6B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000208004BB400C001005F5A6B1C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 C00100030500FB040093B3ED01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 A6000002050049B600C27E4B39 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 C00100030700D12E0014140342C8AE00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 12 12 0 E00100020400BE41BBC7BACE USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000004080036C900A60001F1AFC9FB000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000004080036C900E00101C26FC596000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A60000050600609F000094D6C40E0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000030700AC53000F411A349263 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 E0010005080054AB00141441240D0ECF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 A6000003050022DD00CA3B9C30 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000060800E01F00A20001605AE410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000060800E01F00A60001BCF2ED17000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A2000007070007F8005564FA6B157100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 44 44 0 A50000042400F40B000000000000000000000000000000000000000000000000000000000000000095D4A28A + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A60000070600B64900007A6860130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000040700BA45000F41625785F3 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000080800CC3300A500013F9036A9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000080800CC3300A20001BA8679AC000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A50000090500DE2103D6515435000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 A10000050500807F007BE269C4 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000090C00BC430054640027004D0084CD5EED0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 44 44 0 A500000524009F60000000000000000000000000000000000000000000000000000000000000000048D9D8CB USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000A08001AE500A10001AE651B42000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000A08001AE500A5000172CD1245000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A100000B250002FD00B786B17D6A044D24C1651C2B1A76F6396D790639F58CA6D62DDDB8E179A9BD4A6C5C6C9200000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200000607006C93000F41A33C2AB4 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A500000B050008F703C6DBFA26000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 A100000605003DC200632D10DE USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000C0800679800A200011C98B985000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000C0800679800A100014526FF87000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200000D0700807F0059643EDA283F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A0000007070055AA016450891085EC + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A100000D25007F8000D7843025CC713EA1543DF81EBAAF6BE244543EB9F4BC6FA74E8F246A711CD8C3EA54665F00000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A2000007070007F8000F41630A457A USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000E0800B14E00A000013F11196A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000E0800B14E00A2000151C59D69000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000000F070004FB000000E0109A2200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B00200080500629D004A354747 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200000F0C00C13E003E620027005900101FD1980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A0000008070012ED016450F8E6B5D9 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001008003FC000B002017532670A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001008003FC000A0000187F37724000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B00200114500A15E008E0091009E006F0083007C006D00690079008800000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009D00000000000000000000000000988D37C39E006F0083007C006D00690079008800000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009D00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200000907002BD4000F41D2CA1A81 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000001107008A7500000002FCFB4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B0020009050009F6004270904E USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000120800E91600A20001A47AD7CB000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000120800E91600B00201386F43E6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200001307000EF1004B640F46BD2D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000000A0700C43B016450398D1A9E + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002001345007788008A009C009400880008009A0099008B00080008009100850000000000000000008F00A4009B0090008F00A100A000940088009A0097008D000000000000000000BEDDBBB29400880008009A0099008B00080008009100850000000000000000008F00A4009B0090008F00A100A000940088009A0097008D +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200000A07009669000F41D397DA08 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000140800946B00A0000121EDB70D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000140800946B00A200014F39330E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A0000015070021DE0000007BC22C5100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002000B0500DF200052FA3E5D + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000150C00E41B004E640027004F00755632510000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000000B0700AF50016450F9BB7550 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000016080042BD00B002019E7183CF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000016080042BD00A000016CB093E1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B00200174500DC23008200A200AA0093009F009800A90087009A009100000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009C00000000000000000000000000F1B14CECAA0093009F009800A90087009A009100000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009C00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200000C0700EB14000F416BC2A256 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A00000170700F708000000BAA9831600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002000C0500C93600FFA00844 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001808006E9100A20001D8B88A5E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001808006E9100B0020144AD1E73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200001907008976005664DBD4593000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000000D0700D22D01645041EE0D0E + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B00200194500F00F008C009C009600080086009D0097008E00810092009100850000000000000000008F00A4009A008F008E00A1009F00920087009A0096008C000000000000000000E3A1F2A19600080086009D0097008E00810092009100850000000000000000008F00A4009A008F008E00A1009F00920087009A0096008C +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200000D0700807F000F41ABF4CD98 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001A0800B84700A00001FB312AB1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001A0800B84700A2000195E5AEB2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000001B07000DF2000000CA0273AA00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002000E05001FE000EF2AA657 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200001B0C00C8370048640027005A00021B15CE0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000000E07006F9001645040B3CD87 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001C0800C53A00B00201E2B3DE5A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001C0800C53A00A000011072CE74000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002001D45005BA400A8009100AB0071008B008F009100920093009100000000000000000000000000AF00A500AD00A000B100A300AA00A200A3009C000000000000000000000000008A57E0B3AB0071008B008F009100920093009100000000000000000000000000AF00A500AD00A000B100A300AA00A200A3009C00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200000F070056A9000F416A9F62DF + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000001D0700708F003A000B89A2D100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002000F0500748B00E76F715E USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001E080013EC00A2000133FB6E9B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001E080013EC00B00201AFEEFAB6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200001F0700F40B005A625A6BF72B00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A00000100700E11E016450A25FACED + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002001F45008D720008009900920086008800960097008D007F0091008D00850000000000000000008F00A4009B0090008F00A100A000930087009A0096008D00000000000000000069C4E77C920086008800960097008D007F0091008D00850000000000000000008F00A4009B0090008F00A100A000930087009A0096008D +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000100700B34C000F4148456C7B USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000200800DE2100A000011D15EAC2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000200800DE2100A2000173C16EC1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000002107006B94002900A6F807F200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B00200110500FA0500438F0629 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000210C00AE510048640027005500DD002B870000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000001107008A750164506269C323 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000022080008F700B00201A289DE00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000022080008F700A000015048CE2E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B00200234500966900870088008800700085009600940070001A001A00000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009D0000000000000000000000000074CA825A8800700085009600940070001A001A00000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009D00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000120700659A000F41892EC33C + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A00000230700BD420000008C0CEEF100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B0020012050047B8005B407F33 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000240800758A00A20001D5DFAEE8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000240800758A00B0020149CA3AC5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000250700926D00556427B73E5900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000001307005CA3016450A3026C64 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B00200254500EB14008D00A100900087000800980099008C00080008000800080000000000000000008F00A3009A008F008E00A0009F00930087009A0096008C0000000000000000000F8D1061900087000800980099008C00080008000800080000000000000000008F00A3009A008F008E00A0009F00930087009A0096008C +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200001307000EF1000F414918ACF2 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000260800A35C00A00001F6560E07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000260800A35C00A2000198828A04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A0000027070016E90058265460564800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002001405003AC500FE5F9E23 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000270C00D32C0057640027004E0017D2351D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000001407004AB5016450DB617BF4 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00002808008F7000B00201DE4B8395000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00002808008F7000A000012C8A93BB000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B0020029450011EE007B00950097006E0084008A007400720078008000000000000000000000000000AE00A500AD00A000B100A200AA00A300A3009D000000000000000000000000007AB44F7697006E0084008A007400720078008000000000000000000000000000AE00A500AD00A000B100A200AA00A300A3009D00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000150700738C000F41F14DD4AC + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000002907003AC500000044F2661300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B0020015050051AE00F61A492A USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00002A080059A600A200010F033354000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00002A080059A600B002019316A779000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200002B0700BE4100566455244C8900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000001607009C630164501A0AD4B3 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002002B4500C7380089009C00920008008A00990098008A007F0093008E00860000000000000000008F00A4009A008F008E00A100A000930087009A0096008D000000000000000000A0269EE8920008008A00990098008A007F0093008E00860000000000000000008F00A4009A008F008E00A100A000930087009A0096008D +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000160700CE31000F41F0101425 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00002C080024DB00A000018A945392000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00002C080024DB00A20001E440D791000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000002D0700916E005F2DD3D14D7200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B00200170500877800E690E739 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200002D0C0054AB004A64002700590057B20D220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A00000170700F708016450DA3CBB7D USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00002E0800F20D00B0020135086750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00002E0800F20D00A00001C7C9777E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002002F45006C9300A80083008A006D00870082008900940074001A00000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009D00000000000000000000000000DD3369188A006D00870082008900940074001A00000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009D00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000180700E21D000F4141D04BDE + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000002F070047B8004C4C4EAAB86E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B00200180500C03F00B4605C02 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003008007C8300A2000111FF9D33000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003008007C8300B002018DEA091E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200003107009B6400586440DB796400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A00000190700DB240164506BFCE486 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B00200314500E21D00080008000800080088009A0096008F00820092009000080000000000000000008F00A3009A008F008E00A000A000930087009A0096008C000000000000000000E0BA753D0800080088009A0096008F00820092009000080000000000000000008F00A3009A008F008E00A000A000930087009A0096008C +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200001907008976000F4181E62410 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000320800AA5500A0000132763DDC000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000320800AA5500A200015CA2B9DF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000003307001FE072635FE0E8A18200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002001A050016E900A4EAF211 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000330C00DA25005464002700500088A694DC0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000001A070066990164506AA1240F USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000340800D72800B002012BF4C937000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000340800D72800A00001D935D919000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B0020035450049B6007D00920094008C009A008B008400890094006D00000000000000000000000000AE00A500AD00A000B100A300AA00A200A3009D00000000000000000000000000520A47F394008C009A008B008400890094006D00000000000000000000000000AE00A500AD00A000B100A300AA00A200A3009D00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200001B07005FA0000F41408D8B57 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A00000350700629D0000006775A83E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002001B05007D8200ACAF2518 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000036080001FE00A20001FABC79F6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000036080001FE00B0020166A9EDDB000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000370700E619005964B9BF1A2300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000001C07001BE4016450D2F45C51 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002003745009F600008000800080008008600970095000800830090008D00880000000000000000008F00A3009A008F008E00A100A000930087009A0096008C000000000000000000F054EC42080008008600970095000800830090008D00880000000000000000008F00A3009A008F008E00A100A000930087009A0096008C +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200001C070049B6000F4138EE9CC7 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003808002DD200A000014EB46049000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003808002DD200A200012060E44A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000003907009867725F526A136B6D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002001D050000FF0009B0C408 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000390C005DA2004A640027004F005D569D1A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000001D0700708F01645012C2339F USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003A0800FB0400B00201F128548B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003A0800FB0400A0000103E944A5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002003B4500659A0084007D008B0099009C006A009A007B0089008300000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009C00000000000000000000000000BAEEF1FA8B0099009C006A009A007B0089008300000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009C00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200001E07009F60000F41F9853380 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000003B07004EB1000000D6B5F7C500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A300001E0700B649000F41F8F75650 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003C0800867900A20001867E2463000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003C0800867900A30001B114E662000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200003D0700619E005864307089D800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000001F0700A659016450D3A99CD8 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A300003D0500629D009DDA98C4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 114 114 0 A400001F6A001EE1640043010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F647900E6F6BD05 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003E080050AF00A00001A5F7848C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003E080050AF00A40001795F8D8B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000003F0700E51A0063324BE2275A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B00200200500708F00DCB5EECB + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A400003F05006B940099962233000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 12 12 0 E0000020040049B6AEA0E8AB USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004008001BE400B00201E7BD49D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004008001BE400E00001D5F1C38E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B00200414500857A0078006F0074009200A6008C0071006C008E009400000000000000000000000000AF00A500AD00A000B100A300A900A200A3009C0000000000000000000000000079DB6FC674009200A6008C0071006C008E009400000000000000000000000000AF00A500AD00A000B100A300A900A200A3009C00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A2000021070039C6000F41C7E8B94B + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 E000004108001BE400000000315A099D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 A60000210500B74800B39B168D USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000420800CD3200A2000136F5F911000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000420800CD3200A60001EA5DF016000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200004307002AD5005A647427533000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A00000220700D6290164502CAFB954 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 A60000436C00EC130001640043010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F647900FA60A49A000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 12 12 0 E00100220400FD0253E4FA3B USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000440800B04F00A00001B36299D7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000440800B04F00E0010132DE18BE000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A0000045070005FA0061447F5F4C1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B00200230500CD3200C47A97D1 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 E00100450800D22D000000002B1189D3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000230700EF100100238AF5F029 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000460800669900B002010CFEAD15000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000460800669900A2000190EB3938000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B00200474500F807009500860087008D00A3006D007D0081009C007C00000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009C0000000000000000000000000074D7CC3787008D00A3006D007D0081009C007C00000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009C00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000240700F906000F417EE0019C + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000470C0016E9004C640027004D005C10F4310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 44 44 0 A50000242400B7480000000000000000000000000000000000000000000000000000000000000000664B5D3F USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004808004AB500A200014A37A484000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004808004AB500A50001CF21EB81000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000490700AD52005764F1A7756700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A00000250700C03F01645054CCAEC4 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 192 0 A50000499200D22D004C642A00000000640043010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F647900954F9F36EAEDD0364E04D4A2B430F0D25BF63D97E631EC0F0F86A6A3DCDEF50C82BB7E8C2D30303030303030302D302D30303030303030302D6E6F626F647900954F9F36EAEDD0364E04 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 12 12 0 E000002504008976203A9633 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004A08009C6300A0000169BE046B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004A08009C6300E00001A9339E1B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000004B070029D60041281F96933800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002002605000DF20079AA0FDB + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 E000004B08009C63004C642A9C8BFEAB000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 12 12 0 E0010026040056A9D15D8DC2 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004C0800E11E00B00201703CF080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004C0800E11E00E00101034161C7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002004D45007F80009E008E008E007E00AB00840096007F0092008100000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009C00000000000000000000000000D393E7738E007E00AB00840096007F0092008100000000000000000000000000AF00A500AD00A000B100A300AA00A300A3009C00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A2000027070044BB000F417FBDC115 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 E001004D0800837C004C642ACB9D5A09000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A2000027070044BB010023F3CB2730 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004E080037C800A20001A1744041000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200004F0700D02F005964C7DF8EA700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A0000028070051AE016450E45131B6 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200004F0C0047B80052640027004D00E19CE96F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 44 44 0 A500002824004DB200000000000000000000000000000000000000000000000000000000000000003DB8032C USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000500800B94600A000017742AA0C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000500800B94600A500019C80610A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000005107000CF300624F1EC75A2600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002002905004AB5002B5AB4E0 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 192 0 A5000051920021DE0052642A00000000640043010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F647900954F9F36EAEDD0364E04D4A2B430F0D25BF63D97E631EC0F0F86A6A3DCDEF50CCC7D08E82D30303030303030302D302D30303030303030302D6E6F626F647900954F9F36EAEDD0364E04 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 12 12 0 E00000290400738C14C55D45 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00005208006F9000B00201C8DE9ECE000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00005208006F9000E00001FA921490000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B00200534500F10E0077007A00720083007500930073007E006E008200000000000000000000000000AE00A400AC009F00B100A200A900A200A3009C00000000000000000000000000C5190965720083007500930073007E006E008200000000000000000000000000AE00A400AC009F00B100A200A900A200A3009C00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200002A0700D52A000F41CF205E67 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 E000005308006F900052642AB5A4CC36000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 114 114 0 A700002A6A0044BB640043010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F6479001CF66539 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000054080012ED00A20001BF88EE26000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000054080012ED00A70001544A2520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000550700F50A0058641D3C23CD00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000002B0700EC13016450E50CF13F - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000560800C43B00A000019C014EC9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A00000570700718E726054F685049700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002002C05008A7500968A2CEA - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000580800E81700B00201B41CC35B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002005945007689008C007100780072007A009500A10088009C008F00000000000000000000000000AE00A500AD00A000B100A200A900A200A3009C00000000000000000000000000D98A26F0780072007A009500A10088009C008F00000000000000000000000000AE00A500AD00A000B100A200A900A200A3009C00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200002D0700C33C000F41B74349F7 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00005A08003EC100A200016554739A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200005B0700D926005964EDCD672F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000002E07002CD30164505C0449E8 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00005C080043BC00A00001E0C3135C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000005D0700F609725F58291DE42400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002002F050037C8008E4555F0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00005E0800956A00B002015F5F279E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002005F45000BF400A30088009D008D00A80071007F0092006F006100000000000000000000000000AE00A400AC009F00B100A200A900A200A3009C000000000000000000000000001A1438ED9D008D00A80071007F0092006F006100000000000000000000000000AE00A400AC009F00B100A200A900A200A3009C00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000300700F00F000F4154F2E814 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000060080058A700A200018370B3E9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000610700BF400059646AA8553300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A00000310700C9360164507EDE474C - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00006208008E7100A00001A0F91306000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000006307003BC4006432979DA1E700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B0020032050004FB00326A5B9D - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000640800F30C00B00201B97BE7ED000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002006545006D92008D008F008A00750083008D0092008B0071007A00000000000000000000000000AE00A500AD00A000B100A200A900A200A3009C00000000000000000000000000394AB8458A00750083008D0092008B0071007A00000000000000000000000000AE00A500AD00A000B100A200A900A200A3009C00000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200003307004DB2000F4155AF289D - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000066080025DA00A200016833572C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000670700C23D0057645CD0AEF300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A0000034070009F6016450C7D6FF9B - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000068080009F600A00001DC3B4E93000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A00000690700BC43002E00509568C700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A3000035070019E6000F41EC883513 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00006A0800DF2000A30001C8D82C7D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A300006B05003BC40055C25B16000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 114 114 0 A40000366A006798640043010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F647900B5C8699F - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00006C0800A25D00A40001A68D87BD000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A400006D0500996600E41BAEE2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 A60000370500689700E8D1ECD8 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00006E0800748B00A6000185042752000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 A600006F6C0055AA0001640043010107000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F6479006EA4C362000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000380700A15E010023D1112994 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000700800FA0500A20001E14E401B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200007107001DE2005A635942221700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 44 44 0 A50000392400847B000000000000000000000000000000000000000000000000000000000000000038910386 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00007208002CD300A5000129052BF2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 192 0 A50000739300A15E005A632900000000640043010107000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F6479008B7767E4A81CC57C17A21C0F44B08232229E7F2E5DBFA70A5CEF58A3966ED710002FF9938030303030303030302D302D30303030303030302D6E6F626F6479008B7767E4A81CC57C17A2 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 a200003a07007788010023107a86d3 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000700800FA0500A20001E14E401B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200007107001DE2005A635942221700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 44 44 0 a500003b240052ad0000000000000000000000000000000000000000000000000000000000000000828af704 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00007208002CD300A5000129052BF2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 192 0 A50000739300A15E005A632900000000640043010107000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F6479008B7767E4A81CC57C17A21C0F44B08232229E7F2E5DBFA70A5CEF58A3966ED710002FF9938030303030303030302D302D30303030303030302D6E6F626F6479008B7767E4A81CC57C17A2 -USBDEVFS_REAPURBNDELAY 0 3 1 0 0 114 114 0 a700003c6a009b64640043010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e4650312d30303030303030302d302d30303030303030302d6e6f626f647900473c9b29 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000074080051AE00A70001AC924B34000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0 - USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A7000075050011EE00ACFFDA28000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A7000055050052AD00C5D5FE86000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/tests/goodixmoc/device b/tests/goodixmoc/device index 627c9dc0..a076caa1 100644 --- a/tests/goodixmoc/device +++ b/tests/goodixmoc/device @@ -1,30 +1,30 @@ -P: /devices/pci0000:00/0000:00:14.0/usb1/1-8 -N: bus/usb/001/003=12010002EF000040C627A26000010102030109022000010103A0320904000002FF0000040705830240000007050102400000 -E: DEVNAME=/dev/bus/usb/001/003 +P: /devices/pci0000:00/0000:00:14.0/usb3/3-2 +N: bus/usb/003/008=12010002EF000040C627405800010102030109022000010103A0320904000002FF0000040705830240000007050102400000 +E: DEVNAME=/dev/bus/usb/003/008 E: DEVTYPE=usb_device E: DRIVER=usb -E: PRODUCT=27c6/60a2/100 +E: PRODUCT=27c6/5840/100 E: TYPE=239/0/0 -E: BUSNUM=001 -E: DEVNUM=003 +E: BUSNUM=003 +E: DEVNUM=008 E: MAJOR=189 -E: MINOR=2 +E: MINOR=263 E: SUBSYSTEM=usb E: ID_VENDOR=Goodix_Technology_Co.__Ltd. E: ID_VENDOR_ENC=Goodix\x20Technology\x20Co.\x2c\x20Ltd. E: ID_VENDOR_ID=27c6 E: ID_MODEL=Goodix_USB2.0_MISC E: ID_MODEL_ENC=Goodix\x20USB2.0\x20MISC -E: ID_MODEL_ID=60a2 +E: ID_MODEL_ID=5840 E: ID_REVISION=0100 -E: ID_SERIAL=Goodix_Technology_Co.__Ltd._Goodix_USB2.0_MISC_UIDCBEE4D7B_XXXX_MOC_B0 -E: ID_SERIAL_SHORT=UIDCBEE4D7B_XXXX_MOC_B0 +E: ID_SERIAL=Goodix_Technology_Co.__Ltd._Goodix_USB2.0_MISC_UIDE1AD5CBA_XXXX_MOC_B0 +E: ID_SERIAL_SHORT=UIDE1AD5CBA_XXXX_MOC_B0 E: ID_BUS=usb E: ID_USB_INTERFACES=:ff0000: E: ID_VENDOR_FROM_DATABASE=Shenzhen Goodix Technology Co.,Ltd. -E: ID_PATH=pci-0000:00:14.0-usb-0:8 -E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8 -E: LIBFPRINT_DRIVER=AuthenTec AES1610 +E: ID_PATH=pci-0000:00:14.0-usb-0:2 +E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_2 +E: LIBFPRINT_DRIVER=Goodix MOC Fingerprint Sensor A: authorized=1 A: avoid_reset_quirk=0 A: bConfigurationValue=1 @@ -37,32 +37,32 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0100 A: bmAttributes=a0 -A: busnum=1 -A: configuration=UIDCBEE4D7B_XXXX_MOC_B0 -H: descriptors=12010002EF000040C627A26000010102030109022000010103A0320904000002FF0000040705830240000007050102400000 -A: dev=189:2 -A: devnum=3 -A: devpath=8 +A: busnum=3\n +A: configuration=UIDE1AD5CBA_XXXX_MOC_B0 +H: descriptors=12010002EF000040C627405800010102030109022000010103A0320904000002FF0000040705830240000007050102400000 +A: dev=189:263 +A: devnum=8\n +A: devpath=2 L: driver=../../../../../bus/usb/drivers/usb -A: idProduct=60a2 +A: idProduct=5840 A: idVendor=27c6 A: ltm_capable=no A: manufacturer=Goodix Technology Co., Ltd. A: maxchild=0 -L: port=../1-0:1.0/usb1-port8 -A: power/active_duration=324448 +L: port=../3-0:1.0/usb3-port2 +A: power/active_duration=2684 A: power/async=enabled A: power/autosuspend=2 A: power/autosuspend_delay_ms=2000 -A: power/connected_duration=5916532 +A: power/connected_duration=54348 A: power/control=auto A: power/level=auto A: power/persist=1 A: power/runtime_active_kids=0 -A: power/runtime_active_time=327268 +A: power/runtime_active_time=2518 A: power/runtime_enabled=enabled A: power/runtime_status=active -A: power/runtime_suspended_time=5588987 +A: power/runtime_suspended_time=51550 A: power/runtime_usage=0 A: power/wakeup=disabled A: power/wakeup_abort_count= @@ -75,38 +75,39 @@ A: power/wakeup_max_time_ms= A: power/wakeup_total_time_ms= A: product=Goodix USB2.0 MISC A: quirks=0x0 -A: removable=fixed +A: removable=removable A: rx_lanes=1 -A: serial=UIDCBEE4D7B_XXXX_MOC_B0 +A: serial=UIDE1AD5CBA_XXXX_MOC_B0 A: speed=12 A: tx_lanes=1 -A: urbnum=2180 +A: urbnum=15 A: version= 2.00 -P: /devices/pci0000:00/0000:00:14.0/usb1 -N: bus/usb/001/001=12010002090001406B1D020004050302010109021900010100E0000904000001090000000705810304000C -E: DEVNAME=/dev/bus/usb/001/001 +P: /devices/pci0000:00/0000:00:14.0/usb3 +N: bus/usb/003/001=12010002090001406B1D020008050302010109021900010100E0000904000001090000000705810304000C +E: DEVNAME=/dev/bus/usb/003/001 E: DEVTYPE=usb_device E: DRIVER=usb -E: PRODUCT=1d6b/2/504 +E: PRODUCT=1d6b/2/508 E: TYPE=9/0/1 -E: BUSNUM=001 +E: BUSNUM=003 E: DEVNUM=001 E: MAJOR=189 -E: MINOR=0 +E: MINOR=256 E: SUBSYSTEM=usb -E: ID_VENDOR=Linux_5.4.0-29-generic_xhci-hcd -E: ID_VENDOR_ENC=Linux\x205.4.0-29-generic\x20xhci-hcd +E: ID_VENDOR=Linux_5.8.0-38-generic_xhci-hcd +E: ID_VENDOR_ENC=Linux\x205.8.0-38-generic\x20xhci-hcd E: ID_VENDOR_ID=1d6b E: ID_MODEL=xHCI_Host_Controller E: ID_MODEL_ENC=xHCI\x20Host\x20Controller E: ID_MODEL_ID=0002 -E: ID_REVISION=0504 -E: ID_SERIAL=Linux_5.4.0-29-generic_xhci-hcd_xHCI_Host_Controller_0000:00:14.0 +E: ID_REVISION=0508 +E: ID_SERIAL=Linux_5.8.0-38-generic_xhci-hcd_xHCI_Host_Controller_0000:00:14.0 E: ID_SERIAL_SHORT=0000:00:14.0 E: ID_BUS=usb E: ID_USB_INTERFACES=:090000: E: ID_VENDOR_FROM_DATABASE=Linux Foundation +E: ID_AUTOSUSPEND=1 E: ID_MODEL_FROM_DATABASE=2.0 root hub E: ID_PATH=pci-0000:00:14.0 E: ID_PATH_TAG=pci-0000_00_14_0 @@ -123,33 +124,33 @@ A: bMaxPacketSize0=64 A: bMaxPower=0mA A: bNumConfigurations=1 A: bNumInterfaces= 1 -A: bcdDevice=0504 +A: bcdDevice=0508 A: bmAttributes=e0 -A: busnum=1 +A: busnum=3\n A: configuration= -H: descriptors=12010002090001406B1D020004050302010109021900010100E0000904000001090000000705810304000C -A: dev=189:0 -A: devnum=1 +H: descriptors=12010002090001406B1D020008050302010109021900010100E0000904000001090000000705810304000C +A: dev=189:256 +A: devnum=1\n A: devpath=0 L: driver=../../../../bus/usb/drivers/usb A: idProduct=0002 A: idVendor=1d6b A: interface_authorized_default=1 A: ltm_capable=no -A: manufacturer=Linux 5.4.0-29-generic xhci-hcd -A: maxchild=12 -A: power/active_duration=5879432 +A: manufacturer=Linux 5.8.0-38-generic xhci-hcd +A: maxchild=4 +A: power/active_duration=2790916 A: power/async=enabled A: power/autosuspend=0 A: power/autosuspend_delay_ms=0 -A: power/connected_duration=5916912 +A: power/connected_duration=15607832 A: power/control=auto A: power/level=auto -A: power/runtime_active_kids=2 -A: power/runtime_active_time=5879430 +A: power/runtime_active_kids=1 +A: power/runtime_active_time=2790874 A: power/runtime_enabled=enabled A: power/runtime_status=active -A: power/runtime_suspended_time=37481 +A: power/runtime_suspended_time=12816956 A: power/runtime_usage=0 A: power/wakeup=disabled A: power/wakeup_abort_count= @@ -167,5 +168,7 @@ A: rx_lanes=1 A: serial=0000:00:14.0 A: speed=480 A: tx_lanes=1 -A: urbnum=1319 +A: urbnum=584 A: version= 2.00 + + diff --git a/tests/hwdb-check-unsupported.py b/tests/hwdb-check-unsupported.py new file mode 100755 index 00000000..650cd099 --- /dev/null +++ b/tests/hwdb-check-unsupported.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +import os +import sys +import urllib +import urllib.request +import re + +error = False + +try: + response = urllib.request.urlopen('https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices.md') +except: + print("Could not download current list of unsupported devices, skipping test.") + sys.exit(77) +data = response.read().decode('utf-8') + +devices = [] +devices_re = re.compile(r'^.*([0-9a-fA-F]{4}):([0-9a-fA-F]{4}).*$', re.MULTILINE) +for m in devices_re.finditer(data): + vid = m.group(1) + pid = m.group(2) + devices.append((vid, pid)) + +generator = open(os.path.join(os.path.dirname(__file__), '..', 'libfprint', 'fprint-list-udev-hwdb.c')).read() + +id_re = re.compile(' { .vid = 0x([a-fA-F0-9]*), .pid = 0x([a-fA-F0-9]*) }') +# Check everything is the same +started = False +for l in generator.split('\n'): + m = id_re.match(l) + if m is None: + # Stop on the first line that does not match anymore + if started: + break + continue + else: + started = True + + vid_pid = (m.group(1), m.group(2)) + try: + devices.remove(vid_pid) + except ValueError: + print("Generator has entry that is not on wiki: {}:{}".format(*vid_pid)) + error = True + +for vid_pid in devices: + print("New entry from wiki is missing: {}:{}".format(*vid_pid)) + error = True + +if error: + sys.exit(1) +else: + sys.exit(0) diff --git a/tests/meson.build b/tests/meson.build index b8d1c8a8..492502e4 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -5,6 +5,7 @@ envs.set('G_MESSAGES_DEBUG', 'all') # Setup paths envs.set('MESON_SOURCE_ROOT', meson.source_root()) +envs.set('MESON_BUILD_ROOT', meson.build_root()) envs.prepend('LD_LIBRARY_PATH', join_paths(meson.build_root(), 'libfprint')) # Set FP_DEVICE_EMULATION so that drivers can adapt (e.g. to use fixed @@ -12,7 +13,11 @@ envs.prepend('LD_LIBRARY_PATH', join_paths(meson.build_root(), 'libfprint')) envs.set('FP_DEVICE_EMULATION', '1') # Set a colon-separated list of native drivers we enable in tests -envs.set('FP_DRIVERS_WHITELIST', 'virtual_image') +envs.set('FP_DRIVERS_WHITELIST', ':'.join([ + 'virtual_image', + 'virtual_device', + 'virtual_device_storage', +])) envs.set('NO_AT_BRIDGE', '1') @@ -28,49 +33,58 @@ drivers_tests = [ if get_option('introspection') envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint')) + virtual_devices_tests = [ + 'virtual-image', + 'virtual-device', + ] - if 'virtual_image' in drivers - python3 = find_program('python3') - unittest_inspector = find_program('unittest_inspector.py') - base_args = files('virtual-image.py') - suite = [] + unittest_inspector = find_program('unittest_inspector.py') - r = run_command(unittest_inspector, files('virtual-image.py')) - unit_tests = r.stdout().strip().split('\n') + foreach vdtest: virtual_devices_tests + driver_name = '_'.join(vdtest.split('-')) + if driver_name in drivers + python3 = find_program('python3') + base_args = files(vdtest + '.py') + suite = ['virtual-driver'] - if r.returncode() == 0 and unit_tests.length() > 0 - suite += 'virtual-image' - else - unit_tests = ['virtual-image'] - endif + r = run_command(unittest_inspector, files(vdtest + '.py')) + unit_tests = r.stdout().strip().split('\n') - foreach ut: unit_tests - ut_suite = suite - ut_args = base_args - if unit_tests.length() > 1 - ut_args += ut - ut_suite += ut.split('.')[0] + if r.returncode() == 0 and unit_tests.length() > 0 + suite += vdtest + else + unit_tests = [vdtest] endif - test(ut, - python3, - args: ut_args, - suite: ut_suite, - depends: libfprint_typelib, - env: envs, + + foreach ut: unit_tests + ut_suite = suite + ut_args = base_args + if unit_tests.length() > 1 + ut_args += ut + ut_suite += ut.split('.')[0] + endif + test(ut, + python3, + args: ut_args, + suite: ut_suite, + depends: libfprint_typelib, + env: envs, + ) + endforeach + else + test(vdtest, + find_program('sh'), + args: ['-c', 'exit 77'] ) - endforeach - else - test('virtual-image', - find_program('sh'), - args: ['-c', 'exit 77'] - ) - endif + endif + endforeach foreach driver_test: drivers_tests driver_envs = envs driver_envs.set('FP_DRIVERS_WHITELIST', driver_test) - if driver_test in drivers and gusb_dep.version().version_compare('>= 0.3.0') + if (driver_test in supported_drivers and + gusb_dep.version().version_compare('>= 0.3.0')) test(driver_test, find_program('umockdev-test.py'), args: join_paths(meson.current_source_dir(), driver_test), @@ -168,6 +182,13 @@ foreach test_name: unit_tests ) endforeach +# Run udev rule generator with fatal warnings +envs.set('UDEV_HWDB', udev_hwdb.full_path()) +envs.set('UDEV_HWDB_CHECK_CONTENTS', default_drivers_are_enabled ? '1' : '0') +test('udev-hwdb', + find_program('test-generated-hwdb.sh'), + env: envs) + gdb = find_program('gdb', required: false) if gdb.found() add_test_setup('gdb', @@ -188,6 +209,7 @@ if valgrind.found() timeout_multiplier: 10, env: [ 'G_SLICE=always-malloc', + 'UNDER_VALGRIND=1', ('LIBFPRINT_TEST_WRAPPER=@0@ --tool=memcheck --leak-check=full ' + '--suppressions=@1@ --suppressions=@2@').format( valgrind.path(), glib_suppressions, python_suppressions) diff --git a/tests/synaptics/device b/tests/synaptics/device index 6da3eea7..87c4bed2 100644 --- a/tests/synaptics/device +++ b/tests/synaptics/device @@ -34,11 +34,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0000 A: bmAttributes=a0 -A: busnum=1 +A: busnum=1\n A: configuration= H: descriptors=12010002FF10FF08CB06BD0000000000010109022700010100A0320904000003FF000000070501024000000705810240000007058303080004 A: dev=189:69 -A: devnum=70 +A: devnum=70\n A: devpath=1 L: driver=../../../../../bus/usb/drivers/usb A: idProduct=00bd diff --git a/tests/test-fp-context.c b/tests/test-fp-context.c index 156e6d47..c74548cd 100644 --- a/tests/test-fp-context.c +++ b/tests/test-fp-context.c @@ -50,7 +50,7 @@ test_context_has_virtual_device (void) GPtrArray *devices; unsigned int i; - fpt_setup_virtual_device_environment (); + fpt_setup_virtual_device_environment (FPT_VIRTUAL_DEVICE_IMAGE); context = fp_context_new (); devices = fp_context_get_devices (context); @@ -82,7 +82,7 @@ test_context_enumerates_new_devices (void) context = fp_context_new (); - fpt_setup_virtual_device_environment (); + fpt_setup_virtual_device_environment (FPT_VIRTUAL_DEVICE_IMAGE); fp_context_enumerate (context); devices = fp_context_get_devices (context); @@ -120,7 +120,7 @@ context_device_removed_cb (FpContext *ctx, FpDevice *device, FptContext *tctx) static void test_context_remove_device_closed (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); gboolean removed; tctx->user_data = NULL; @@ -162,7 +162,7 @@ close_done_cb (GObject *device, GAsyncResult *res, gpointer user_data) static void test_context_remove_device_closing (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); g_autoptr(GError) close_error = NULL; g_autoptr(GError) error = NULL; gboolean removed; @@ -207,7 +207,7 @@ test_context_remove_device_closing (void) static void test_context_remove_device_open (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); g_autoptr(GError) error = NULL; gboolean removed = FALSE; @@ -267,7 +267,7 @@ open_done_cb (GObject *device, GAsyncResult *res, gpointer user_data) static void test_context_remove_device_opening (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); g_autoptr(GError) close_error = NULL; gboolean open_done = FALSE; gboolean removed; @@ -327,7 +327,7 @@ enroll_done_cb (GObject *device, GAsyncResult *res, gpointer user_data) static void test_context_remove_device_active (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); g_autoptr(GError) error = NULL; g_autoptr(GCancellable) cancellable = NULL; g_autoptr(GError) enroll_error = NULL; diff --git a/tests/test-fp-device.c b/tests/test-fp-device.c index e3eb662e..b8f6f172 100644 --- a/tests/test-fp-device.c +++ b/tests/test-fp-device.c @@ -36,7 +36,7 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, FptContext *tctx) static void test_device_open_async (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open (tctx->device, NULL, (GAsyncReadyCallback) on_device_opened, tctx); @@ -59,7 +59,7 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, FptContext *tctx) static void test_device_close_async (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open (tctx->device, NULL, (GAsyncReadyCallback) on_device_opened, tctx); while (!tctx->user_data) @@ -76,7 +76,7 @@ static void test_device_open_sync (void) { g_autoptr(GError) error = NULL; - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open_sync (tctx->device, NULL, &error); g_assert_no_error (error); @@ -97,7 +97,7 @@ static void test_device_open_sync_notify (void) { g_autoptr(GError) error = NULL; - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); g_signal_connect (tctx->device, "notify::open", G_CALLBACK (on_open_notify), tctx); fp_device_open_sync (tctx->device, NULL, &error); @@ -109,7 +109,7 @@ static void test_device_close_sync (void) { g_autoptr(GError) error = NULL; - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open_sync (tctx->device, NULL, NULL); fp_device_close_sync (tctx->device, NULL, &error); @@ -131,7 +131,7 @@ static void test_device_close_sync_notify (void) { g_autoptr(GError) error = NULL; - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open_sync (tctx->device, NULL, NULL); @@ -144,7 +144,7 @@ test_device_close_sync_notify (void) static void test_device_get_driver (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open_sync (tctx->device, NULL, NULL); g_assert_cmpstr (fp_device_get_driver (tctx->device), ==, "virtual_image"); @@ -153,7 +153,7 @@ test_device_get_driver (void) static void test_device_get_device_id (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open_sync (tctx->device, NULL, NULL); g_assert_cmpstr (fp_device_get_device_id (tctx->device), ==, "0"); @@ -162,7 +162,7 @@ test_device_get_device_id (void) static void test_device_get_name (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open_sync (tctx->device, NULL, NULL); g_assert_cmpstr (fp_device_get_name (tctx->device), ==, @@ -172,7 +172,7 @@ test_device_get_name (void) static void test_device_get_scan_type (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open_sync (tctx->device, NULL, NULL); g_assert_cmpint (fp_device_get_scan_type (tctx->device), ==, FP_SCAN_TYPE_SWIPE); @@ -181,7 +181,7 @@ test_device_get_scan_type (void) static void test_device_get_finger_status (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open_sync (tctx->device, NULL, NULL); g_assert_cmpint (fp_device_get_finger_status (tctx->device), ==, FP_FINGER_STATUS_NONE); @@ -190,7 +190,7 @@ test_device_get_finger_status (void) static void test_device_get_nr_enroll_stages (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open_sync (tctx->device, NULL, NULL); g_assert_cmpuint (fp_device_get_nr_enroll_stages (tctx->device), ==, 5); @@ -199,7 +199,7 @@ test_device_get_nr_enroll_stages (void) static void test_device_supports_identify (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open_sync (tctx->device, NULL, NULL); g_assert_true (fp_device_supports_identify (tctx->device)); @@ -208,7 +208,7 @@ test_device_supports_identify (void) static void test_device_supports_capture (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open_sync (tctx->device, NULL, NULL); g_assert_true (fp_device_supports_capture (tctx->device)); @@ -217,7 +217,7 @@ test_device_supports_capture (void) static void test_device_has_storage (void) { - g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); fp_device_open_sync (tctx->device, NULL, NULL); g_assert_false (fp_device_has_storage (tctx->device)); diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 43261285..b2f99d34 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -453,7 +453,7 @@ test_driver_set_nr_enroll_stages (void) g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); g_autoptr(GParamSpec) pspec = NULL; FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - int expected_stages = g_random_int_range (G_MININT32, G_MAXINT32); + int expected_stages = g_random_int_range (1, G_MAXINT32); g_signal_connect (device, "notify::nr-enroll-stages", G_CALLBACK (on_device_notify), NULL); fpi_device_set_nr_enroll_stages (device, expected_stages); @@ -463,6 +463,18 @@ test_driver_set_nr_enroll_stages (void) pspec = g_steal_pointer (&fake_dev->user_data); g_assert_cmpstr (pspec->name, ==, "nr-enroll-stages"); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, + "*enroll_stages > 0*"); + fpi_device_set_nr_enroll_stages (device, 0); + g_assert_cmpint (fp_device_get_nr_enroll_stages (device), ==, expected_stages); + g_test_assert_expected_messages (); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, + "*enroll_stages > 0*"); + fpi_device_set_nr_enroll_stages (device, -2); + g_assert_cmpint (fp_device_get_nr_enroll_stages (device), ==, expected_stages); + g_test_assert_expected_messages (); } static void diff --git a/tests/test-generated-hwdb.sh b/tests/test-generated-hwdb.sh new file mode 100755 index 00000000..87c08bbf --- /dev/null +++ b/tests/test-generated-hwdb.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -e + +[ -x "$UDEV_HWDB" ] || exit 1 + +if [ "$UDEV_HWDB_CHECK_CONTENTS" == 1 ]; then + generated_rules=$(mktemp "${TMPDIR:-/tmp}/libfprint-XXXXXX.hwdb") +else + generated_rules=/dev/null +fi + +$UDEV_HWDB > "$generated_rules" + +if [ "$UDEV_HWDB_CHECK_CONTENTS" != 1 ]; then + exit 77 +fi + +if ! diff -u "$MESON_SOURCE_ROOT/data/autosuspend.hwdb" "$generated_rules"; then + echo "E: Autosuspend file needs to be re-generated!" + echo " ninja -C $MESON_BUILD_ROOT libfprint/sync-udev-hwdb" + exit 1 +fi + +rm "$generated_rules" diff --git a/tests/test-utils.c b/tests/test-utils.c index 834a90e8..a14d1cae 100644 --- a/tests/test-utils.c +++ b/tests/test-utils.c @@ -22,16 +22,31 @@ #include "test-utils.h" +struct +{ + const char *envvar; + const char *driver_id; + const char *device_id; +} devtype_vars[FPT_NUM_VIRTUAL_DEVICE_TYPES] = { + { "FP_VIRTUAL_IMAGE", "virtual_image", "virtual_image" }, /* FPT_VIRTUAL_DEVICE_IMAGE */ + { "FP_VIRTUAL_DEVICE", "virtual_device", "virtual_device" }, /* FPT_VIRTUAL_DEVICE_NONIMAGE */ + { "FP_VIRTUAL_DEVICE_STORAGE", "virtual_device_storage", "virtual_device_storage" } /* FPT_VIRTUAL_DEVICE_NONIMAGE_STORAGE */ +}; + +static FptVirtualDeviceType global_devtype; + void fpt_teardown_virtual_device_environment (void) { - const char *path = g_getenv ("FP_VIRTUAL_IMAGE"); + const char *path; + + path = g_getenv (devtype_vars[global_devtype].envvar); if (path) { g_autofree char *temp_dir = g_path_get_dirname (path); - g_unsetenv ("FP_VIRTUAL_IMAGE"); + g_unsetenv (devtype_vars[global_devtype].envvar); g_unlink (path); g_rmdir (temp_dir); } @@ -44,19 +59,23 @@ on_signal_event (int sig) } void -fpt_setup_virtual_device_environment (void) +fpt_setup_virtual_device_environment (FptVirtualDeviceType devtype) { g_autoptr(GError) error = NULL; g_autofree char *temp_dir = NULL; g_autofree char *temp_path = NULL; + g_autofree char *filename = NULL; - g_assert_null (g_getenv ("FP_VIRTUAL_IMAGE")); + g_assert_null (g_getenv (devtype_vars[devtype].envvar)); temp_dir = g_dir_make_tmp ("libfprint-XXXXXX", &error); g_assert_no_error (error); - temp_path = g_build_filename (temp_dir, "virtual-image.socket", NULL); - g_setenv ("FP_VIRTUAL_IMAGE", temp_path, TRUE); + filename = g_strdup_printf ("%s.socket", devtype_vars[devtype].device_id); + temp_path = g_build_filename (temp_dir, filename, NULL); + g_setenv (devtype_vars[devtype].envvar, temp_path, TRUE); + + global_devtype = devtype; signal (SIGKILL, on_signal_event); signal (SIGABRT, on_signal_event); @@ -78,13 +97,16 @@ fpt_context_new (void) } FptContext * -fpt_context_new_with_virtual_imgdev (void) +fpt_context_new_with_virtual_device (FptVirtualDeviceType devtype) { FptContext *tctx; GPtrArray *devices; unsigned int i; - fpt_setup_virtual_device_environment (); + g_assert_true (devtype >= FPT_VIRTUAL_DEVICE_IMAGE && + devtype < FPT_NUM_VIRTUAL_DEVICE_TYPES); + + fpt_setup_virtual_device_environment (devtype); tctx = fpt_context_new (); devices = fp_context_get_devices (tctx->fp_context); @@ -96,7 +118,7 @@ fpt_context_new_with_virtual_imgdev (void) { FpDevice *device = devices->pdata[i]; - if (g_strcmp0 (fp_device_get_driver (device), "virtual_image") == 0) + if (g_strcmp0 (fp_device_get_driver (device), devtype_vars[devtype].driver_id) == 0) { tctx->device = device; break; diff --git a/tests/test-utils.h b/tests/test-utils.h index 4bc1e699..7419a4c7 100644 --- a/tests/test-utils.h +++ b/tests/test-utils.h @@ -19,7 +19,14 @@ #include -void fpt_setup_virtual_device_environment (void); +typedef enum { + FPT_VIRTUAL_DEVICE_IMAGE = 0, + FPT_VIRTUAL_DEVICE_NONIMAGE, + FPT_VIRTUAL_DEVICE_NONIMAGE_STORAGE, + FPT_NUM_VIRTUAL_DEVICE_TYPES +} FptVirtualDeviceType; + +void fpt_setup_virtual_device_environment (FptVirtualDeviceType devtype); void fpt_teardown_virtual_device_environment (void); typedef struct _FptContext @@ -30,7 +37,7 @@ typedef struct _FptContext } FptContext; FptContext * fpt_context_new (void); -FptContext * fpt_context_new_with_virtual_imgdev (void); +FptContext * fpt_context_new_with_virtual_device (FptVirtualDeviceType devtype); void fpt_context_free (FptContext *test_context); diff --git a/tests/umockdev-test.py b/tests/umockdev-test.py old mode 100644 new mode 100755 diff --git a/tests/vfs0050/device b/tests/vfs0050/device index 1bea50a0..b66be4ba 100644 --- a/tests/vfs0050/device +++ b/tests/vfs0050/device @@ -38,11 +38,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0060 A: bmAttributes=a0 -A: busnum=1 +A: busnum=1\n A: configuration= H: descriptors=12011001FF10FF088A13500060000000010109022E00010100A0320904000004FF00000007050102400000070581024000000705820240000007058303080004 A: dev=189:3 -A: devnum=4 +A: devnum=4\n A: devpath=9 L: driver=../../../../../bus/usb/drivers/usb A: idProduct=0050 diff --git a/tests/vfs301/device b/tests/vfs301/device index 635f7951..26d3b57e 100644 --- a/tests/vfs301/device +++ b/tests/vfs301/device @@ -37,11 +37,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0c90 A: bmAttributes=a0 -A: busnum=2 +A: busnum=2\n A: configuration= H: descriptors=12011001FF10FF088A130500900C0000000109022700010100A0320904000003FF000000070501024000000705810240000007058202400000 A: dev=189:132 -A: devnum=5 +A: devnum=5\n A: devpath=1.3 L: driver=../../../../../../bus/usb/drivers/usb A: idProduct=0005 @@ -120,11 +120,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0000 A: bmAttributes=e0 -A: busnum=2 +A: busnum=2\n A: configuration= H: descriptors=12010002090001408780200000000000000109021900010100E0000904000001090000000705810302000C A: dev=189:129 -A: devnum=2 +A: devnum=2\n A: devpath=1 L: driver=../../../../../bus/usb/drivers/usb A: idProduct=0020 @@ -204,11 +204,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0504 A: bmAttributes=e0 -A: busnum=2 +A: busnum=2\n A: configuration= H: descriptors=12010002090000406B1D020004050302010109021900010100E0000904000001090000000705810304000C A: dev=189:128 -A: devnum=1 +A: devnum=1\n A: devpath=0 L: driver=../../../../bus/usb/drivers/usb A: idProduct=0002 diff --git a/tests/vfs5011/device b/tests/vfs5011/device index 4c75e596..e39a74fa 100644 --- a/tests/vfs5011/device +++ b/tests/vfs5011/device @@ -35,11 +35,11 @@ A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0078 A: bmAttributes=a0 -A: busnum=2 +A: busnum=2\n A: configuration= H: descriptors=12011001FF11FF088A13170078000000010109022E00010100A0320904000004FF00000007050102400000070581024000000705820240000007058303080004 A: dev=189:144 -A: devnum=17 +A: devnum=17\n A: devpath=6 L: driver=../../../../../bus/usb/drivers/usb A: idProduct=0017 diff --git a/tests/virtual-device.py b/tests/virtual-device.py new file mode 100644 index 00000000..b9889e09 --- /dev/null +++ b/tests/virtual-device.py @@ -0,0 +1,1112 @@ +#!/usr/bin/env python3 + +import sys +try: + import gi + import re + import os + + from gi.repository import GLib, Gio + + import unittest + import socket + import struct + import subprocess + import shutil + import traceback + import glob + import tempfile +except Exception as e: + print("Missing dependencies: %s" % str(e)) + sys.exit(77) + +FPrint = None + +# Re-run the test with the passed wrapper if set +wrapper = os.getenv('LIBFPRINT_TEST_WRAPPER') +if wrapper: + wrap_cmd = wrapper.split(' ') + [sys.executable, os.path.abspath(__file__)] + \ + sys.argv[1:] + os.unsetenv('LIBFPRINT_TEST_WRAPPER') + sys.exit(subprocess.check_call(wrap_cmd)) + +ctx = GLib.main_context_default() + + +class Connection: + + def __init__(self, addr): + self.addr = addr + + def __enter__(self): + self.con = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.con.connect(self.addr) + return self.con + + def __exit__(self, exc_type, exc_val, exc_tb): + self.con.close() + del self.con + + +class GLibErrorMessage: + def __init__(self, component, level, expected_message): + self.level = level + self.component = component + self.expected_message = expected_message + + def __enter__(self): + GLib.test_expect_message(self.component, self.level, self.expected_message) + + def __exit__(self, exc_type, exc_val, exc_tb): + (filename, line, func_name, text) = traceback.extract_stack()[-2] + GLib.test_assert_expected_messages_internal(self.component, + filename, line, func_name) + +class VirtualDeviceBase(unittest.TestCase): + + @classmethod + def setUpClass(cls): + unittest.TestCase.setUpClass() + cls.tmpdir = tempfile.mkdtemp(prefix='libfprint-') + + driver_name = cls.driver_name if hasattr(cls, 'driver_name') else None + if not driver_name: + driver_name = re.compile(r'(? 0 + + def enroll_in_progress(): + if self._enroll_stage < 0 and not self._enrolled: + return True + + if isinstance(self._enrolled, Exception): + raise(self._enrolled) + + nonlocal retries + self.assertLessEqual(self._enroll_stage, self.dev.get_nr_enroll_stages()) + if should_retry and retries > retry_scan: + self.assertEqual(self._enroll_stage, retries - 1) + else: + self.assertEqual(self._enroll_stage, retries) + + if retries == retry_scan + 1: + self.assertIsNotNone(self._enroll_progress_error) + self.assertEqual(self._enroll_progress_error.code, FPrint.DeviceRetry.TOO_SHORT) + else: + self.assertIsNone(self._enroll_progress_error) + + if self._enroll_stage < self.dev.get_nr_enroll_stages(): + self._enroll_stage = -1 + self.assertIsNone(self._enrolled) + self.assertEqual(self.dev.get_finger_status(), + FPrint.FingerStatusFlags.NEEDED) + if retry_scan == retries: + GLib.idle_add(self.send_auto, FPrint.DeviceRetry.TOO_SHORT) + else: + GLib.idle_add(self.send_command, 'SCAN', nick) + retries += 1 + + return not self._enrolled + + self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NONE) + + self.send_command('SCAN', nick) + + template = FPrint.Print.new(self.dev) + template.set_finger(finger) + template.set_username(username) + + self.dev.enroll(template, callback=done_cb, progress_cb=progress_cb) + while enroll_in_progress(): + ctx.iteration(False) + + self.assertEqual(self._enroll_stage, retries if not should_retry else retries - 1) + self.assertEqual(self._enroll_stage, self.dev.get_nr_enroll_stages()) + self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NONE) + + self.assertEqual(self._enrolled.get_device_stored(), + self.dev.has_storage()) + self.assertEqual(self._enrolled.props.driver, self.dev.get_driver()) + self.assertEqual(self._enrolled.props.device_id, self.dev.get_device_id()) + self.assertEqual(self._enrolled.props.device_stored, self.dev.has_storage()) + self.assertEqual(self._enrolled.props.fpi_data.unpack(), nick) + self.assertIsNone(self._enrolled.props.image) + + return self._enrolled + + def start_verify(self, p, identify=False): + self._verify_match = None + self._verify_fp = None + self._verify_error = None + self._verify_report_match = None + self._verify_report_print = None + self._verify_completed = False + self._verify_reported = False + self._cancellable = Gio.Cancellable() + + if identify: + self.assertTrue(self.dev.supports_identify()) + + def match_cb(dev, match, pnt, data, error): + self._verify_reported = True + self._verify_report_match = match + self._verify_report_print = pnt + self._verify_report_error = error + + def verify_cb(dev, res): + try: + self._verify_match, self._verify_fp = ( + dev.identify_finish(res) if identify else dev.verify_finish(res)) + except gi.repository.GLib.Error as e: + self._verify_error = e + + self._verify_completed = True + + if identify: + self.dev.identify(p if isinstance(p, list) else [p], + cancellable=self._cancellable, match_cb=match_cb, callback=verify_cb) + else: + self.dev.verify(p, cancellable=self._cancellable, match_cb=match_cb, + callback=verify_cb) + + def cancel_verify(self): + self._cancellable.cancel() + while not self._verify_completed: + ctx.iteration(True) + + self.assertIsNone(self._verify_match) + self.assertIsNotNone(self._verify_error) + self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NONE) + + def complete_verify(self): + while not self._verify_completed: + ctx.iteration(True) + + if self._verify_error is not None: + raise self._verify_error + + def check_verify(self, p, scan_nick, match, identify=False): + if isinstance(scan_nick, str): + self.send_command('SCAN', scan_nick) + elif scan_nick is not None: + self.send_auto(scan_nick) + + self.start_verify(p, identify) + self.complete_verify() + + self.assertTrue(self._verify_reported) + + if not match: + self.assertIsNone(self._verify_report_match) + + if identify: + if match: + self.assertIsNotNone(self._verify_report_match) + self.assertIsNotNone(self._verify_match) + else: + if self._verify_fp: + self.assertEqual(self._verify_fp.equal(p), match) + if match: + self.assertTrue( + self._verify_fp.equal(self._verify_report_match)) + else: + self.assertFalse(match) + + if isinstance(scan_nick, str): + self.assertEqual(self._verify_fp.props.fpi_data.get_string(), scan_nick) + + +class VirtualDevice(VirtualDeviceBase): + + def test_device_properties(self): + self.assertEqual(self.dev.get_driver(), 'virtual_device') + self.assertEqual(self.dev.get_device_id(), '0') + self.assertEqual(self.dev.get_name(), 'Virtual device for debugging') + self.assertTrue(self.dev.is_open()) + self.assertEqual(self.dev.get_scan_type(), FPrint.ScanType.SWIPE) + self.assertEqual(self.dev.get_nr_enroll_stages(), 5) + self.assertFalse(self.dev.supports_identify()) + self.assertFalse(self.dev.supports_capture()) + self.assertFalse(self.dev.has_storage()) + self.assertEqual(self.dev.props.driver, self.dev.get_driver()) + self.assertEqual(self.dev.props.device_id, self.dev.get_device_id()) + self.assertEqual(self.dev.props.name, self.dev.get_name()) + self.assertEqual(self.dev.props.scan_type, self.dev.get_scan_type()) + self.assertEqual(self.dev.props.nr_enroll_stages, self.dev.get_nr_enroll_stages()) + self.assertEqual(self.dev.props.open, self.dev.is_open()) + + def test_open_error(self): + self._close_on_teardown = False + self.send_command('IGNORED_COMMAND') # This will be consumed by close + self.send_error(FPrint.DeviceError.PROTO) # This will be consumed by open + + with GLibErrorMessage('libfprint-virtual_device', + GLib.LogLevelFlags.LEVEL_WARNING, 'Could not process command: *'): + self.dev.close_sync() + + with self.assertRaises(GLib.Error) as error: + self.dev.open_sync() + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.PROTO)) + + def test_open_error_with_keep_alive(self): + self._close_on_teardown = False + self.set_keep_alive(True) + self.dev.close_sync() + + self.send_error(FPrint.DeviceError.PROTO) + with self.assertRaises(GLib.Error) as error: + self.dev.open_sync() + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.PROTO)) + + def test_delayed_open(self): + self.send_command('IGNORED_COMMAND') # This will be consumed by close + self.send_sleep(500) # This will be consumed by open + + with GLibErrorMessage('libfprint-virtual_device', + GLib.LogLevelFlags.LEVEL_WARNING, 'Could not process command: *'): + self.dev.close_sync() + + opened = False + def on_opened(dev, res): + nonlocal opened + dev.open_finish(res) + opened = True + + self.dev.open(callback=on_opened) + + self.wait_timeout(10) + self.assertFalse(self.dev.is_open()) + + self.wait_timeout(10) + self.assertFalse(self.dev.is_open()) + + while not opened: + ctx.iteration(True) + + def test_delayed_open_with_keep_alive(self): + self.set_keep_alive(True) + self.dev.close_sync() + + opened = False + def on_opened(dev, res): + nonlocal opened + dev.open_finish(res) + opened = True + + self.send_sleep(500) + self.dev.open(callback=on_opened) + + self.wait_timeout(10) + self.assertFalse(self.dev.is_open()) + + self.wait_timeout(10) + self.assertFalse(self.dev.is_open()) + + while not opened: + ctx.iteration(True) + + def test_enroll(self): + matching = self.enroll_print('testprint', FPrint.Finger.LEFT_LITTLE) + self.assertEqual(matching.get_username(), 'testuser') + self.assertEqual(matching.get_finger(), FPrint.Finger.LEFT_LITTLE) + + def test_enroll_with_retry(self): + matching = self.enroll_print('testprint', FPrint.Finger.LEFT_LITTLE, retry_scan=2) + self.assertEqual(matching.get_username(), 'testuser') + self.assertEqual(matching.get_finger(), FPrint.Finger.LEFT_LITTLE) + + def test_enroll_verify_match(self): + matching = self.enroll_print('testprint', FPrint.Finger.LEFT_THUMB) + + self.check_verify(matching, 'testprint', match=True, + identify=self.dev.supports_identify()) + + def test_enroll_verify_no_match(self): + matching = self.enroll_print('testprint', FPrint.Finger.LEFT_RING) + + if self.dev.has_storage(): + with self.assertRaises(GLib.Error) as error: + self.check_verify(matching, 'not-testprint', match=False, + identify=self.dev.supports_identify()) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.DATA_NOT_FOUND)) + else: + self.check_verify(matching, 'not-testprint', match=False, + identify=self.dev.supports_identify()) + + def test_enroll_verify_error(self): + matching = self.enroll_print('testprint', FPrint.Finger.LEFT_RING) + + with self.assertRaises(GLib.Error) as error: + self.check_verify(matching, FPrint.DeviceError.GENERAL, match=False, + identify=self.dev.supports_identify()) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.GENERAL)) + + def test_enroll_verify_retry(self): + with self.assertRaises(GLib.GError) as error: + self.check_verify(FPrint.Print.new(self.dev), + FPrint.DeviceRetry.TOO_SHORT, match=False) + self.assertTrue(error.exception.matches(FPrint.DeviceRetry.quark(), + FPrint.DeviceRetry.TOO_SHORT)) + + def test_enroll_script_interactive(self): + enrolled = None + def done_cb(dev, res): + nonlocal enrolled + try: + enrolled = dev.enroll_finish(res) + except Exception as e: + enrolled = e + + enroll_stage = 0 + enroll_progress_error = None + def progress_cb(dev, stage, pnt, data, error): + nonlocal enroll_stage, enroll_progress_error + enroll_stage = stage + enroll_progress_error = error + + def wait_for_next_stage(expected): + nonlocal enroll_stage, enroll_progress_error + enroll_progress_error = None + next_stage = enroll_stage + 1 + while enroll_stage < next_stage and not enroll_progress_error: + ctx.iteration(True) + + if isinstance(expected, FPrint.DeviceRetry): + self.assertEqual(enroll_stage, next_stage - 1) + self.assertEqual(enroll_progress_error.code, int(expected)) + else: + self.assertEqual(enroll_stage, expected) + self.assertIsNone(enroll_progress_error) + self.assertIsNone(enrolled) + + self.send_sleep(50) + self.send_command('SCAN', 'print-id') + self.send_command('SCAN', 'print-id') + self.send_auto(FPrint.DeviceRetry.TOO_SHORT) + self.send_command('SCAN', 'print-id') + self.send_sleep(50) + self.send_command('SCAN', 'print-id') + self.send_auto(FPrint.DeviceRetry.CENTER_FINGER) + self.send_command('SCAN', 'another-id') + self.send_command('SCAN', 'print-id') + + self.dev.enroll(FPrint.Print.new(self.dev), callback=done_cb, + progress_cb=progress_cb) + + wait_for_next_stage(1) + wait_for_next_stage(2) + wait_for_next_stage(FPrint.DeviceRetry.TOO_SHORT) + wait_for_next_stage(3) + wait_for_next_stage(4) + wait_for_next_stage(FPrint.DeviceRetry.CENTER_FINGER) + wait_for_next_stage(FPrint.DeviceRetry.GENERAL) + wait_for_next_stage(5) + + while not enrolled: + ctx.iteration(True) + + self.assertEqual(enrolled.get_driver(), self.dev.get_driver()) + self.assertEqual(enrolled.props.fpi_data.unpack(), 'print-id') + + def test_enroll_script(self): + self.send_command('SET_ENROLL_STAGES', 8) + self.send_command('SCAN', 'print-id') + self.send_command('SCAN', 'print-id') + self.send_auto(FPrint.DeviceRetry.TOO_SHORT) + self.send_command('SCAN', 'print-id') + self.send_auto(FPrint.DeviceRetry.REMOVE_FINGER) + self.send_command('SCAN', 'print-id') + self.send_auto(FPrint.DeviceRetry.CENTER_FINGER) + self.send_command('SCAN', 'print-id') + self.send_sleep(10) + self.send_sleep(20) + self.send_auto(FPrint.DeviceRetry.GENERAL) + self.send_auto(FPrint.DeviceRetry.REMOVE_FINGER) + self.send_command('SCAN', 'print-id') + self.send_command('SCAN', 'another-id') + self.send_command('SCAN', 'print-id') + self.send_command('SCAN', 'print-id') + + enrolled = self.dev.enroll_sync(FPrint.Print.new(self.dev)) + self.assertEqual(enrolled.get_driver(), self.dev.get_driver()) + self.assertEqual(enrolled.props.fpi_data.unpack(), 'print-id') + + return enrolled + + def test_enroll_verify_script(self): + enrolled = self.test_enroll_script() + self.send_auto(FPrint.DeviceRetry.CENTER_FINGER) + with self.assertRaises(GLib.GError) as error: + self.dev.verify_sync(enrolled) + self.assertTrue(error.exception.matches(FPrint.DeviceRetry.quark(), + FPrint.DeviceRetry.CENTER_FINGER)) + + self.send_sleep(50) + self.send_auto(FPrint.DeviceRetry.TOO_SHORT) + with self.assertRaises(GLib.GError) as error: + self.dev.verify_sync(enrolled) + self.assertTrue(error.exception.matches(FPrint.DeviceRetry.quark(), + FPrint.DeviceRetry.TOO_SHORT)) + + self.send_command('SCAN', 'another-id') + if self.dev.has_storage(): + with self.assertRaises(GLib.GError) as error: + self.dev.verify_sync(enrolled) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.DATA_NOT_FOUND)) + else: + verify_match, verify_fp = self.dev.verify_sync(enrolled) + self.assertFalse(verify_match) + self.assertFalse(verify_fp.equal(enrolled)) + + self.send_auto(enrolled) + verify_match, verify_fp = self.dev.verify_sync(enrolled) + self.assertTrue(verify_match) + self.assertTrue(verify_fp.equal(enrolled)) + + def test_finger_status(self): + self.start_verify(FPrint.Print.new(self.dev), + identify=self.dev.supports_identify()) + + self.assertEqual(self.dev.get_finger_status(), + FPrint.FingerStatusFlags.NEEDED) + + self.send_finger_report(True) + self.assertEqual(self.dev.get_finger_status(), + FPrint.FingerStatusFlags.NEEDED | FPrint.FingerStatusFlags.PRESENT) + + self.send_finger_report(False) + self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NEEDED) + + self.cancel_verify() + + def test_finger_status_after_sleep(self): + self.send_sleep(10) + self.start_verify(FPrint.Print.new(self.dev), + identify=self.dev.supports_identify()) + + self.assertEqual(self.dev.get_finger_status(), + FPrint.FingerStatusFlags.NONE) + + while self.dev.get_finger_status() != FPrint.FingerStatusFlags.NEEDED: + ctx.iteration(True) + + self.assertEqual(self.dev.get_finger_status(), + FPrint.FingerStatusFlags.NEEDED) + + self.send_finger_report(True) + self.assertEqual(self.dev.get_finger_status(), + FPrint.FingerStatusFlags.NEEDED | FPrint.FingerStatusFlags.PRESENT) + + self.send_finger_report(False) + self.assertEqual(self.dev.get_finger_status(), + FPrint.FingerStatusFlags.NEEDED) + + self.cancel_verify() + + def test_change_enroll_stages(self): + notified_spec = None + def on_stage_changed(dev, spec): + nonlocal notified_spec + notified_spec = spec + + self.dev.connect('notify::nr-enroll-stages', on_stage_changed) + + notified_spec = None + self.send_command('SET_ENROLL_STAGES', 20) + self.assertEqual(self.dev.get_nr_enroll_stages(), 20) + self.assertEqual(notified_spec.name, 'nr-enroll-stages') + + notified_spec = None + self.send_command('SET_ENROLL_STAGES', 1) + self.assertEqual(self.dev.get_nr_enroll_stages(), 1) + self.assertEqual(notified_spec.name, 'nr-enroll-stages') + + with GLibErrorMessage('libfprint-device', + GLib.LogLevelFlags.LEVEL_CRITICAL, '*enroll_stages > 0*'): + notified_spec = None + self.send_command('SET_ENROLL_STAGES', 0) + self.assertEqual(self.dev.get_nr_enroll_stages(), 1) + self.assertIsNone(notified_spec) + + def test_quick_enroll(self): + self.send_command('SET_ENROLL_STAGES', 1) + self.assertEqual(self.dev.get_nr_enroll_stages(), 1) + matching = self.enroll_print('testprint', FPrint.Finger.LEFT_LITTLE) + self.assertEqual(matching.get_username(), 'testuser') + self.assertEqual(matching.get_finger(), FPrint.Finger.LEFT_LITTLE) + + def test_change_scan_type(self): + notified_spec = None + def on_scan_type_changed(dev, spec): + nonlocal notified_spec + notified_spec = spec + + self.dev.connect('notify::scan-type', on_scan_type_changed) + + for scan_type in [FPrint.ScanType.PRESS, FPrint.ScanType.SWIPE]: + notified_spec = None + self.send_auto(scan_type) + self.assertEqual(self.dev.get_scan_type(), scan_type) + self.assertEqual(notified_spec.name, 'scan-type') + + with GLibErrorMessage('libfprint-virtual_device', + GLib.LogLevelFlags.LEVEL_WARNING, '*Scan type*not found'): + notified_spec = None + self.send_command('SET_SCAN_TYPE', 'eye-contact') + self.assertEqual(self.dev.get_scan_type(), FPrint.ScanType.SWIPE) + self.assertIsNone(notified_spec) + + def test_device_unplug(self): + self._close_on_teardown = False + notified_spec = None + def on_removed_notify(dev, spec): + nonlocal notified_spec + notified_spec = spec + + removed = False + def on_removed(dev): + nonlocal removed + removed = True + + self.assertFalse(self.dev.props.removed) + + self.dev.connect('notify::removed', on_removed_notify) + self.dev.connect('removed', on_removed) + self.send_command('UNPLUG') + self.assertEqual(notified_spec.name, 'removed') + self.assertTrue(self.dev.props.removed) + self.assertTrue(removed) + + with self.assertRaises(GLib.GError) as error: + self.dev.close_sync() + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.REMOVED)) + + def test_device_unplug_during_verify(self): + self._close_on_teardown = False + + notified_spec = None + def on_removed_notify(dev, spec): + nonlocal notified_spec + notified_spec = spec + + removed = False + def on_removed(dev): + nonlocal removed + removed = True + + self.assertFalse(self.dev.props.removed) + self.dev.connect('notify::removed', on_removed_notify) + self.dev.connect('removed', on_removed) + + self.start_verify(FPrint.Print.new(self.dev), + identify=self.dev.supports_identify()) + + self.send_command('UNPLUG') + self.assertEqual(notified_spec.name, 'removed') + self.assertTrue(self.dev.props.removed) + self.assertFalse(removed) + + with self.assertRaises(GLib.GError) as error: + self.complete_verify() + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.REMOVED)) + + self.assertTrue(removed) + + with self.assertRaises(GLib.GError) as error: + self.dev.close_sync() + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.REMOVED)) + + def test_device_sleep(self): + self.send_sleep(1500) + + self.start_verify(FPrint.Print.new(self.dev), + identify=self.dev.supports_identify()) + + self.wait_timeout(300) + self.assertFalse(self._verify_completed) + + self._cancellable.cancel() + self.wait_timeout(200) + + self.assertTrue(self._verify_completed) + self.cancel_verify() + + def test_device_sleep_on_cancellation(self): + self.send_command('SET_CANCELLATION_ENABLED', int(False)) + self.send_sleep(1500) + self.send_command('SCAN', 'foo-print') + + self.start_verify(FPrint.Print.new(self.dev), + identify=self.dev.supports_identify()) + self.wait_timeout(300) + + self.assertFalse(self._verify_completed) + + self._cancellable.cancel() + self.wait_timeout(300) + + self.assertFalse(self._verify_completed) + self.cancel_verify() + + # Since we don't really cancel here, next command will be passed to release + self._close_on_teardown = False + with GLibErrorMessage('libfprint-virtual_device', + GLib.LogLevelFlags.LEVEL_WARNING, 'Could not process command: SCAN *'): + self.dev.close_sync() + + def test_device_sleep_before_completing_verify(self): + enrolled = self.enroll_print('foo-print', FPrint.Finger.LEFT_RING) + + self.send_sleep(100) + self.start_verify(enrolled, identify=self.dev.supports_identify()) + self.send_command('SCAN', 'bar-print') + self.send_sleep(800) + + while not self._verify_reported: + ctx.iteration(False) + + self.assertFalse(self._verify_completed) + self.wait_timeout(10) + self.assertFalse(self._verify_completed) + + if self.dev.has_storage(): + with self.assertRaises(GLib.Error) as error: + self.complete_verify() + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.DATA_NOT_FOUND)) + else: + self.complete_verify() + self.assertTrue(self._verify_reported) + + def test_close_error(self): + self._close_on_teardown = False + close_res = None + + def on_closed(dev, res): + nonlocal close_res + try: + close_res = dev.close_finish(res) + except GLib.Error as e: + close_res = e + + self.send_sleep(100) + self.send_error(FPrint.DeviceError.BUSY) + self.dev.close(callback=on_closed) + self.wait_timeout(2) + self.assertIsNone(close_res) + + while not close_res: + ctx.iteration(True) + + self.assertEqual(close_res.code, int(FPrint.DeviceError.BUSY)) + + +class VirtualDeviceClosed(VirtualDeviceBase): + + driver_name = 'virtual_device' + + def setUp(self): + super().setUp() + self._close_on_teardown = False + self.dev.close_sync() + self.assertFalse(self.dev.is_open()) + + def test_close(self): + with self.assertRaises(GLib.Error) as error: + self.dev.close_sync() + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.NOT_OPEN)) + + def test_enroll(self): + with self.assertRaises(GLib.Error) as error: + self.dev.enroll_sync(FPrint.Print.new(self.dev)) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.NOT_OPEN)) + + def test_verify(self): + with self.assertRaises(GLib.Error) as error: + self.dev.verify_sync(FPrint.Print.new(self.dev)) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.NOT_OPEN)) + + def test_identify(self): + with self.assertRaises(GLib.Error) as error: + self.dev.identify_sync([FPrint.Print.new(self.dev)]) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.NOT_OPEN)) + + def test_capture(self): + with self.assertRaises(GLib.Error) as error: + self.dev.capture_sync(wait_for_finger=False) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.NOT_OPEN)) + + def test_delete_print(self): + with self.assertRaises(GLib.Error) as error: + self.dev.delete_print_sync(FPrint.Print.new(self.dev)) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.NOT_OPEN)) + + def test_list_prints(self): + with self.assertRaises(GLib.Error) as error: + self.dev.list_prints_sync() + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.NOT_OPEN)) + + +class VirtualDeviceBusyDeviceOperations(VirtualDeviceBase): + + driver_name = 'virtual_device' + + def setUp(self): + super().setUp() + self._close_on_teardown = False + self.send_sleep(200) + self.dev.close() + + def tearDown(self): + while self.dev.is_open(): + ctx.iteration(True) + super().tearDown() + + def test_open(self): + self.set_keep_alive(True) + + while self.dev.is_open(): + ctx.iteration(True) + + self.assertFalse(self.dev.is_open()) + self.send_sleep(100) + self.dev.open() + with self.assertRaises(GLib.Error) as error: + self.dev.open_sync() + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.BUSY)) + + self.assertFalse(self.dev.is_open()) + while not self.dev.is_open(): + ctx.iteration(True) + + self.dev.close_sync() + + def test_close(self): + with self.assertRaises(GLib.Error) as error: + self.dev.close_sync() + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.BUSY)) + + def test_enroll(self): + with self.assertRaises(GLib.Error) as error: + self.dev.enroll_sync(FPrint.Print.new(self.dev)) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.BUSY)) + + def test_verify(self): + with self.assertRaises(GLib.Error) as error: + self.dev.verify_sync(FPrint.Print.new(self.dev)) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.BUSY)) + + def test_identify(self): + with self.assertRaises(GLib.Error) as error: + self.dev.identify_sync([FPrint.Print.new(self.dev)]) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.BUSY)) + + def test_capture(self): + with self.assertRaises(GLib.Error) as error: + self.dev.capture_sync(wait_for_finger=False) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.BUSY)) + + def test_delete_print(self): + with self.assertRaises(GLib.Error) as error: + self.dev.delete_print_sync(FPrint.Print.new(self.dev)) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.BUSY)) + + def test_list_prints(self): + with self.assertRaises(GLib.Error) as error: + self.dev.list_prints_sync() + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.BUSY)) + + +class VirtualDeviceStorage(VirtualDevice): + + def tearDown(self): + self.cleanup_device_storage() + super().tearDown() + + def cleanup_device_storage(self): + if self.dev.is_open() and not self.dev.props.removed: + for print in self.dev.list_prints_sync(): + self.assertTrue(self.dev.delete_print_sync(print, None)) + + def test_device_properties(self): + self.assertEqual(self.dev.get_driver(), 'virtual_device_storage') + self.assertEqual(self.dev.get_device_id(), '0') + self.assertEqual(self.dev.get_name(), + 'Virtual device with storage and identification for debugging') + self.assertTrue(self.dev.is_open()) + self.assertEqual(self.dev.get_scan_type(), FPrint.ScanType.SWIPE) + self.assertEqual(self.dev.get_nr_enroll_stages(), 5) + self.assertTrue(self.dev.supports_identify()) + self.assertFalse(self.dev.supports_capture()) + self.assertTrue(self.dev.has_storage()) + + def test_duplicate_enroll(self): + self.enroll_print('testprint', FPrint.Finger.LEFT_LITTLE) + with self.assertRaises(GLib.Error) as error: + self.enroll_print('testprint', FPrint.Finger.LEFT_LITTLE) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.DATA_DUPLICATE)) + + def test_list_empty(self): + self.assertFalse(self.dev.list_prints_sync()) + + def test_list_populated(self): + self.send_command('INSERT', 'p1') + print2 = self.enroll_print('p2', FPrint.Finger.LEFT_LITTLE) + self.assertEqual({'p1', 'p2'}, {p.props.fpi_data.get_string() for p in self.dev.list_prints_sync()}) + + def test_list_delete(self): + p = self.enroll_print('testprint', FPrint.Finger.RIGHT_THUMB) + l = self.dev.list_prints_sync() + print(l[0]) + self.assertEqual(len(l), 1) + print('blub', p.props.fpi_data, type(l[0].props.fpi_data)) + assert p.equal(l[0]) + self.dev.delete_print_sync(p) + self.assertFalse(self.dev.list_prints_sync()) + + def test_delete_error(self): + deleted_res = None + def on_deleted(dev, res): + nonlocal deleted_res + try: + deleted_res = dev.delete_print_finish(res) + except GLib.Error as e: + deleted_res = e + + self.send_sleep(100) + self.send_error(FPrint.DeviceError.DATA_NOT_FOUND) + self.dev.delete_print(FPrint.Print.new(self.dev), callback=on_deleted) + self.wait_timeout(2) + self.assertIsNone(deleted_res) + + while not deleted_res: + ctx.iteration(True) + + self.assertEqual(deleted_res.code, int(FPrint.DeviceError.DATA_NOT_FOUND)) + + def test_list_error(self): + list_res = None + + def on_listed(dev, res): + nonlocal list_res + try: + list_res = dev.list_prints_finish(res) + except GLib.Error as e: + list_res = e + + self.send_sleep(100) + self.send_error(FPrint.DeviceError.BUSY) + self.dev.list_prints(callback=on_listed) + self.wait_timeout(2) + self.assertIsNone(list_res) + + while not list_res: + ctx.iteration(True) + + self.assertEqual(list_res.code, int(FPrint.DeviceError.BUSY)) + + def test_list_delete_missing(self): + p = self.enroll_print('testprint', FPrint.Finger.RIGHT_THUMB) + self.send_command('REMOVE', 'testprint') + + with self.assertRaises(GLib.Error) as error: + self.dev.delete_print_sync(p) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.DATA_NOT_FOUND)) + + def test_identify_match(self): + rt = self.enroll_print('right-thumb', FPrint.Finger.RIGHT_THUMB) + lt = self.enroll_print('left-thumb', FPrint.Finger.LEFT_THUMB) + + self.check_verify([rt, lt], 'right-thumb', identify=True, match=True) + self.check_verify([rt, lt], 'left-thumb', identify=True, match=True) + + def test_identify_no_match(self): + rt = self.enroll_print('right-thumb', FPrint.Finger.RIGHT_THUMB) + lt = self.enroll_print('left-thumb', FPrint.Finger.LEFT_THUMB) + + self.check_verify(lt, 'right-thumb', identify=True, match=False) + self.check_verify(rt, 'left-thumb', identify=True, match=False) + + def test_identify_retry(self): + with self.assertRaises(GLib.GError) as error: + self.check_verify(FPrint.Print.new(self.dev), + FPrint.DeviceRetry.TOO_SHORT, identify=True, match=False) + self.assertTrue(error.exception.matches(FPrint.DeviceRetry.quark(), + FPrint.DeviceRetry.TOO_SHORT)) + + def test_delete_multiple_times(self): + rt = self.enroll_print('right-thumb', FPrint.Finger.RIGHT_THUMB) + self.dev.delete_print_sync(rt) + + with self.assertRaises(GLib.Error) as error: + self.dev.delete_print_sync(rt) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.DATA_NOT_FOUND)) + + def test_verify_missing_print(self): + with self.assertRaises(GLib.Error) as error: + self.check_verify(FPrint.Print.new(self.dev), + 'not-existing-print', False, identify=False) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.DATA_NOT_FOUND)) + + def test_identify_missing_print(self): + with self.assertRaises(GLib.Error) as error: + self.check_verify(FPrint.Print.new(self.dev), + 'not-existing-print', False, identify=True) + self.assertTrue(error.exception.matches(FPrint.DeviceError.quark(), + FPrint.DeviceError.DATA_NOT_FOUND)) + + +if __name__ == '__main__': + try: + gi.require_version('FPrint', '2.0') + from gi.repository import FPrint + except Exception as e: + print("Missing dependencies: %s" % str(e)) + sys.exit(77) + + # avoid writing to stderr + unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2)) diff --git a/tests/virtual-image.py b/tests/virtual-image.py index ce1df509..7609bd65 100755 --- a/tests/virtual-image.py +++ b/tests/virtual-image.py @@ -223,6 +223,10 @@ class VirtualImage(unittest.TestCase): ctx.iteration(True) self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NONE) + self.assertEqual(self._enrolled.props.driver, self.dev.get_driver()) + self.assertEqual(self._enrolled.props.device_id, self.dev.get_device_id()) + self.assertEqual(self._enrolled.props.device_stored, self.dev.has_storage()) + self.assertIsNone(self._enrolled.get_image()) return self._enrolled @@ -244,6 +248,7 @@ class VirtualImage(unittest.TestCase): while self._verify_match is None: ctx.iteration(True) assert(self._verify_match) + self.assertIsNotNone(self._verify_fp.props.image) self._verify_match = None self._verify_fp = None