lib: Major rewrite of the libfprint core and API
This is a rewrite of the core based on GObject and Gio. This commit breaks the build in a lot of ways, but basic functionality will start working again with the next commits.
This commit is contained in:
parent
30a449841c
commit
689aff0232
53 changed files with 8358 additions and 6759 deletions
|
@ -60,21 +60,18 @@
|
||||||
<para>
|
<para>
|
||||||
In summary, libfprint represents fingerprints in several internal structures
|
In summary, libfprint represents fingerprints in several internal structures
|
||||||
and each representation will offer you a way of determining the
|
and each representation will offer you a way of determining the
|
||||||
<ulink url="#driver_id">driver ID</ulink> and <ulink url="#device-types">devtype</ulink> of the print in
|
<ulink url="#driver">driver</ulink> and <ulink url="#device-id">device ID</ulink> of the print in
|
||||||
question. Prints are only compatible if the driver ID <emphasis role="strong">and</emphasis> devtypes
|
question. Prints are only compatible if the driver ID <emphasis role="strong">and</emphasis> devtypes
|
||||||
match. libfprint does offer you some "is this print compatible?" helper
|
match. libfprint does offer you some "is this print compatible?" helper
|
||||||
functions, so you don't have to worry about these details too much.
|
functions, so you don't have to worry about these details too much.
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2 id="driver_id">
|
<refsect2 id="driver">
|
||||||
<title>Driver IDs</title>
|
<title>Driver</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Each driver is assigned a unique ID by the project maintainer. These
|
Each driver is assigned a unique string identifier by the project maintainer.
|
||||||
assignments are
|
|
||||||
<ulink url="https://gitlab.freedesktop.org/libfprint/libfprint/blob/master/libfprint/drivers/driver_ids.h">
|
|
||||||
documented in the sources</ulink> and will never change.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -89,22 +86,23 @@
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2 id="device-types">
|
<refsect2 id="device-id">
|
||||||
<title>Device types</title>
|
<title>Device ID</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Internally, the <ulink url="libfprint-Driver-operations.html#libfprint-Driver-operations.description">driver</ulink> behind a device assigns a 32-bit
|
Internally, the behind a device assigns a string identifier to the device
|
||||||
<emphasis>devtype</emphasis> identifier to the device. This cannot be used as a unique
|
This cannot be used as a unique ID for a specific device as many devices
|
||||||
ID for a specific device as many devices under the same range may share
|
under the same range may share the same devtype. The device ID may even
|
||||||
the same devtype. The devtype may even be 0 in all cases.
|
be the same string in all cases. It is guaranteed to have a non-zero length
|
||||||
|
and be a valid file name. It defaults to "0".
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The only reason you may be interested in retrieving the devtype for a
|
The only reason you may be interested in retrieving the device ID for a
|
||||||
device is for the purpose of checking if some print data is compatible
|
device is for the purpose of checking if some print data is compatible
|
||||||
with a device. libfprint uses the devtype as one way of checking that the
|
with a device. libfprint uses the device ID as one way of checking that the
|
||||||
print you are verifying is compatible with the device in question - the
|
print you are verifying is compatible with the device in question - the
|
||||||
devtypes must be equal. This effectively allows drivers to support more
|
device ID must be equal. This effectively allows drivers to support more
|
||||||
than one type of device where the data from each one is not compatible with
|
than one type of device where the data from each one is not compatible with
|
||||||
the other. Note that libfprint does provide you with helper functions to
|
the other. Note that libfprint does provide you with helper functions to
|
||||||
determine whether a print is compatible with a device, so under most
|
determine whether a print is compatible with a device, so under most
|
||||||
|
|
|
@ -13,12 +13,12 @@
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Usually the first thing you want to do is determine which fingerprint
|
Usually the first thing you want to do is determine which fingerprint
|
||||||
devices are present. This is done through <ulink url="libfprint-Device-discovery.html">device discovery</ulink>.
|
devices are present. This is done using the <ulink url="fp-context.html">FpContext</ulink> object.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Once you have found a device you would like to operate, you should open it.
|
Once you have found a device you would like to operate, you should open it.
|
||||||
Refer to <ulink url="libfprint-Devices-operations.html">device operations</ulink>. This section also details enrollment,
|
Refer to <ulink url="fp-context.html">device operations</ulink>. This section also details enrollment,
|
||||||
image capture, and verification.
|
image capture, and verification.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|
|
@ -25,39 +25,43 @@
|
||||||
|
|
||||||
<part>
|
<part>
|
||||||
<title>Library API Documentation</title>
|
<title>Library API Documentation</title>
|
||||||
<xi:include href="xml/events.xml"/>
|
<xi:include href="xml/fp-context.xml"/>
|
||||||
<xi:include href="xml/discovery.xml"/>
|
<xi:include href="xml/fp-device.xml"/>
|
||||||
|
<xi:include href="xml/fp-image-device.xml"/>
|
||||||
<xi:include href="xml/drv.xml"/>
|
<xi:include href="xml/fp-print.xml"/>
|
||||||
<xi:include href="xml/dev.xml"/>
|
<xi:include href="xml/fp-image.xml"/>
|
||||||
<xi:include href="xml/print_data.xml"/>
|
|
||||||
<xi:include href="xml/img.xml"/>
|
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
<part>
|
<part>
|
||||||
<title>Writing Drivers</title>
|
<title>Writing Drivers</title>
|
||||||
<chapter id="driver-helpers">
|
<chapter id="driver-dev">
|
||||||
<title>Logging, and async machinery</title>
|
<title>Device methods for drivers</title>
|
||||||
<xi:include href="xml/fpi-log.xml"/>
|
<xi:include href="xml/fpi-device.xml"/>
|
||||||
<xi:include href="xml/fpi-ssm.xml"/>
|
<xi:include href="xml/fpi-image-device.xml"/>
|
||||||
<xi:include href="xml/fpi-poll.xml"/>
|
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<chapter id="driver-dev">
|
<chapter id="driver-helpers">
|
||||||
<title>Device and driver structures</title>
|
<title>USB and State Machine helpers</title>
|
||||||
<xi:include href="xml/fpi-dev.xml"/>
|
<xi:include href="xml/fpi-usb-transfer.xml"/>
|
||||||
<xi:include href="xml/fpi-dev-img.xml"/>
|
<xi:include href="xml/fpi-ssm.xml"/>
|
||||||
<xi:include href="xml/fpi-core.xml"/>
|
<xi:include href="xml/fpi-log.xml"/>
|
||||||
<xi:include href="xml/fpi-core-img.xml"/>
|
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<chapter id="driver-img">
|
<chapter id="driver-img">
|
||||||
<title>Image manipulation</title>
|
<title>Image manipulation</title>
|
||||||
<xi:include href="xml/fpi-img.xml"/>
|
<xi:include href="xml/fpi-image.xml"/>
|
||||||
<xi:include href="xml/fpi-assembling.xml"/>
|
<xi:include href="xml/fpi-assembling.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<xi:include href="xml/fpi-usb.xml"/>
|
<chapter id="driver-print">
|
||||||
|
<title>Print handling</title>
|
||||||
|
<xi:include href="xml/fpi-print.xml"/>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="driver-misc">
|
||||||
|
<title>Listing drivers</title>
|
||||||
|
<xi:include href="xml/fpi-context.xml"/>
|
||||||
|
</chapter>
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
<index id="api-index">
|
<index id="api-index">
|
||||||
|
|
|
@ -1,125 +1,191 @@
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<INCLUDE>fprint.h</INCLUDE>
|
<FILE>drivers_api</FILE>
|
||||||
<FILE>events</FILE>
|
|
||||||
<TITLE>Initialisation and events handling</TITLE>
|
|
||||||
LIBFPRINT_DEPRECATED
|
|
||||||
fp_init
|
|
||||||
fp_exit
|
|
||||||
fp_pollfd
|
|
||||||
fp_handle_events_timeout
|
|
||||||
fp_handle_events
|
|
||||||
fp_get_next_timeout
|
|
||||||
fp_get_pollfds
|
|
||||||
fp_pollfd_added_cb
|
|
||||||
fp_pollfd_removed_cb
|
|
||||||
fp_set_pollfd_notifiers
|
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<INCLUDE>fprint.h</INCLUDE>
|
<FILE>fp-context</FILE>
|
||||||
<FILE>discovery</FILE>
|
<TITLE>FpContext</TITLE>
|
||||||
<TITLE>Device discovery</TITLE>
|
FP_TYPE_CONTEXT
|
||||||
fp_dscv_dev
|
FpContextClass
|
||||||
fp_discover_devs
|
fp_context_new
|
||||||
fp_dscv_devs_free
|
fp_context_enumerate
|
||||||
fp_dscv_dev_get_driver
|
fp_context_get_devices
|
||||||
fp_dscv_dev_get_devtype
|
FpContext
|
||||||
fp_dscv_dev_get_driver_id
|
|
||||||
fp_dscv_dev_supports_print_data
|
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<INCLUDE>fprint.h</INCLUDE>
|
<FILE>fp-device</FILE>
|
||||||
<FILE>drv</FILE>
|
FP_TYPE_DEVICE
|
||||||
fp_driver
|
FP_DEVICE_RETRY
|
||||||
fp_driver_get_name
|
FP_DEVICE_ERROR
|
||||||
fp_driver_get_full_name
|
FpDeviceType
|
||||||
fp_driver_get_driver_id
|
FpScanType
|
||||||
fp_driver_get_scan_type
|
FpDeviceRetry
|
||||||
fp_driver_supports_imaging
|
FpDeviceError
|
||||||
|
fp_device_retry_quark
|
||||||
|
fp_device_error_quark
|
||||||
|
FpEnrollProgress
|
||||||
|
fp_device_get_driver
|
||||||
|
fp_device_get_device_id
|
||||||
|
fp_device_get_name
|
||||||
|
fp_device_get_scan_type
|
||||||
|
fp_device_get_nr_enroll_stages
|
||||||
|
fp_device_has_storage
|
||||||
|
fp_device_supports_identify
|
||||||
|
fp_device_supports_capture
|
||||||
|
fp_device_open
|
||||||
|
fp_device_close
|
||||||
|
fp_device_enroll
|
||||||
|
fp_device_verify
|
||||||
|
fp_device_identify
|
||||||
|
fp_device_capture
|
||||||
|
fp_device_delete_print
|
||||||
|
fp_device_list_prints
|
||||||
|
fp_device_open_finish
|
||||||
|
fp_device_close_finish
|
||||||
|
fp_device_enroll_finish
|
||||||
|
fp_device_verify_finish
|
||||||
|
fp_device_identify_finish
|
||||||
|
fp_device_capture_finish
|
||||||
|
fp_device_delete_print_finish
|
||||||
|
fp_device_list_prints_finish
|
||||||
|
fp_device_open_sync
|
||||||
|
fp_device_close_sync
|
||||||
|
fp_device_enroll_sync
|
||||||
|
fp_device_verify_sync
|
||||||
|
fp_device_identify_sync
|
||||||
|
fp_device_capture_sync
|
||||||
|
fp_device_delete_print_sync
|
||||||
|
fp_device_list_prints_sync
|
||||||
|
FpDevice
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<INCLUDE>fprint.h</INCLUDE>
|
<FILE>fp-image</FILE>
|
||||||
<FILE>dev</FILE>
|
FP_TYPE_IMAGE
|
||||||
fp_dev
|
FpMinutia
|
||||||
fp_scan_type
|
fp_image_new
|
||||||
fp_capture_result
|
fp_image_get_width
|
||||||
fp_enroll_result
|
fp_image_get_height
|
||||||
fp_verify_result
|
fp_image_get_ppmm
|
||||||
|
fp_image_get_minutiae
|
||||||
fp_dev_get_driver
|
fp_image_detect_minutiae
|
||||||
fp_dev_get_nr_enroll_stages
|
fp_image_detect_minutiae_finish
|
||||||
fp_dev_get_devtype
|
fp_image_get_data
|
||||||
fp_dev_supports_print_data
|
fp_image_get_binarized
|
||||||
fp_dev_supports_imaging
|
|
||||||
fp_dev_supports_identification
|
|
||||||
fp_dev_get_img_width
|
|
||||||
fp_dev_get_img_height
|
|
||||||
|
|
||||||
fp_operation_stop_cb
|
|
||||||
fp_img_operation_cb
|
|
||||||
fp_dev_open_cb
|
|
||||||
fp_enroll_stage_cb
|
|
||||||
fp_identify_cb
|
|
||||||
|
|
||||||
fp_dev_open
|
|
||||||
fp_async_dev_open
|
|
||||||
|
|
||||||
fp_dev_close
|
|
||||||
fp_async_dev_close
|
|
||||||
|
|
||||||
fp_enroll_finger
|
|
||||||
fp_enroll_finger_img
|
|
||||||
fp_async_enroll_start
|
|
||||||
fp_async_enroll_stop
|
|
||||||
|
|
||||||
fp_verify_finger
|
|
||||||
fp_verify_finger_img
|
|
||||||
fp_async_verify_start
|
|
||||||
fp_async_verify_stop
|
|
||||||
|
|
||||||
fp_identify_finger
|
|
||||||
fp_identify_finger_img
|
|
||||||
fp_async_identify_start
|
|
||||||
fp_async_identify_stop
|
|
||||||
|
|
||||||
fp_dev_img_capture
|
|
||||||
fp_async_capture_start
|
|
||||||
fp_async_capture_stop
|
|
||||||
</SECTION>
|
|
||||||
|
|
||||||
<SECTION>
|
|
||||||
<INCLUDE>fprint.h</INCLUDE>
|
|
||||||
<FILE>print_data</FILE>
|
|
||||||
fp_finger
|
|
||||||
fp_print_data
|
|
||||||
fp_print_data_get_data
|
|
||||||
fp_print_data_from_data
|
|
||||||
fp_print_data_free
|
|
||||||
fp_print_data_get_driver_id
|
|
||||||
fp_print_data_get_devtype
|
|
||||||
</SECTION>
|
|
||||||
|
|
||||||
<SECTION>
|
|
||||||
<INCLUDE>fprint.h</INCLUDE>
|
|
||||||
<FILE>img</FILE>
|
|
||||||
fp_img
|
|
||||||
fp_minutia
|
|
||||||
fp_img_free
|
|
||||||
fp_img_get_height
|
|
||||||
fp_img_get_width
|
|
||||||
fp_img_get_data
|
|
||||||
fp_img_save_to_file
|
|
||||||
fp_img_standardize
|
|
||||||
fp_img_binarize
|
|
||||||
fp_img_get_minutiae
|
|
||||||
fp_minutia_get_coords
|
fp_minutia_get_coords
|
||||||
|
FpImage
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fp-image-device</FILE>
|
||||||
|
FP_TYPE_IMAGE_DEVICE
|
||||||
|
FpImageDevice
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fp-print</FILE>
|
||||||
|
FP_TYPE_PRINT
|
||||||
|
FpFinger
|
||||||
|
FpPrint
|
||||||
|
fp_print_new
|
||||||
|
fp_print_new_from_data
|
||||||
|
fp_print_to_data
|
||||||
|
fp_print_get_driver
|
||||||
|
fp_print_get_device_id
|
||||||
|
fp_print_get_device_stored
|
||||||
|
fp_print_get_image
|
||||||
|
fp_print_get_finger
|
||||||
|
fp_print_get_username
|
||||||
|
fp_print_get_description
|
||||||
|
fp_print_get_enroll_date
|
||||||
|
fp_print_set_finger
|
||||||
|
fp_print_set_username
|
||||||
|
fp_print_set_description
|
||||||
|
fp_print_set_enroll_date
|
||||||
|
fp_print_compatible
|
||||||
|
fp_print_equal
|
||||||
|
fp_print_serialize
|
||||||
|
fp_print_deserialize
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-assembling</FILE>
|
||||||
|
fpi_frame
|
||||||
|
fpi_frame_asmbl_ctx
|
||||||
|
fpi_do_movement_estimation
|
||||||
|
fpi_assemble_frames
|
||||||
|
fpi_line_asmbl_ctx
|
||||||
|
fpi_assemble_lines
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-context</FILE>
|
||||||
|
fpi_get_driver_types
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-device</FILE>
|
||||||
|
FpDeviceClass
|
||||||
|
FpTimeoutFunc
|
||||||
|
FpDeviceAction
|
||||||
|
FpIdEntry
|
||||||
|
fpi_device_get_usb_device
|
||||||
|
fpi_device_get_virtual_env
|
||||||
|
fpi_device_get_current_action
|
||||||
|
fpi_device_retry_new
|
||||||
|
fpi_device_error_new
|
||||||
|
fpi_device_retry_new_msg
|
||||||
|
fpi_device_error_new_msg
|
||||||
|
fpi_device_get_driver_data
|
||||||
|
fpi_device_get_enroll_data
|
||||||
|
fpi_device_get_capture_data
|
||||||
|
fpi_device_get_verify_data
|
||||||
|
fpi_device_get_identify_data
|
||||||
|
fpi_device_get_delete_data
|
||||||
|
fpi_device_get_cancellable
|
||||||
|
fpi_device_action_is_cancelled
|
||||||
|
fpi_device_add_timeout
|
||||||
|
fpi_device_set_nr_enroll_stages
|
||||||
|
fpi_device_set_scan_type
|
||||||
|
fpi_device_action_error
|
||||||
|
fpi_device_probe_complete
|
||||||
|
fpi_device_open_complete
|
||||||
|
fpi_device_close_complete
|
||||||
|
fpi_device_enroll_complete
|
||||||
|
fpi_device_verify_complete
|
||||||
|
fpi_device_identify_complete
|
||||||
|
fpi_device_capture_complete
|
||||||
|
fpi_device_delete_complete
|
||||||
|
fpi_device_enroll_progress
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-image</FILE>
|
||||||
|
FpiImageFlags
|
||||||
|
FpImage
|
||||||
|
fpi_std_sq_dev
|
||||||
|
fpi_mean_sq_diff_norm
|
||||||
|
fpi_image_resize
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-image-device</FILE>
|
||||||
|
<TITLE>FpImageDevice</TITLE>
|
||||||
|
FpImageDeviceState
|
||||||
|
FpImageDeviceClass
|
||||||
|
fpi_image_device_session_error
|
||||||
|
fpi_image_device_open_complete
|
||||||
|
fpi_image_device_close_complete
|
||||||
|
fpi_image_device_activate_complete
|
||||||
|
fpi_image_device_deactivate_complete
|
||||||
|
fpi_image_device_report_finger_status
|
||||||
|
fpi_image_device_image_captured
|
||||||
|
fpi_image_device_retry_scan
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<INCLUDE>fpi-log.h</INCLUDE>
|
|
||||||
<FILE>fpi-log</FILE>
|
<FILE>fpi-log</FILE>
|
||||||
fp_dbg
|
fp_dbg
|
||||||
fp_info
|
fp_info
|
||||||
|
@ -130,121 +196,57 @@ BUG
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<INCLUDE>fpi-ssm.h</INCLUDE>
|
<FILE>fpi-print</FILE>
|
||||||
<FILE>fpi-ssm</FILE>
|
FpPrintType
|
||||||
fpi_ssm
|
FpiMatchResult
|
||||||
ssm_completed_fn
|
fpi_print_add_print
|
||||||
ssm_handler_fn
|
fpi_print_set_type
|
||||||
|
fpi_print_set_device_stored
|
||||||
|
fpi_print_add_from_image
|
||||||
|
fpi_print_bz3_match
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-ssm</FILE>
|
||||||
|
FpiSsmCompletedCallback
|
||||||
|
FpiSsmHandlerCallback
|
||||||
fpi_ssm_new
|
fpi_ssm_new
|
||||||
fpi_ssm_free
|
fpi_ssm_free
|
||||||
fpi_ssm_start
|
fpi_ssm_start
|
||||||
fpi_ssm_start_subsm
|
fpi_ssm_start_subsm
|
||||||
|
|
||||||
fpi_ssm_next_state
|
fpi_ssm_next_state
|
||||||
fpi_ssm_next_state_timeout_cb
|
|
||||||
fpi_ssm_jump_to_state
|
fpi_ssm_jump_to_state
|
||||||
fpi_ssm_mark_completed
|
fpi_ssm_mark_completed
|
||||||
fpi_ssm_mark_failed
|
fpi_ssm_mark_failed
|
||||||
fpi_ssm_get_user_data
|
fpi_ssm_get_user_data
|
||||||
fpi_ssm_get_error
|
fpi_ssm_get_error
|
||||||
|
fpi_ssm_dup_error
|
||||||
fpi_ssm_get_cur_state
|
fpi_ssm_get_cur_state
|
||||||
|
fpi_ssm_next_state_timeout_cb
|
||||||
|
fpi_ssm_usb_transfer_cb
|
||||||
|
FpiSsm
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<INCLUDE>fpi-poll.h</INCLUDE>
|
<FILE>fpi-usb-transfer</FILE>
|
||||||
<FILE>fpi-poll</FILE>
|
FPI_USB_ENDPOINT_IN
|
||||||
fpi_timeout
|
FPI_USB_ENDPOINT_OUT
|
||||||
fpi_timeout_fn
|
FpiUsbTransferCallback
|
||||||
fpi_timeout_add
|
FpiTransferType
|
||||||
fpi_timeout_set_name
|
FpiUsbTransfer
|
||||||
fpi_timeout_cancel
|
fpi_usb_transfer_new
|
||||||
|
fpi_usb_transfer_ref
|
||||||
|
fpi_usb_transfer_unref
|
||||||
|
fpi_usb_transfer_set_short_error
|
||||||
|
fpi_usb_transfer_fill_bulk
|
||||||
|
fpi_usb_transfer_fill_bulk_full
|
||||||
|
fpi_usb_transfer_fill_control
|
||||||
|
fpi_usb_transfer_fill_interrupt
|
||||||
|
fpi_usb_transfer_fill_interrupt_full
|
||||||
|
fpi_usb_transfer_submit
|
||||||
|
fpi_usb_transfer_submit_sync
|
||||||
|
<SUBSECTION Standard>
|
||||||
|
FPI_TYPE_USB_TRANSFER
|
||||||
|
fpi_usb_transfer_get_type
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
|
||||||
<INCLUDE>fpi-dev.h</INCLUDE>
|
|
||||||
<FILE>fpi-dev</FILE>
|
|
||||||
fp_img_dev
|
|
||||||
|
|
||||||
FP_DEV
|
|
||||||
FP_IMG_DEV
|
|
||||||
fp_dev_set_instance_data
|
|
||||||
FP_INSTANCE_DATA
|
|
||||||
|
|
||||||
fpi_dev_get_usb_dev
|
|
||||||
fpi_dev_get_verify_data
|
|
||||||
fpi_dev_set_nr_enroll_stages
|
|
||||||
</SECTION>
|
|
||||||
|
|
||||||
<SECTION>
|
|
||||||
<INCLUDE>fpi-dev-img.h</INCLUDE>
|
|
||||||
<FILE>fpi-dev-img</FILE>
|
|
||||||
fp_imgdev_action
|
|
||||||
fp_imgdev_state
|
|
||||||
fp_imgdev_enroll_state
|
|
||||||
|
|
||||||
fpi_imgdev_abort_scan
|
|
||||||
fpi_imgdev_activate_complete
|
|
||||||
fpi_imgdev_close_complete
|
|
||||||
fpi_imgdev_deactivate_complete
|
|
||||||
fpi_imgdev_get_action
|
|
||||||
fpi_imgdev_get_action_result
|
|
||||||
fpi_imgdev_get_action_state
|
|
||||||
fpi_imgdev_image_captured
|
|
||||||
fpi_imgdev_open_complete
|
|
||||||
fpi_imgdev_report_finger_status
|
|
||||||
fpi_imgdev_session_error
|
|
||||||
fpi_imgdev_set_action_result
|
|
||||||
</SECTION>
|
|
||||||
|
|
||||||
<SECTION>
|
|
||||||
<INCLUDE>fpi-core.h</INCLUDE>
|
|
||||||
<FILE>fpi-core</FILE>
|
|
||||||
usb_id
|
|
||||||
fp_driver_type
|
|
||||||
</SECTION>
|
|
||||||
|
|
||||||
<SECTION>
|
|
||||||
<INCLUDE>fpi-core.h</INCLUDE>
|
|
||||||
<FILE>fpi-core-img</FILE>
|
|
||||||
FpiImgDriverFlags
|
|
||||||
fp_img_driver
|
|
||||||
</SECTION>
|
|
||||||
|
|
||||||
<SECTION>
|
|
||||||
<INCLUDE>fpi-img.h</INCLUDE>
|
|
||||||
<FILE>fpi-img</FILE>
|
|
||||||
FpiImgFlags
|
|
||||||
|
|
||||||
fpi_img_new
|
|
||||||
fpi_img_new_for_imgdev
|
|
||||||
fpi_img_realloc
|
|
||||||
fpi_img_resize
|
|
||||||
|
|
||||||
fpi_std_sq_dev
|
|
||||||
fpi_mean_sq_diff_norm
|
|
||||||
</SECTION>
|
|
||||||
|
|
||||||
<SECTION>
|
|
||||||
<INCLUDE>fpi-assembling.h</INCLUDE>
|
|
||||||
<FILE>fpi-assembling</FILE>
|
|
||||||
fpi_frame
|
|
||||||
fpi_frame_asmbl_ctx
|
|
||||||
fpi_line_asmbl_ctx
|
|
||||||
|
|
||||||
fpi_do_movement_estimation
|
|
||||||
fpi_assemble_frames
|
|
||||||
fpi_assemble_lines
|
|
||||||
</SECTION>
|
|
||||||
|
|
||||||
<SECTION>
|
|
||||||
<INCLUDE>fpi-usb.h</INCLUDE>
|
|
||||||
<FILE>fpi-usb</FILE>
|
|
||||||
fpi_usb_transfer
|
|
||||||
|
|
||||||
fpi_usb_transfer_cb_fn
|
|
||||||
fpi_usb_alloc
|
|
||||||
fpi_usb_fill_bulk_transfer
|
|
||||||
fpi_usb_submit_transfer
|
|
||||||
fpi_usb_cancel_transfer
|
|
||||||
</SECTION>
|
|
||||||
|
|
118
doc/libfprint-sections.txt-new-manual
Normal file
118
doc/libfprint-sections.txt-new-manual
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>context</FILE>
|
||||||
|
<TITLE>Device discovery and hotplugging</TITLE>
|
||||||
|
FP_TYPE_CONTEXT
|
||||||
|
FpContext
|
||||||
|
fp_context_new
|
||||||
|
fp_context_enumerate
|
||||||
|
fp_context_get_devices
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>device</FILE>
|
||||||
|
<TITLE>Device</TITLE>
|
||||||
|
FP_TYPE_DEVICE
|
||||||
|
FpDevice
|
||||||
|
FpDeviceType
|
||||||
|
FpScanType
|
||||||
|
FpDeviceRetry
|
||||||
|
FpDeviceError
|
||||||
|
FP_DEVICE_ERROR
|
||||||
|
FP_DEVICE_RETRY
|
||||||
|
fp_device_get_driver
|
||||||
|
fp_device_get_device_id
|
||||||
|
fp_device_get_name
|
||||||
|
fp_device_get_scan_type
|
||||||
|
|
||||||
|
fp_device_open
|
||||||
|
fp_device_open_finish
|
||||||
|
fp_device_open_sync
|
||||||
|
|
||||||
|
fp_device_close
|
||||||
|
fp_device_close_finish
|
||||||
|
fp_device_close_sync
|
||||||
|
|
||||||
|
fp_device_enroll
|
||||||
|
fp_device_enroll_finish
|
||||||
|
fp_device_enroll_sync
|
||||||
|
|
||||||
|
fp_device_identify
|
||||||
|
fp_device_identify_finish
|
||||||
|
fp_device_identify_sync
|
||||||
|
|
||||||
|
fp_device_capture
|
||||||
|
fp_device_capture_finish
|
||||||
|
fp_device_capture_sync
|
||||||
|
|
||||||
|
fp_device_verify
|
||||||
|
fp_device_verify_finish
|
||||||
|
fp_device_verify_sync
|
||||||
|
|
||||||
|
_fp_device_get_cancellable
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>print</FILE>
|
||||||
|
<TITLE>Fingerprint handling</TITLE>
|
||||||
|
FpPrint
|
||||||
|
fp_print_new
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>image</FILE>
|
||||||
|
<TITLE>Image handling</TITLE>
|
||||||
|
FP_TYPE_IMAGE
|
||||||
|
FpImage
|
||||||
|
fp_image_new
|
||||||
|
fp_image_detect_minutiae
|
||||||
|
fp_image_detect_minutiae_finish
|
||||||
|
fp_image_device_new
|
||||||
|
fp_image_get_binarized
|
||||||
|
fp_image_get_data
|
||||||
|
fp_image_get_height
|
||||||
|
fp_image_get_minutiae
|
||||||
|
fp_image_get_ppmm
|
||||||
|
fp_image_get_width
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>internal-image-device</FILE>
|
||||||
|
<INCLUDE>drivers_api.h</INCLUDE>
|
||||||
|
<TITLE>Base class for image devices</TITLE>
|
||||||
|
FpImageDevice
|
||||||
|
FpImageDeviceClass
|
||||||
|
FpImageDeviceState
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>internal-usb-transfers</FILE>
|
||||||
|
<INCLUDE>drivers_api.h</INCLUDE>
|
||||||
|
<TITLE>USB Transfers</TITLE>
|
||||||
|
FpUsbTransfer
|
||||||
|
fp_usb_transfer_fill_bulk
|
||||||
|
fp_usb_transfer_fill_bulk_full
|
||||||
|
fp_usb_transfer_fill_control
|
||||||
|
fp_usb_transfer_fill_interrupt
|
||||||
|
fp_usb_transfer_fill_interrupt_full
|
||||||
|
fp_usb_transfer_get_type
|
||||||
|
fp_usb_transfer_new
|
||||||
|
fp_usb_transfer_ref
|
||||||
|
fp_usb_transfer_set_short_error
|
||||||
|
fp_usb_transfer_submit
|
||||||
|
fp_usb_transfer_submit_sync
|
||||||
|
fp_usb_transfer_unref
|
||||||
|
FpUsbTransferCallback
|
||||||
|
FP_USB_ENDPOINT_IN
|
||||||
|
FP_USB_ENDPOINT_OUT
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
|
|
@ -2,41 +2,13 @@ subdir('xml')
|
||||||
|
|
||||||
private_headers = [
|
private_headers = [
|
||||||
'config.h',
|
'config.h',
|
||||||
|
|
||||||
'aeslib.h',
|
|
||||||
'assembling.h',
|
|
||||||
'fp_internal.h',
|
|
||||||
'nbis-helpers.h',
|
'nbis-helpers.h',
|
||||||
'fpi-async.h',
|
'fprint.h',
|
||||||
'fpi-data.h',
|
'fp_internal.h',
|
||||||
|
|
||||||
# Drivers
|
# Subdirectories to ignore
|
||||||
'aes1660.h',
|
'drivers',
|
||||||
'aes2501.h',
|
'nbis',
|
||||||
'aes2550.h',
|
|
||||||
'aes2660.h',
|
|
||||||
'aes3k.h',
|
|
||||||
'aesx660.h',
|
|
||||||
'driver_ids.h',
|
|
||||||
'elan.h',
|
|
||||||
'upek_proto.h',
|
|
||||||
'upeksonly.h',
|
|
||||||
'upektc.h',
|
|
||||||
'upektc_img.h',
|
|
||||||
'vfs0050.h',
|
|
||||||
'vfs301_proto_fragments.h',
|
|
||||||
'vfs301_proto.h',
|
|
||||||
'vfs5011_proto.h',
|
|
||||||
|
|
||||||
# NBIS
|
|
||||||
'morph.h',
|
|
||||||
'sunrast.h',
|
|
||||||
'bozorth.h',
|
|
||||||
'defs.h',
|
|
||||||
'log.h',
|
|
||||||
'bz_array.h',
|
|
||||||
'lfs.h',
|
|
||||||
'mytime.h',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
html_images = [
|
html_images = [
|
||||||
|
@ -59,6 +31,7 @@ gnome.gtkdoc('libfprint',
|
||||||
content_files: content_files,
|
content_files: content_files,
|
||||||
expand_content_files: expand_content_files,
|
expand_content_files: expand_content_files,
|
||||||
scan_args: [
|
scan_args: [
|
||||||
|
#'--rebuild-sections',
|
||||||
'--ignore-decorators=API_EXPORTED',
|
'--ignore-decorators=API_EXPORTED',
|
||||||
'--ignore-headers=' + ' '.join(private_headers),
|
'--ignore-headers=' + ' '.join(private_headers),
|
||||||
],
|
],
|
||||||
|
|
|
@ -23,17 +23,12 @@
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include "fprint.h"
|
#include "fp_internal.h"
|
||||||
|
|
||||||
#include "fpi-log.h"
|
#include "fpi-log.h"
|
||||||
#include "fpi-dev.h"
|
#include "fpi-usb-transfer.h"
|
||||||
#include "fpi-dev-img.h"
|
|
||||||
#include "fpi-core.h"
|
|
||||||
#include "fpi-ssm.h"
|
#include "fpi-ssm.h"
|
||||||
#include "fpi-poll.h"
|
|
||||||
#include "fpi-dev.h"
|
|
||||||
#include "fpi-usb.h"
|
|
||||||
#include "fpi-img.h"
|
|
||||||
#include "fpi-assembling.h"
|
#include "fpi-assembling.h"
|
||||||
#include "drivers/driver_ids.h"
|
#include "fpi-image-device.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
364
libfprint/fp-context.c
Normal file
364
libfprint/fp-context.c
Normal file
|
@ -0,0 +1,364 @@
|
||||||
|
/*
|
||||||
|
* FpContext - A FPrint context
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* 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 "context"
|
||||||
|
#include <fpi-log.h>
|
||||||
|
|
||||||
|
#include "fpi-context.h"
|
||||||
|
#include "fpi-device.h"
|
||||||
|
#include <gusb.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION: fp-context
|
||||||
|
* @title: FpContext
|
||||||
|
* @short_description: Discover fingerprint devices
|
||||||
|
*
|
||||||
|
* The #FpContext allows you to discover fingerprint scanning hardware. This
|
||||||
|
* is the starting point when integrating libfprint into your software.
|
||||||
|
*
|
||||||
|
* The <link linkend="device-added">device-added</link> and device-removed signals allow you to handle devices
|
||||||
|
* that may be hotplugged at runtime.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GUsbContext *usb_ctx;
|
||||||
|
GCancellable *cancellable;
|
||||||
|
|
||||||
|
gint pending_devices;
|
||||||
|
gboolean enumerated;
|
||||||
|
|
||||||
|
GArray *drivers;
|
||||||
|
GPtrArray *devices;
|
||||||
|
} FpContextPrivate;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE_WITH_PRIVATE (FpContext, fp_context, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DEVICE_ADDED_SIGNAL,
|
||||||
|
DEVICE_REMOVED_SIGNAL,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
static guint signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
static void
|
||||||
|
async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
FpDevice *device;
|
||||||
|
FpContext *context;
|
||||||
|
FpContextPrivate *priv;
|
||||||
|
|
||||||
|
device = (FpDevice *) g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), res, &error);
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
return;
|
||||||
|
|
||||||
|
context = FP_CONTEXT (user_data);
|
||||||
|
priv = fp_context_get_instance_private (context);
|
||||||
|
priv->pending_devices--;
|
||||||
|
g_message ("Ignoring device due to initialization error: %s", error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context = FP_CONTEXT (user_data);
|
||||||
|
priv = fp_context_get_instance_private (context);
|
||||||
|
priv->pending_devices--;
|
||||||
|
g_ptr_array_add (priv->devices, device);
|
||||||
|
g_signal_emit (context, signals[DEVICE_ADDED_SIGNAL], 0, device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
|
||||||
|
{
|
||||||
|
FpContextPrivate *priv = fp_context_get_instance_private (self);
|
||||||
|
GType found_driver = G_TYPE_NONE;
|
||||||
|
const FpIdEntry *found_entry = NULL;
|
||||||
|
gint found_score = 0;
|
||||||
|
gint i;
|
||||||
|
guint16 pid, vid;
|
||||||
|
|
||||||
|
pid = g_usb_device_get_pid (device);
|
||||||
|
vid = g_usb_device_get_vid (device);
|
||||||
|
|
||||||
|
/* Find the best driver to handle this USB device. */
|
||||||
|
for (i = 0; i < priv->drivers->len; i++)
|
||||||
|
{
|
||||||
|
GType driver = g_array_index (priv->drivers, GType, i);
|
||||||
|
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
|
||||||
|
const FpIdEntry *entry;
|
||||||
|
|
||||||
|
if (cls->type != FP_DEVICE_TYPE_USB)
|
||||||
|
{
|
||||||
|
g_type_class_unref (cls);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (entry = cls->id_table; entry->pid; entry++)
|
||||||
|
{
|
||||||
|
gint driver_score = 50;
|
||||||
|
|
||||||
|
if (entry->pid != pid || entry->vid != vid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cls->usb_discover)
|
||||||
|
driver_score = cls->usb_discover (device);
|
||||||
|
|
||||||
|
/* Is this driver better than the one we had? */
|
||||||
|
if (driver_score <= found_score)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
found_score = driver_score;
|
||||||
|
found_driver = driver;
|
||||||
|
found_entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_type_class_unref (cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_driver == G_TYPE_NONE)
|
||||||
|
{
|
||||||
|
g_debug ("No driver found for USB device %04X:%04X", pid, vid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->pending_devices++;
|
||||||
|
g_async_initable_new_async (found_driver,
|
||||||
|
G_PRIORITY_LOW,
|
||||||
|
priv->cancellable,
|
||||||
|
async_device_init_done_cb,
|
||||||
|
self,
|
||||||
|
"fp-usb-device", device,
|
||||||
|
"fp-driver-data", found_entry->driver_data,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usb_device_removed_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
|
||||||
|
{
|
||||||
|
FpContextPrivate *priv = fp_context_get_instance_private (self);
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
/* Do the lazy way and just look at each device. */
|
||||||
|
for (i = 0; i < priv->devices->len; i++)
|
||||||
|
{
|
||||||
|
FpDevice *dev = g_ptr_array_index (priv->devices, i);
|
||||||
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (dev);
|
||||||
|
|
||||||
|
if (cls->type != FP_DEVICE_TYPE_USB)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (fpi_device_get_usb_device (dev) == device)
|
||||||
|
{
|
||||||
|
g_signal_emit (self, signals[DEVICE_REMOVED_SIGNAL], 0, dev);
|
||||||
|
g_ptr_array_remove_index_fast (priv->devices, i);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_context_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
FpContext *self = (FpContext *) object;
|
||||||
|
FpContextPrivate *priv = fp_context_get_instance_private (self);
|
||||||
|
|
||||||
|
g_clear_pointer (&priv->devices, g_ptr_array_unref);
|
||||||
|
|
||||||
|
g_cancellable_cancel (priv->cancellable);
|
||||||
|
g_clear_object (&priv->cancellable);
|
||||||
|
g_clear_pointer (&priv->drivers, g_array_unref);
|
||||||
|
g_clear_object (&priv->usb_ctx);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (fp_context_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_context_class_init (FpContextClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = fp_context_finalize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpContext::device-added:
|
||||||
|
* @context: the #FpContext instance that emitted the signal
|
||||||
|
* @device: A #FpDevice
|
||||||
|
*
|
||||||
|
* This signal is emitted when a fingerprint reader is added.
|
||||||
|
**/
|
||||||
|
signals[DEVICE_ADDED_SIGNAL] = g_signal_new ("device-added",
|
||||||
|
G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (FpContextClass, device_added),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
g_cclosure_marshal_VOID__OBJECT,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
1,
|
||||||
|
FP_TYPE_DEVICE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpContext::device-removed:
|
||||||
|
* @context: the #FpContext instance that emitted the signal
|
||||||
|
* @device: A #FpDevice
|
||||||
|
*
|
||||||
|
* This signal is emitted when a fingerprint reader is removed.
|
||||||
|
**/
|
||||||
|
signals[DEVICE_REMOVED_SIGNAL] = g_signal_new ("device-removed",
|
||||||
|
G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (FpContextClass, device_removed),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
g_cclosure_marshal_VOID__OBJECT,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
1,
|
||||||
|
FP_TYPE_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_context_init (FpContext *self)
|
||||||
|
{
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
FpContextPrivate *priv = fp_context_get_instance_private (self);
|
||||||
|
|
||||||
|
priv->drivers = g_array_new (TRUE, FALSE, sizeof (GType));
|
||||||
|
fpi_get_driver_types (priv->drivers);
|
||||||
|
|
||||||
|
priv->devices = g_ptr_array_new_with_free_func (g_object_unref);
|
||||||
|
|
||||||
|
priv->cancellable = g_cancellable_new ();
|
||||||
|
priv->usb_ctx = g_usb_context_new (&error);
|
||||||
|
if (!priv->usb_ctx)
|
||||||
|
{
|
||||||
|
fp_warn ("Could not initialise USB Subsystem: %s", error->message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_usb_context_set_debug (priv->usb_ctx, G_LOG_LEVEL_INFO);
|
||||||
|
g_signal_connect_object (priv->usb_ctx,
|
||||||
|
"device-added",
|
||||||
|
G_CALLBACK (usb_device_added_cb),
|
||||||
|
self,
|
||||||
|
G_CONNECT_SWAPPED);
|
||||||
|
g_signal_connect_object (priv->usb_ctx,
|
||||||
|
"device-removed",
|
||||||
|
G_CALLBACK (usb_device_removed_cb),
|
||||||
|
self,
|
||||||
|
G_CONNECT_SWAPPED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_context_new:
|
||||||
|
*
|
||||||
|
* Create a new #FpContext.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): a newly created #FpContext
|
||||||
|
*/
|
||||||
|
FpContext *
|
||||||
|
fp_context_new (void)
|
||||||
|
{
|
||||||
|
return g_object_new (FP_TYPE_CONTEXT, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_context_enumerate:
|
||||||
|
* @context: a #FpContext
|
||||||
|
*
|
||||||
|
* Enumerate all devices. You should call this function exactly once
|
||||||
|
* at startup. Please note that it iterates the mainloop until all
|
||||||
|
* devices are enumerated.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fp_context_enumerate (FpContext *context)
|
||||||
|
{
|
||||||
|
FpContextPrivate *priv = fp_context_get_instance_private (context);
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
g_return_if_fail (FP_IS_CONTEXT (context));
|
||||||
|
|
||||||
|
if (priv->enumerated)
|
||||||
|
return;
|
||||||
|
|
||||||
|
priv->enumerated = TRUE;
|
||||||
|
|
||||||
|
/* USB devices are handled from callbacks */
|
||||||
|
g_usb_context_enumerate (priv->usb_ctx);
|
||||||
|
|
||||||
|
/* Handle Virtual devices based on environment variables */
|
||||||
|
for (i = 0; i < priv->drivers->len; i++)
|
||||||
|
{
|
||||||
|
GType driver = g_array_index (priv->drivers, GType, i);
|
||||||
|
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
|
||||||
|
const FpIdEntry *entry;
|
||||||
|
|
||||||
|
if (cls->type != FP_DEVICE_TYPE_VIRTUAL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (entry = cls->id_table; entry->pid; entry++)
|
||||||
|
{
|
||||||
|
const gchar *val;
|
||||||
|
|
||||||
|
val = g_getenv (entry->virtual_envvar);
|
||||||
|
if (!val || val[0] == '\0')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_debug ("Found virtual environment device: %s, %s", entry->virtual_envvar, val);
|
||||||
|
priv->pending_devices++;
|
||||||
|
g_async_initable_new_async (driver,
|
||||||
|
G_PRIORITY_LOW,
|
||||||
|
priv->cancellable,
|
||||||
|
async_device_init_done_cb,
|
||||||
|
context,
|
||||||
|
"fp-environ", val,
|
||||||
|
"fp-driver-data", entry->driver_data,
|
||||||
|
NULL);
|
||||||
|
g_debug ("created");
|
||||||
|
}
|
||||||
|
|
||||||
|
g_type_class_unref (cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (priv->pending_devices)
|
||||||
|
g_main_context_iteration (NULL, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_context_get_devices:
|
||||||
|
* @context: a #FpContext
|
||||||
|
*
|
||||||
|
* Get all devices. fp_context_enumerate() will be called as needed.
|
||||||
|
*
|
||||||
|
* Returns: (transfer none) (element-type FpDevice): a new #GPtrArray of #GUsbDevice's.
|
||||||
|
*/
|
||||||
|
GPtrArray *
|
||||||
|
fp_context_get_devices (FpContext *context)
|
||||||
|
{
|
||||||
|
FpContextPrivate *priv = fp_context_get_instance_private (context);
|
||||||
|
|
||||||
|
g_return_val_if_fail (FP_IS_CONTEXT (context), NULL);
|
||||||
|
|
||||||
|
fp_context_enumerate (context);
|
||||||
|
|
||||||
|
return priv->devices;
|
||||||
|
}
|
52
libfprint/fp-context.h
Normal file
52
libfprint/fp-context.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* FpContext - A FPrint context
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "fp-device.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define FP_TYPE_CONTEXT (fp_context_get_type ())
|
||||||
|
G_DECLARE_DERIVABLE_TYPE (FpContext, fp_context, FP, CONTEXT, GObject)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpContextClass:
|
||||||
|
* @device_added: Called when a new device is added
|
||||||
|
* @device_removed: Called when a device is removed
|
||||||
|
*
|
||||||
|
* Class structure for #FpContext instances.
|
||||||
|
*/
|
||||||
|
struct _FpContextClass
|
||||||
|
{
|
||||||
|
GObjectClass parent_class;
|
||||||
|
|
||||||
|
void (*device_added) (FpContext *context,
|
||||||
|
FpDevice *device);
|
||||||
|
void (*device_removed) (FpContext *context,
|
||||||
|
FpDevice *device);
|
||||||
|
};
|
||||||
|
|
||||||
|
FpContext *fp_context_new (void);
|
||||||
|
|
||||||
|
void fp_context_enumerate (FpContext *context);
|
||||||
|
|
||||||
|
GPtrArray *fp_context_get_devices (FpContext *context);
|
||||||
|
|
||||||
|
G_END_DECLS
|
2574
libfprint/fp-device.c
Normal file
2574
libfprint/fp-device.c
Normal file
File diff suppressed because it is too large
Load diff
255
libfprint/fp-device.h
Normal file
255
libfprint/fp-device.h
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
/*
|
||||||
|
* FpDevice - A fingerprint reader device
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "fp-image.h"
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define FP_TYPE_DEVICE (fp_device_get_type ())
|
||||||
|
#define FP_DEVICE_RETRY (fp_device_retry_quark ())
|
||||||
|
#define FP_DEVICE_ERROR (fp_device_error_quark ())
|
||||||
|
G_DECLARE_DERIVABLE_TYPE (FpDevice, fp_device, FP, DEVICE, GObject)
|
||||||
|
|
||||||
|
#include "fp-print.h"
|
||||||
|
|
||||||
|
/* NOTE: We keep the class struct private! */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpDeviceType:
|
||||||
|
* @FP_DEVICE_TYPE_VIRTUAL: The device is a virtual device
|
||||||
|
* @FP_DEVICE_TYPE_USB: The device is a USB device
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FP_DEVICE_TYPE_VIRTUAL,
|
||||||
|
FP_DEVICE_TYPE_USB,
|
||||||
|
} FpDeviceType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpScanType:
|
||||||
|
* @FP_SCAN_TYPE_SWIPE: Sensor requires swiping the finger.
|
||||||
|
* @FP_SCAN_TYPE_PRESS: Sensor requires placing/pressing down the finger.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FP_SCAN_TYPE_SWIPE,
|
||||||
|
FP_SCAN_TYPE_PRESS,
|
||||||
|
} FpScanType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpDeviceRetry:
|
||||||
|
* @FP_DEVICE_RETRY_GENERAL: The scan did not succeed due to poor scan quality
|
||||||
|
* or other general user scanning problem.
|
||||||
|
* @FP_DEVICE_RETRY_TOO_SHORT: The scan did not succeed because the finger
|
||||||
|
* swipe was too short.
|
||||||
|
* @FP_DEVICE_RETRY_CENTER_FINGER: The scan did not succeed because the finger
|
||||||
|
* was not centered on the scanner.
|
||||||
|
* @FP_DEVICE_RETRY_REMOVE_FINGER: The scan did not succeed due to quality or
|
||||||
|
* pressure problems; the user should remove their finger from the scanner
|
||||||
|
* before retrying.
|
||||||
|
*
|
||||||
|
* Error codes representing scan failures resulting in the user needing to
|
||||||
|
* retry.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FP_DEVICE_RETRY_GENERAL,
|
||||||
|
FP_DEVICE_RETRY_TOO_SHORT,
|
||||||
|
FP_DEVICE_RETRY_CENTER_FINGER,
|
||||||
|
FP_DEVICE_RETRY_REMOVE_FINGER,
|
||||||
|
} FpDeviceRetry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpDeviceError:
|
||||||
|
* @FP_DEVICE_ERROR_GENERAL: A general error occured.
|
||||||
|
* @FP_DEVICE_ERROR_NOT_SUPPORTED: The device does not support the requested
|
||||||
|
* operation.
|
||||||
|
* @FP_DEVICE_ERROR_NOT_OPEN: The device needs to be opened to start this
|
||||||
|
* operation.
|
||||||
|
* @FP_DEVICE_ERROR_ALREADY_OPEN: The device has already been opened.
|
||||||
|
* @FP_DEVICE_ERROR_BUSY: The device is busy with another request.
|
||||||
|
* @FP_DEVICE_ERROR_PROTO: Protocol error
|
||||||
|
* @FP_DEVICE_ERROR_DATA_INVALID: The passed data is invalid
|
||||||
|
* @FP_DEVICE_ERROR_DATA_NOT_FOUND: Requested print was not found on device
|
||||||
|
* @FP_DEVICE_ERROR_DATA_FULL: No space on device available for operation
|
||||||
|
*
|
||||||
|
* Error codes for device operations. More specific errors from other domains
|
||||||
|
* such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FP_DEVICE_ERROR_GENERAL,
|
||||||
|
FP_DEVICE_ERROR_NOT_SUPPORTED,
|
||||||
|
FP_DEVICE_ERROR_NOT_OPEN,
|
||||||
|
FP_DEVICE_ERROR_ALREADY_OPEN,
|
||||||
|
FP_DEVICE_ERROR_BUSY,
|
||||||
|
FP_DEVICE_ERROR_PROTO,
|
||||||
|
FP_DEVICE_ERROR_DATA_INVALID,
|
||||||
|
FP_DEVICE_ERROR_DATA_NOT_FOUND,
|
||||||
|
FP_DEVICE_ERROR_DATA_FULL,
|
||||||
|
} FpDeviceError;
|
||||||
|
|
||||||
|
GQuark fp_device_retry_quark (void);
|
||||||
|
GQuark fp_device_error_quark (void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpEnrollProgress:
|
||||||
|
* @device: a #FpDevice
|
||||||
|
* @completed_stages: Number of completed stages
|
||||||
|
* @print: (nullable): The last scaned print
|
||||||
|
* @user_data: (nullable): User provided data
|
||||||
|
* @error: (nullable) (transfer none): #GError or %NULL
|
||||||
|
*
|
||||||
|
* The passed error is guaranteed to be of type %FP_DEVICE_RETRY if set.
|
||||||
|
*/
|
||||||
|
typedef void (*FpEnrollProgress) (FpDevice *device,
|
||||||
|
gint completed_stages,
|
||||||
|
FpPrint *print,
|
||||||
|
gpointer user_data,
|
||||||
|
GError *error);
|
||||||
|
|
||||||
|
|
||||||
|
const gchar *fp_device_get_driver (FpDevice *device);
|
||||||
|
const gchar *fp_device_get_device_id (FpDevice *device);
|
||||||
|
const gchar *fp_device_get_name (FpDevice *device);
|
||||||
|
FpScanType fp_device_get_scan_type (FpDevice *device);
|
||||||
|
gint fp_device_get_nr_enroll_stages (FpDevice *device);
|
||||||
|
|
||||||
|
gboolean fp_device_supports_identify (FpDevice *device);
|
||||||
|
gboolean fp_device_supports_capture (FpDevice *device);
|
||||||
|
gboolean fp_device_has_storage (FpDevice *device);
|
||||||
|
|
||||||
|
/* Opening the device */
|
||||||
|
void fp_device_open (FpDevice *device,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void fp_device_close (FpDevice *device,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void fp_device_enroll (FpDevice *device,
|
||||||
|
FpPrint *template_print,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
FpEnrollProgress progress_cb,
|
||||||
|
gpointer progress_data,
|
||||||
|
GDestroyNotify progress_destroy,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void fp_device_verify (FpDevice *device,
|
||||||
|
FpPrint *enrolled_print,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void fp_device_identify (FpDevice *device,
|
||||||
|
GPtrArray *prints,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void fp_device_capture (FpDevice *device,
|
||||||
|
gboolean wait_for_finger,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void fp_device_delete_print (FpDevice *device,
|
||||||
|
FpPrint *enrolled_print,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void fp_device_list_prints (FpDevice *device,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
gboolean fp_device_open_finish (FpDevice *device,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
|
gboolean fp_device_close_finish (FpDevice *device,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
|
FpPrint *fp_device_enroll_finish (FpDevice *device,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
|
gboolean fp_device_verify_finish (FpDevice *device,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gboolean *match,
|
||||||
|
FpPrint **print,
|
||||||
|
GError **error);
|
||||||
|
gboolean fp_device_identify_finish (FpDevice *device,
|
||||||
|
GAsyncResult *result,
|
||||||
|
FpPrint **match,
|
||||||
|
FpPrint **print,
|
||||||
|
GError **error);
|
||||||
|
FpImage * fp_device_capture_finish (FpDevice *device,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
|
gboolean fp_device_delete_print_finish (FpDevice *device,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
|
GPtrArray * fp_device_list_prints_finish (FpDevice *device,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
|
||||||
|
gboolean fp_device_open_sync (FpDevice *device,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
gboolean fp_device_close_sync (FpDevice *device,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
FpPrint * fp_device_enroll_sync (FpDevice *device,
|
||||||
|
FpPrint *template_print,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
FpEnrollProgress progress_cb,
|
||||||
|
gpointer progress_data,
|
||||||
|
GError **error);
|
||||||
|
gboolean fp_device_verify_sync (FpDevice *device,
|
||||||
|
FpPrint *enrolled_print,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
gboolean *match,
|
||||||
|
FpPrint **print,
|
||||||
|
GError **error);
|
||||||
|
gboolean fp_device_identify_sync (FpDevice *device,
|
||||||
|
GPtrArray *prints,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
FpPrint **match,
|
||||||
|
FpPrint **print,
|
||||||
|
GError **error);
|
||||||
|
FpImage * fp_device_capture_sync (FpDevice *device,
|
||||||
|
gboolean wait_for_finger,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
gboolean fp_device_delete_print_sync (FpDevice *device,
|
||||||
|
FpPrint *enrolled_print,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
GPtrArray * fp_device_list_prints_sync (FpDevice *device,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
|
||||||
|
G_END_DECLS
|
795
libfprint/fp-image-device.c
Normal file
795
libfprint/fp-image-device.c
Normal file
|
@ -0,0 +1,795 @@
|
||||||
|
/*
|
||||||
|
* FpImageDevice - An image based fingerprint reader device
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* 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 "image_device"
|
||||||
|
#include "fpi-log.h"
|
||||||
|
|
||||||
|
#include "fpi-image-device.h"
|
||||||
|
#include "fpi-print.h"
|
||||||
|
#include "fpi-image.h"
|
||||||
|
|
||||||
|
#define MIN_ACCEPTABLE_MINUTIAE 10
|
||||||
|
#define BOZORTH3_DEFAULT_THRESHOLD 40
|
||||||
|
#define IMG_ENROLL_STAGES 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION: fp-image-device
|
||||||
|
* @title: FpImageDevice
|
||||||
|
* @short_description: Image device subclass
|
||||||
|
*
|
||||||
|
* This is a helper class for the commonly found image based devices.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION: fpi-image-device
|
||||||
|
* @title: Internal FpImageDevice
|
||||||
|
* @short_description: Internal image device routines
|
||||||
|
*
|
||||||
|
* See #FpImageDeviceClass for more details. Also see the public
|
||||||
|
* #FpImageDevice routines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FpImageDeviceState state;
|
||||||
|
gboolean active;
|
||||||
|
|
||||||
|
gint enroll_stage;
|
||||||
|
|
||||||
|
guint pending_activation_timeout_id;
|
||||||
|
gboolean pending_activation_timeout_waiting_finger_off;
|
||||||
|
|
||||||
|
gint bz3_threshold;
|
||||||
|
} FpImageDevicePrivate;
|
||||||
|
|
||||||
|
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpImageDevice, fp_image_device, FP_TYPE_DEVICE)
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************/
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
* - sanitize_image seems a bit odd, in particular the sizing stuff.
|
||||||
|
**/
|
||||||
|
|
||||||
|
/* Static helper functions */
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_device_change_state (FpImageDevice *self, FpImageDeviceState state)
|
||||||
|
{
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||||
|
|
||||||
|
/* Cannot change to inactive using this function. */
|
||||||
|
g_assert (state != FP_IMAGE_DEVICE_STATE_INACTIVE);
|
||||||
|
|
||||||
|
/* We might have been waiting for the finger to go OFF to start the
|
||||||
|
* next operation. */
|
||||||
|
if (priv->pending_activation_timeout_id)
|
||||||
|
{
|
||||||
|
g_source_remove (priv->pending_activation_timeout_id);
|
||||||
|
priv->pending_activation_timeout_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state);
|
||||||
|
|
||||||
|
priv->state = state;
|
||||||
|
|
||||||
|
/* change_state is the only callback which is optional and does not
|
||||||
|
* have a default implementation. */
|
||||||
|
if (cls->change_state)
|
||||||
|
cls->change_state (self, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_device_activate (FpImageDevice *self)
|
||||||
|
{
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||||
|
|
||||||
|
g_assert (!priv->active);
|
||||||
|
|
||||||
|
/* We don't have a neutral ACTIVE state, but we always will
|
||||||
|
* go into WAIT_FINGER_ON afterwards. */
|
||||||
|
priv->state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
|
||||||
|
|
||||||
|
/* We might have been waiting for deactivation to finish before
|
||||||
|
* starting the next operation. */
|
||||||
|
if (priv->pending_activation_timeout_id)
|
||||||
|
{
|
||||||
|
g_source_remove (priv->pending_activation_timeout_id);
|
||||||
|
priv->pending_activation_timeout_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_dbg ("Activating image device\n");
|
||||||
|
cls->activate (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_device_deactivate (FpDevice *device)
|
||||||
|
{
|
||||||
|
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
|
||||||
|
|
||||||
|
if (!priv->active)
|
||||||
|
{
|
||||||
|
/* XXX: We currently deactivate both from minutiae scan result
|
||||||
|
* and finger off report. */
|
||||||
|
fp_dbg ("Already deactivated, ignoring request.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
|
||||||
|
|
||||||
|
fp_dbg ("Deactivating image device\n");
|
||||||
|
cls->deactivate (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
pending_activation_timeout (gpointer user_data)
|
||||||
|
{
|
||||||
|
FpImageDevice *self = FP_IMAGE_DEVICE (user_data);
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
|
||||||
|
priv->pending_activation_timeout_id = 0;
|
||||||
|
|
||||||
|
if (priv->pending_activation_timeout_waiting_finger_off)
|
||||||
|
fpi_device_action_error (FP_DEVICE (self),
|
||||||
|
fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER,
|
||||||
|
"Remove finger before requesting another scan operation"));
|
||||||
|
else
|
||||||
|
fpi_device_action_error (FP_DEVICE (self),
|
||||||
|
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callbacks/vfuncs */
|
||||||
|
static void
|
||||||
|
fp_image_device_open (FpDevice *device)
|
||||||
|
{
|
||||||
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
|
||||||
|
|
||||||
|
/* Nothing special about opening an image device, just
|
||||||
|
* forward the request. */
|
||||||
|
cls->img_open (FP_IMAGE_DEVICE (device));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_device_close (FpDevice *device)
|
||||||
|
{
|
||||||
|
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
||||||
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
|
||||||
|
/* In the close case we may need to wait/force deactivation first.
|
||||||
|
* Three possible cases:
|
||||||
|
* 1. We are inactive
|
||||||
|
* -> immediately close
|
||||||
|
* 2. We are waiting for finger off
|
||||||
|
* -> imediately deactivate
|
||||||
|
* 3. We are deactivating
|
||||||
|
* -> handled by deactivate_complete */
|
||||||
|
|
||||||
|
if (!priv->active)
|
||||||
|
cls->img_close (self);
|
||||||
|
else if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE)
|
||||||
|
fp_image_device_deactivate (device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_device_cancel_action (FpDevice *device)
|
||||||
|
{
|
||||||
|
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
||||||
|
FpDeviceAction action;
|
||||||
|
|
||||||
|
action = fpi_device_get_current_action (device);
|
||||||
|
|
||||||
|
/* We can only cancel capture operations, in that case, deactivate and return
|
||||||
|
* an error immediately. */
|
||||||
|
if (action == FP_DEVICE_ACTION_ENROLL ||
|
||||||
|
action == FP_DEVICE_ACTION_VERIFY ||
|
||||||
|
action == FP_DEVICE_ACTION_IDENTIFY ||
|
||||||
|
action == FP_DEVICE_ACTION_CAPTURE)
|
||||||
|
{
|
||||||
|
fp_image_device_deactivate (FP_DEVICE (self));
|
||||||
|
|
||||||
|
/* XXX: Some nicer way of doing this would be good. */
|
||||||
|
fpi_device_action_error (FP_DEVICE (self),
|
||||||
|
g_error_new (G_IO_ERROR,
|
||||||
|
G_IO_ERROR_CANCELLED,
|
||||||
|
"Device operation was cancelled"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_device_start_capture_action (FpDevice *device)
|
||||||
|
{
|
||||||
|
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpDeviceAction action;
|
||||||
|
|
||||||
|
/* There is just one action that we cannot support out
|
||||||
|
* of the box, which is a capture without first waiting
|
||||||
|
* for a finger to be on the device.
|
||||||
|
*/
|
||||||
|
action = fpi_device_get_current_action (device);
|
||||||
|
if (action == FP_DEVICE_ACTION_CAPTURE)
|
||||||
|
{
|
||||||
|
gboolean wait_for_finger;
|
||||||
|
|
||||||
|
fpi_device_get_capture_data (device, &wait_for_finger);
|
||||||
|
|
||||||
|
if (!wait_for_finger)
|
||||||
|
{
|
||||||
|
fpi_device_action_error (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (action == FP_DEVICE_ACTION_ENROLL)
|
||||||
|
{
|
||||||
|
FpPrint *enroll_print = NULL;
|
||||||
|
|
||||||
|
fpi_device_get_enroll_data (device, &enroll_print);
|
||||||
|
fpi_print_set_type (enroll_print, FP_PRINT_NBIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->enroll_stage = 0;
|
||||||
|
|
||||||
|
/* The device might still be deactivating from a previous call.
|
||||||
|
* In that situation, try to wait for a bit before reporting back an
|
||||||
|
* error (which will usually say that the user should remove the
|
||||||
|
* finger).
|
||||||
|
*/
|
||||||
|
if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE || priv->active)
|
||||||
|
{
|
||||||
|
g_debug ("Got a new request while the device was still active");
|
||||||
|
g_assert (priv->pending_activation_timeout_id == 0);
|
||||||
|
priv->pending_activation_timeout_id =
|
||||||
|
g_timeout_add (100, pending_activation_timeout, device);
|
||||||
|
|
||||||
|
if (priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
||||||
|
priv->pending_activation_timeout_waiting_finger_off = TRUE;
|
||||||
|
else
|
||||||
|
priv->pending_activation_timeout_waiting_finger_off = FALSE;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And activate the device; we rely on fpi_image_device_activate_complete()
|
||||||
|
* to be called when done (or immediately). */
|
||||||
|
fp_image_device_activate (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************/
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_device_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
FpImageDevice *self = (FpImageDevice *) object;
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
|
||||||
|
g_assert (priv->active == FALSE);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (fp_image_device_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_device_default_activate (FpImageDevice *self)
|
||||||
|
{
|
||||||
|
fpi_image_device_activate_complete (self, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_device_default_deactivate (FpImageDevice *self)
|
||||||
|
{
|
||||||
|
fpi_image_device_deactivate_complete (self, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_device_class_init (FpImageDeviceClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
FpDeviceClass *fp_device_class = FP_DEVICE_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = fp_image_device_finalize;
|
||||||
|
|
||||||
|
fp_device_class->open = fp_image_device_open;
|
||||||
|
fp_device_class->close = fp_image_device_close;
|
||||||
|
fp_device_class->enroll = fp_image_device_start_capture_action;
|
||||||
|
fp_device_class->verify = fp_image_device_start_capture_action;
|
||||||
|
fp_device_class->identify = fp_image_device_start_capture_action;
|
||||||
|
fp_device_class->capture = fp_image_device_start_capture_action;
|
||||||
|
|
||||||
|
fp_device_class->cancel = fp_image_device_cancel_action;
|
||||||
|
|
||||||
|
/* Default implementations */
|
||||||
|
klass->activate = fp_image_device_default_activate;
|
||||||
|
klass->deactivate = fp_image_device_default_deactivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_device_init (FpImageDevice *self)
|
||||||
|
{
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||||
|
|
||||||
|
/* Set default values. */
|
||||||
|
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), IMG_ENROLL_STAGES);
|
||||||
|
|
||||||
|
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
|
||||||
|
if (cls->bz3_threshold > 0)
|
||||||
|
priv->bz3_threshold = cls->bz3_threshold;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(FpImage) image = FP_IMAGE (source_object);
|
||||||
|
GError *error = NULL;
|
||||||
|
FpPrint *print = NULL;
|
||||||
|
FpDevice *device = FP_DEVICE (user_data);
|
||||||
|
FpImageDevicePrivate *priv;
|
||||||
|
FpDeviceAction action;
|
||||||
|
|
||||||
|
/* Note: We rely on the device to not disappear during an operation. */
|
||||||
|
|
||||||
|
if (!fp_image_detect_minutiae_finish (image, res, &error))
|
||||||
|
{
|
||||||
|
/* Cancel operation . */
|
||||||
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
{
|
||||||
|
fpi_device_action_error (device, g_steal_pointer (&error));
|
||||||
|
fp_image_device_deactivate (device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Replace error with a retry condition. */
|
||||||
|
g_warning ("Failed to detect minutiae: %s", error->message);
|
||||||
|
g_clear_pointer (&error, g_error_free);
|
||||||
|
|
||||||
|
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_GENERAL, "Minutiae detection failed, please retry");
|
||||||
|
}
|
||||||
|
|
||||||
|
priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
|
||||||
|
action = fpi_device_get_current_action (device);
|
||||||
|
|
||||||
|
if (action == FP_DEVICE_ACTION_CAPTURE)
|
||||||
|
{
|
||||||
|
fpi_device_capture_complete (device, g_steal_pointer (&image), error);
|
||||||
|
fp_image_device_deactivate (device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
print = fp_print_new (device);
|
||||||
|
fpi_print_set_type (print, FP_PRINT_NBIS);
|
||||||
|
if (!fpi_print_add_from_image (print, image, &error))
|
||||||
|
g_clear_object (&print);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == FP_DEVICE_ACTION_ENROLL)
|
||||||
|
{
|
||||||
|
FpPrint *enroll_print;
|
||||||
|
fpi_device_get_enroll_data (device, &enroll_print);
|
||||||
|
|
||||||
|
if (print)
|
||||||
|
{
|
||||||
|
fpi_print_add_print (enroll_print, print);
|
||||||
|
priv->enroll_stage += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_device_enroll_progress (device, priv->enroll_stage, print, error);
|
||||||
|
|
||||||
|
if (priv->enroll_stage == IMG_ENROLL_STAGES)
|
||||||
|
{
|
||||||
|
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
|
||||||
|
fp_image_device_deactivate (device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (action == FP_DEVICE_ACTION_VERIFY)
|
||||||
|
{
|
||||||
|
FpPrint *template;
|
||||||
|
FpiMatchResult result;
|
||||||
|
|
||||||
|
fpi_device_get_verify_data (device, &template);
|
||||||
|
if (print)
|
||||||
|
result = fpi_print_bz3_match (template, print, priv->bz3_threshold, &error);
|
||||||
|
else
|
||||||
|
result = FPI_MATCH_ERROR;
|
||||||
|
|
||||||
|
fpi_device_verify_complete (device, result, print, error);
|
||||||
|
fp_image_device_deactivate (device);
|
||||||
|
}
|
||||||
|
else if (action == FP_DEVICE_ACTION_IDENTIFY)
|
||||||
|
{
|
||||||
|
gint i;
|
||||||
|
GPtrArray *templates;
|
||||||
|
FpPrint *result = NULL;
|
||||||
|
|
||||||
|
fpi_device_get_identify_data (device, &templates);
|
||||||
|
for (i = 0; !error && i < templates->len; i++)
|
||||||
|
{
|
||||||
|
FpPrint *template = g_ptr_array_index (templates, i);
|
||||||
|
|
||||||
|
if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS)
|
||||||
|
{
|
||||||
|
result = g_object_ref (template);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_device_identify_complete (device, result, print, error);
|
||||||
|
fp_image_device_deactivate (device);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* XXX: This can be hit currently due to a race condition in the enroll code!
|
||||||
|
* In that case we scan a further image even though the minutiae for the previous
|
||||||
|
* one have not yet been detected.
|
||||||
|
* We need to keep track on the pending minutiae detection and the fact that
|
||||||
|
* it will finish eventually (or we may need to retry on error and activate the
|
||||||
|
* device again). */
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************/
|
||||||
|
/* Private API */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_image_device_set_bz3_threshold:
|
||||||
|
* @self: a #FpImageDevice imaging fingerprint device
|
||||||
|
* @bz3_threshold: BZ3 threshold to use
|
||||||
|
*
|
||||||
|
* Dynamically adjust the bz3 threshold. This is only needed for drivers
|
||||||
|
* that support devices with different properties. It should generally be
|
||||||
|
* called from the probe callback, but is acceptable to call from the open
|
||||||
|
* callback.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_image_device_set_bz3_threshold (FpImageDevice *self,
|
||||||
|
gint bz3_threshold)
|
||||||
|
{
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
|
||||||
|
g_return_if_fail (FP_IS_IMAGE_DEVICE (self));
|
||||||
|
g_return_if_fail (bz3_threshold > 0);
|
||||||
|
|
||||||
|
priv->bz3_threshold = bz3_threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_image_device_report_finger_status:
|
||||||
|
* @self: a #FpImageDevice imaging fingerprint device
|
||||||
|
* @present: whether the finger is present on the sensor
|
||||||
|
*
|
||||||
|
* Reports from the driver whether the user's finger is on
|
||||||
|
* the sensor.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_image_device_report_finger_status (FpImageDevice *self,
|
||||||
|
gboolean present)
|
||||||
|
{
|
||||||
|
FpDevice *device = FP_DEVICE (self);
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpDeviceAction action;
|
||||||
|
|
||||||
|
action = fpi_device_get_current_action (device);
|
||||||
|
|
||||||
|
if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE)
|
||||||
|
{
|
||||||
|
/* Do we really want to always ignore such reports? We could
|
||||||
|
* also track the state in case the user had the finger on
|
||||||
|
* the device at initialisation time and the driver reports
|
||||||
|
* this early.
|
||||||
|
*/
|
||||||
|
g_debug ("Ignoring finger presence report as the device is not active!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
action = fpi_device_get_current_action (device);
|
||||||
|
|
||||||
|
g_assert (action != FP_DEVICE_ACTION_OPEN);
|
||||||
|
g_assert (action != FP_DEVICE_ACTION_CLOSE);
|
||||||
|
|
||||||
|
g_debug ("Image device reported finger status: %s", present ? "on" : "off");
|
||||||
|
|
||||||
|
if (present && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||||
|
{
|
||||||
|
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_CAPTURE);
|
||||||
|
}
|
||||||
|
else if (!present && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
||||||
|
{
|
||||||
|
/* We need to deactivate or continue to await finger */
|
||||||
|
|
||||||
|
/* There are three possible situations:
|
||||||
|
* 1. We are deactivating the device and the action is still in progress
|
||||||
|
* (minutiae detection).
|
||||||
|
* 2. We are still deactivating the device after an action completed
|
||||||
|
* 3. We were waiting for finger removal to start the new action
|
||||||
|
* Either way, we always end up deactivating except for the enroll case.
|
||||||
|
* XXX: This is not quite correct though, as we assume we need another finger
|
||||||
|
* scan even though we might be processing the last one (successfully).
|
||||||
|
*/
|
||||||
|
if (action != FP_DEVICE_ACTION_ENROLL)
|
||||||
|
fp_image_device_deactivate (device);
|
||||||
|
else
|
||||||
|
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_image_device_image_captured:
|
||||||
|
* @self: a #FpImageDevice imaging fingerprint device
|
||||||
|
* @image: whether the finger is present on the sensor
|
||||||
|
*
|
||||||
|
* Reports an image capture. Only use this function if the image was
|
||||||
|
* captured successfully. If there was an issue where the user should
|
||||||
|
* retry, use fpi_image_device_retry_scan() to report the retry condition.
|
||||||
|
*
|
||||||
|
* In the event of a fatal error for the operation use
|
||||||
|
* fpi_image_device_session_error(). This will abort the entire operation
|
||||||
|
* including e.g. an enroll operation which captures multiple images during
|
||||||
|
* one session.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
|
||||||
|
{
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpDeviceAction action;
|
||||||
|
|
||||||
|
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||||
|
|
||||||
|
g_return_if_fail (image != NULL);
|
||||||
|
g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_CAPTURE);
|
||||||
|
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
|
||||||
|
action == FP_DEVICE_ACTION_VERIFY ||
|
||||||
|
action == FP_DEVICE_ACTION_IDENTIFY ||
|
||||||
|
action == FP_DEVICE_ACTION_CAPTURE);
|
||||||
|
|
||||||
|
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
|
||||||
|
|
||||||
|
g_debug ("Image device captured an image");
|
||||||
|
|
||||||
|
/* XXX: We also detect minutiae in capture mode, we solely do this
|
||||||
|
* to normalize the image which will happen as a by-product. */
|
||||||
|
fp_image_detect_minutiae (image,
|
||||||
|
fpi_device_get_cancellable (FP_DEVICE (self)),
|
||||||
|
fpi_image_device_minutiae_detected,
|
||||||
|
self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_image_device_retry_scan:
|
||||||
|
* @self: a #FpImageDevice imaging fingerprint device
|
||||||
|
* @retry: The #FpDeviceRetry error code to report
|
||||||
|
*
|
||||||
|
* Reports a scan failure to the user. This may or may not abort the
|
||||||
|
* current session. It is the equivalent of fpi_image_device_image_captured()
|
||||||
|
* in the case of a retryable error condition (e.g. short swipe).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
|
||||||
|
{
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpDeviceAction action;
|
||||||
|
GError *error;
|
||||||
|
|
||||||
|
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||||
|
|
||||||
|
/* We might be waiting for a finger at this point, so just accept
|
||||||
|
* all but INACTIVE */
|
||||||
|
g_return_if_fail (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE);
|
||||||
|
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
|
||||||
|
action == FP_DEVICE_ACTION_VERIFY ||
|
||||||
|
action == FP_DEVICE_ACTION_IDENTIFY ||
|
||||||
|
action == FP_DEVICE_ACTION_CAPTURE);
|
||||||
|
|
||||||
|
error = fpi_device_retry_new (retry);
|
||||||
|
|
||||||
|
if (action == FP_DEVICE_ACTION_ENROLL)
|
||||||
|
{
|
||||||
|
g_debug ("Reporting retry during enroll");
|
||||||
|
fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We abort the operation and let the surrounding code retry in the
|
||||||
|
* non-enroll case (this is identical to a session error). */
|
||||||
|
g_debug ("Abort current operation due to retry (non-enroll case)");
|
||||||
|
fp_image_device_deactivate (FP_DEVICE (self));
|
||||||
|
fpi_device_action_error (FP_DEVICE (self), error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_image_device_session_error:
|
||||||
|
* @self: a #FpImageDevice imaging fingerprint device
|
||||||
|
* @error: The #GError to report
|
||||||
|
*
|
||||||
|
* Report an error while interacting with the device. This effectively
|
||||||
|
* aborts the current ongoing action.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_image_device_session_error (FpImageDevice *self, GError *error)
|
||||||
|
{
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
|
||||||
|
g_return_if_fail (self);
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
g_warning ("Driver did not provide an error, generating a generic one");
|
||||||
|
error = g_error_new (FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL, "Driver reported session error without an error");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!priv->active)
|
||||||
|
{
|
||||||
|
FpDeviceAction action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||||
|
g_warning ("Driver reported session error, but device is inactive.");
|
||||||
|
|
||||||
|
if (action != FP_DEVICE_ACTION_NONE)
|
||||||
|
{
|
||||||
|
g_warning ("Translating to activation failure!");
|
||||||
|
fpi_image_device_activate_complete (self, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE)
|
||||||
|
{
|
||||||
|
g_warning ("Driver reported session error; translating to deactivation failure.");
|
||||||
|
fpi_image_device_deactivate_complete (self, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error->domain == FP_DEVICE_RETRY)
|
||||||
|
g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
|
||||||
|
|
||||||
|
fp_image_device_deactivate (FP_DEVICE (self));
|
||||||
|
fpi_device_action_error (FP_DEVICE (self), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_image_device_activate_complete:
|
||||||
|
* @self: a #FpImageDevice imaging fingerprint device
|
||||||
|
* @error: A #GError or %NULL on success
|
||||||
|
*
|
||||||
|
* Reports completion of device activation.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
|
||||||
|
{
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpDeviceAction action;
|
||||||
|
|
||||||
|
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||||
|
|
||||||
|
g_return_if_fail (priv->active == FALSE);
|
||||||
|
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
|
||||||
|
action == FP_DEVICE_ACTION_VERIFY ||
|
||||||
|
action == FP_DEVICE_ACTION_IDENTIFY ||
|
||||||
|
action == FP_DEVICE_ACTION_CAPTURE);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_debug ("Image device activation failed");
|
||||||
|
fpi_device_action_error (FP_DEVICE (self), error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_debug ("Image device activation completed");
|
||||||
|
|
||||||
|
priv->active = TRUE;
|
||||||
|
|
||||||
|
/* We always want to capture at this point, move to AWAIT_FINGER
|
||||||
|
* state. */
|
||||||
|
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_image_device_deactivate_complete:
|
||||||
|
* @self: a #FpImageDevice imaging fingerprint device
|
||||||
|
* @error: A #GError or %NULL on success
|
||||||
|
*
|
||||||
|
* Reports completion of device deactivation.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error)
|
||||||
|
{
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||||
|
FpDeviceAction action;
|
||||||
|
|
||||||
|
g_return_if_fail (priv->active == TRUE);
|
||||||
|
g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE);
|
||||||
|
|
||||||
|
g_debug ("Image device deactivation completed");
|
||||||
|
|
||||||
|
priv->active = FALSE;
|
||||||
|
|
||||||
|
/* Deactivation completed. As we deactivate in the background
|
||||||
|
* there may already be a new task pending. Check whether we
|
||||||
|
* need to do anything. */
|
||||||
|
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||||
|
|
||||||
|
/* Special case, if we should be closing, but didn't due to a running
|
||||||
|
* deactivation, then do so now. */
|
||||||
|
if (action == FP_DEVICE_ACTION_CLOSE)
|
||||||
|
{
|
||||||
|
cls->img_close (self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We might be waiting to be able to activate again. */
|
||||||
|
if (priv->pending_activation_timeout_id)
|
||||||
|
fp_image_device_activate (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_image_device_open_complete:
|
||||||
|
* @self: a #FpImageDevice imaging fingerprint device
|
||||||
|
* @error: A #GError or %NULL on success
|
||||||
|
*
|
||||||
|
* Reports completion of open operation.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_image_device_open_complete (FpImageDevice *self, GError *error)
|
||||||
|
{
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpDeviceAction action;
|
||||||
|
|
||||||
|
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||||
|
|
||||||
|
g_return_if_fail (priv->active == FALSE);
|
||||||
|
g_return_if_fail (action == FP_DEVICE_ACTION_OPEN);
|
||||||
|
|
||||||
|
g_debug ("Image device open completed");
|
||||||
|
|
||||||
|
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
|
||||||
|
|
||||||
|
fpi_device_open_complete (FP_DEVICE (self), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_image_device_close_complete:
|
||||||
|
* @self: a #FpImageDevice imaging fingerprint device
|
||||||
|
* @error: A #GError or %NULL on success
|
||||||
|
*
|
||||||
|
* Reports completion of close operation.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_image_device_close_complete (FpImageDevice *self, GError *error)
|
||||||
|
{
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpDeviceAction action;
|
||||||
|
|
||||||
|
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||||
|
|
||||||
|
g_debug ("Image device close completed");
|
||||||
|
|
||||||
|
g_return_if_fail (priv->active == FALSE);
|
||||||
|
g_return_if_fail (action == FP_DEVICE_ACTION_CLOSE);
|
||||||
|
|
||||||
|
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
|
||||||
|
|
||||||
|
fpi_device_close_complete (FP_DEVICE (self), error);
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
* FpImageDevice - An image based fingerprint reader device
|
||||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -17,18 +17,13 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __FPI_DATA_H__
|
#pragma once
|
||||||
#define __FPI_DATA_H__
|
|
||||||
|
|
||||||
struct fp_print_data;
|
#include <fp-device.h>
|
||||||
struct fp_print_data_item {
|
|
||||||
size_t length;
|
|
||||||
unsigned char data[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev);
|
G_BEGIN_DECLS
|
||||||
struct fp_print_data_item *fpi_print_data_item_new(size_t length);
|
|
||||||
struct fp_print_data_item *fpi_print_data_get_item(struct fp_print_data *data);
|
|
||||||
void fpi_print_data_add_item(struct fp_print_data *data, struct fp_print_data_item *item);
|
|
||||||
|
|
||||||
#endif
|
#define FP_TYPE_IMAGE_DEVICE (fp_image_device_get_type ())
|
||||||
|
G_DECLARE_DERIVABLE_TYPE (FpImageDevice, fp_image_device, FP, IMAGE_DEVICE, FpDevice)
|
||||||
|
|
||||||
|
G_END_DECLS
|
610
libfprint/fp-image.c
Normal file
610
libfprint/fp-image.c
Normal file
|
@ -0,0 +1,610 @@
|
||||||
|
/*
|
||||||
|
* FPrint Image
|
||||||
|
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fpi-image.h"
|
||||||
|
|
||||||
|
#include "nbis/include/lfs.h"
|
||||||
|
|
||||||
|
#if HAVE_PIXMAN
|
||||||
|
#include <pixman.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION: fp-image
|
||||||
|
* @title: FpImage
|
||||||
|
* @short_description: Internal Image handling routines
|
||||||
|
*
|
||||||
|
* Some devices will provide the image data corresponding to a print
|
||||||
|
* this object allows accessing this data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION: fpi-image
|
||||||
|
* @title: Internal FpImage
|
||||||
|
* @short_description: Internal image handling routines
|
||||||
|
*
|
||||||
|
* Internal image handling routines. Also see the public <ulink
|
||||||
|
* url="libfprint-FpImage.html">FpImage routines</ulink>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (FpImage, fp_image, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_0,
|
||||||
|
PROP_WIDTH,
|
||||||
|
PROP_HEIGHT,
|
||||||
|
N_PROPS
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *properties[N_PROPS];
|
||||||
|
|
||||||
|
FpImage *
|
||||||
|
fp_image_new (gint width, gint height)
|
||||||
|
{
|
||||||
|
return g_object_new (FP_TYPE_IMAGE,
|
||||||
|
"width", width,
|
||||||
|
"height", height,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
FpImage *self = (FpImage *) object;
|
||||||
|
|
||||||
|
g_clear_pointer (&self->data, g_free);
|
||||||
|
g_clear_pointer (&self->binarized, g_free);
|
||||||
|
g_clear_pointer (&self->minutiae, g_ptr_array_unref);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (fp_image_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_constructed (GObject *object)
|
||||||
|
{
|
||||||
|
FpImage *self = (FpImage *) object;
|
||||||
|
|
||||||
|
self->data = g_malloc0 (self->width * self->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_get_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
FpImage *self = FP_IMAGE (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_WIDTH:
|
||||||
|
g_value_set_uint (value, self->width);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROP_HEIGHT:
|
||||||
|
g_value_set_uint (value, self->height);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_set_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
FpImage *self = FP_IMAGE (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_WIDTH:
|
||||||
|
self->width = g_value_get_uint (value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROP_HEIGHT:
|
||||||
|
self->height = g_value_get_uint (value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_class_init (FpImageClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = fp_image_finalize;
|
||||||
|
object_class->constructed = fp_image_constructed;
|
||||||
|
object_class->set_property = fp_image_set_property;
|
||||||
|
object_class->get_property = fp_image_get_property;
|
||||||
|
|
||||||
|
properties[PROP_WIDTH] =
|
||||||
|
g_param_spec_uint ("width",
|
||||||
|
"Width",
|
||||||
|
"The width of the image",
|
||||||
|
0,
|
||||||
|
G_MAXUINT16,
|
||||||
|
0,
|
||||||
|
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||||
|
|
||||||
|
properties[PROP_HEIGHT] =
|
||||||
|
g_param_spec_uint ("height",
|
||||||
|
"Height",
|
||||||
|
"The height of the image",
|
||||||
|
0,
|
||||||
|
G_MAXUINT16,
|
||||||
|
0,
|
||||||
|
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||||
|
|
||||||
|
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_init (FpImage *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GAsyncReadyCallback user_cb;
|
||||||
|
struct fp_minutiae *minutiae;
|
||||||
|
gint width, height;
|
||||||
|
gdouble ppmm;
|
||||||
|
FpiImageFlags flags;
|
||||||
|
guchar *image;
|
||||||
|
guchar *binarized;
|
||||||
|
} DetectMinutiaeData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_detect_minutiae_free (DetectMinutiaeData *data)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&data->image, g_free);
|
||||||
|
g_clear_pointer (&data->minutiae, free_minutiae);
|
||||||
|
g_clear_pointer (&data->binarized, g_free);
|
||||||
|
g_free (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_detect_minutiae_cb (GObject *source_object,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GTask *task = G_TASK (res);
|
||||||
|
FpImage *image;
|
||||||
|
DetectMinutiaeData *data = g_task_get_task_data (task);
|
||||||
|
GCancellable *cancellable;
|
||||||
|
|
||||||
|
cancellable = g_task_get_cancellable (task);
|
||||||
|
if (!cancellable || !g_cancellable_is_cancelled (cancellable))
|
||||||
|
{
|
||||||
|
gint i;
|
||||||
|
image = FP_IMAGE (source_object);
|
||||||
|
|
||||||
|
image->flags = data->flags;
|
||||||
|
|
||||||
|
g_clear_pointer (&image->data, g_free);
|
||||||
|
image->data = g_steal_pointer (&data->image);
|
||||||
|
|
||||||
|
g_clear_pointer (&image->binarized, g_free);
|
||||||
|
image->binarized = g_steal_pointer (&data->binarized);
|
||||||
|
|
||||||
|
g_clear_pointer (&image->minutiae, g_ptr_array_unref);
|
||||||
|
image->minutiae = g_ptr_array_new_full (data->minutiae->num,
|
||||||
|
(GDestroyNotify) free_minutia);
|
||||||
|
|
||||||
|
for (i = 0; i < data->minutiae->num; i++)
|
||||||
|
g_ptr_array_add (image->minutiae,
|
||||||
|
g_steal_pointer (&data->minutiae->list[i]));
|
||||||
|
|
||||||
|
/* Don't let it delete anything. */
|
||||||
|
data->minutiae->num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->user_cb)
|
||||||
|
data->user_cb (source_object, res, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vflip (guint8 *data, gint width, gint height)
|
||||||
|
{
|
||||||
|
int data_len = width * height;
|
||||||
|
unsigned char rowbuf[width];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < height / 2; i++)
|
||||||
|
{
|
||||||
|
int offset = i * width;
|
||||||
|
int swap_offset = data_len - (width * (i + 1));
|
||||||
|
|
||||||
|
/* copy top row into buffer */
|
||||||
|
memcpy (rowbuf, data + offset, width);
|
||||||
|
|
||||||
|
/* copy lower row over upper row */
|
||||||
|
memcpy (data + offset, data + swap_offset, width);
|
||||||
|
|
||||||
|
/* copy buffer over lower row */
|
||||||
|
memcpy (data + swap_offset, rowbuf, width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hflip (guint8 *data, gint width, gint height)
|
||||||
|
{
|
||||||
|
unsigned char rowbuf[width];
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
int offset = i * width;
|
||||||
|
|
||||||
|
memcpy (rowbuf, data + offset, width);
|
||||||
|
for (j = 0; j < width; j++)
|
||||||
|
data[offset + j] = rowbuf[width - j - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
invert_colors (guint8 *data, gint width, gint height)
|
||||||
|
{
|
||||||
|
int data_len = width * height;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < data_len; i++)
|
||||||
|
data[i] = 0xff - data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_detect_minutiae_thread_func (GTask *task,
|
||||||
|
gpointer source_object,
|
||||||
|
gpointer task_data,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
g_autoptr(GTimer) timer = NULL;
|
||||||
|
DetectMinutiaeData *data = task_data;
|
||||||
|
struct fp_minutiae *minutiae = NULL;
|
||||||
|
g_autofree gint *direction_map = NULL;
|
||||||
|
g_autofree gint *low_contrast_map = NULL;
|
||||||
|
g_autofree gint *low_flow_map = NULL;
|
||||||
|
g_autofree gint *high_curve_map = NULL;
|
||||||
|
g_autofree gint *quality_map = NULL;
|
||||||
|
g_autofree guchar *bdata = NULL;
|
||||||
|
gint map_w, map_h;
|
||||||
|
gint bw, bh, bd;
|
||||||
|
gint r;
|
||||||
|
|
||||||
|
/* Normalize the image first */
|
||||||
|
if (data->flags & FPI_IMAGE_H_FLIPPED)
|
||||||
|
hflip (data->image, data->width, data->height);
|
||||||
|
|
||||||
|
if (data->flags & FPI_IMAGE_V_FLIPPED)
|
||||||
|
vflip (data->image, data->width, data->height);
|
||||||
|
|
||||||
|
if (data->flags & FPI_IMAGE_COLORS_INVERTED)
|
||||||
|
invert_colors (data->image, data->width, data->height);
|
||||||
|
|
||||||
|
data->flags &= ~(FPI_IMAGE_H_FLIPPED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_COLORS_INVERTED);
|
||||||
|
|
||||||
|
timer = g_timer_new ();
|
||||||
|
r = get_minutiae (&minutiae, &quality_map, &direction_map,
|
||||||
|
&low_contrast_map, &low_flow_map, &high_curve_map,
|
||||||
|
&map_w, &map_h, &bdata, &bw, &bh, &bd,
|
||||||
|
data->image, data->width, data->height, 8,
|
||||||
|
data->ppmm, &g_lfsparms_V2);
|
||||||
|
g_timer_stop (timer);
|
||||||
|
fp_dbg ("Minutiae scan completed in %f secs", g_timer_elapsed (timer, NULL));
|
||||||
|
|
||||||
|
data->binarized = g_steal_pointer (&bdata);
|
||||||
|
data->minutiae = minutiae;
|
||||||
|
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
fp_err ("get minutiae failed, code %d", r);
|
||||||
|
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Minutiae scan failed with code %d", r);
|
||||||
|
g_object_unref (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_image_get_height:
|
||||||
|
* @self: A #FpImage
|
||||||
|
*
|
||||||
|
* Gets the pixel height of an image.
|
||||||
|
*
|
||||||
|
* Returns: the height of the image
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
fp_image_get_height (FpImage *self)
|
||||||
|
{
|
||||||
|
return self->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_image_get_width:
|
||||||
|
* @self: A #FpImage
|
||||||
|
*
|
||||||
|
* Gets the pixel width of an image.
|
||||||
|
*
|
||||||
|
* Returns: the width of the image
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
fp_image_get_width (FpImage *self)
|
||||||
|
{
|
||||||
|
return self->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_image_get_ppmm:
|
||||||
|
* @self: A #FpImage
|
||||||
|
*
|
||||||
|
* Gets the resolution of the image. Note that this is assumed to
|
||||||
|
* be fixed to 500 points per inch (~19.685 p/mm) for most drivers.
|
||||||
|
*
|
||||||
|
* Returns: the resolution of the image in points per millimeter
|
||||||
|
*/
|
||||||
|
gdouble
|
||||||
|
fp_image_get_ppmm (FpImage *self)
|
||||||
|
{
|
||||||
|
return self->ppmm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_image_get_data:
|
||||||
|
* @self: A #FpImage
|
||||||
|
* @len: (out) (optional): Return location for length or %NULL
|
||||||
|
*
|
||||||
|
* Gets the greyscale data for an image. This data must not be modified or
|
||||||
|
* freed.
|
||||||
|
*
|
||||||
|
* Returns: (transfer none) (array length=len): The image data
|
||||||
|
*/
|
||||||
|
const guchar *
|
||||||
|
fp_image_get_data (FpImage *self, gsize *len)
|
||||||
|
{
|
||||||
|
if (len)
|
||||||
|
*len = self->width * self->height;
|
||||||
|
|
||||||
|
return self->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_image_get_binarized:
|
||||||
|
* @self: A #FpImage
|
||||||
|
* @len: (out) (optional): Return location for length or %NULL
|
||||||
|
*
|
||||||
|
* Gets the binarized data for an image. This data must not be modified or
|
||||||
|
* freed. You need to first detect the minutiae using
|
||||||
|
* fp_image_detect_minutiae().
|
||||||
|
*
|
||||||
|
* Returns: (transfer none) (array length=len): The binarized image data
|
||||||
|
*/
|
||||||
|
const guchar *
|
||||||
|
fp_image_get_binarized (FpImage *self, gsize *len)
|
||||||
|
{
|
||||||
|
if (len && self->binarized)
|
||||||
|
*len = self->width * self->height;
|
||||||
|
|
||||||
|
return self->binarized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_image_get_minutiae:
|
||||||
|
* @self: A #FpImage
|
||||||
|
*
|
||||||
|
* Gets the minutiae for an image. This data must not be modified or
|
||||||
|
* freed. You need to first detect the minutiae using
|
||||||
|
* fp_image_detect_minutiae().
|
||||||
|
*
|
||||||
|
* Returns: (transfer none) (element-type FpMinutia): The detected minutiae
|
||||||
|
*/
|
||||||
|
GPtrArray *
|
||||||
|
fp_image_get_minutiae (FpImage *self)
|
||||||
|
{
|
||||||
|
return self->minutiae;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_image_detect_minutiae:
|
||||||
|
* @self: A #FpImage
|
||||||
|
* @cancellable: a #GCancellable, or %NULL
|
||||||
|
* @callback: the function to call on completion
|
||||||
|
* @user_data: the data to pass to @callback
|
||||||
|
*
|
||||||
|
* Detects the minutiae found in an image.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fp_image_detect_minutiae (FpImage *self,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GTask *task;
|
||||||
|
DetectMinutiaeData *data = g_new0 (DetectMinutiaeData, 1);
|
||||||
|
|
||||||
|
task = g_task_new (self, cancellable, fp_image_detect_minutiae_cb, user_data);
|
||||||
|
|
||||||
|
data->image = g_malloc (self->width * self->height);
|
||||||
|
memcpy (data->image, self->data, self->width * self->height);
|
||||||
|
data->flags = self->flags;
|
||||||
|
data->width = self->width;
|
||||||
|
data->height = self->height;
|
||||||
|
data->ppmm = self->ppmm;
|
||||||
|
data->user_cb = callback;
|
||||||
|
|
||||||
|
g_task_set_task_data (task, data, (GDestroyNotify) fp_image_detect_minutiae_free);
|
||||||
|
g_task_run_in_thread (task, fp_image_detect_minutiae_thread_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_image_detect_minutiae_finish:
|
||||||
|
* @self: A #FpImage
|
||||||
|
* @result: A #GAsyncResult
|
||||||
|
* @error: Return location for errors, or %NULL to ignore
|
||||||
|
*
|
||||||
|
* Finish minutiae detection in an image
|
||||||
|
*
|
||||||
|
* Returns: %TRUE on success
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
fp_image_detect_minutiae_finish (FpImage *self,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return g_task_propagate_boolean (G_TASK (result), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_std_sq_dev:
|
||||||
|
* @buf: buffer (usually bitmap, one byte per pixel)
|
||||||
|
* @size: size of @buffer
|
||||||
|
*
|
||||||
|
* Calculates the squared standard deviation of the individual
|
||||||
|
* pixels in the buffer, as per the following formula:
|
||||||
|
* |[<!-- -->
|
||||||
|
* mean = sum (buf[0..size]) / size
|
||||||
|
* sq_dev = sum ((buf[0.size] - mean) ^ 2)
|
||||||
|
* ]|
|
||||||
|
* This function is usually used to determine whether image
|
||||||
|
* is empty.
|
||||||
|
*
|
||||||
|
* Returns: the squared standard deviation for @buffer
|
||||||
|
*/
|
||||||
|
gint
|
||||||
|
fpi_std_sq_dev (const guint8 *buf,
|
||||||
|
gint size)
|
||||||
|
{
|
||||||
|
guint64 res = 0, mean = 0;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
mean += buf[i];
|
||||||
|
|
||||||
|
mean /= size;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
int dev = (int) buf[i] - mean;
|
||||||
|
res += dev * dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res / size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_mean_sq_diff_norm:
|
||||||
|
* @buf1: buffer (usually bitmap, one byte per pixel)
|
||||||
|
* @buf2: buffer (usually bitmap, one byte per pixel)
|
||||||
|
* @size: buffer size of smallest buffer
|
||||||
|
*
|
||||||
|
* This function calculates the normalized mean square difference of
|
||||||
|
* two buffers, usually two lines, as per the following formula:
|
||||||
|
* |[<!-- -->
|
||||||
|
* sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* This functions is usually used to get numerical difference
|
||||||
|
* between two images.
|
||||||
|
*
|
||||||
|
* Returns: the normalized mean squared difference between @buf1 and @buf2
|
||||||
|
*/
|
||||||
|
gint
|
||||||
|
fpi_mean_sq_diff_norm (const guint8 *buf1,
|
||||||
|
const guint8 *buf2,
|
||||||
|
gint size)
|
||||||
|
{
|
||||||
|
int res = 0, i;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
int dev = (int) buf1[i] - (int) buf2[i];
|
||||||
|
res += dev * dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res / size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_minutia_get_coords:
|
||||||
|
* @min: A #FpMinutia
|
||||||
|
* @x: (out): x position in image
|
||||||
|
* @y: (out): y position in image
|
||||||
|
*
|
||||||
|
* Returns the coordinates of the found minutia. This is only useful for
|
||||||
|
* debugging purposes and the API is not considered stable for production.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fp_minutia_get_coords (FpMinutia *min, gint *x, gint *y)
|
||||||
|
{
|
||||||
|
if (x)
|
||||||
|
*x = min->x;
|
||||||
|
if (y)
|
||||||
|
*y = min->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_PIXMAN
|
||||||
|
FpImage *
|
||||||
|
fpi_image_resize (FpImage *orig_img,
|
||||||
|
guint w_factor,
|
||||||
|
guint h_factor)
|
||||||
|
{
|
||||||
|
int new_width = orig_img->width * w_factor;
|
||||||
|
int new_height = orig_img->height * h_factor;
|
||||||
|
pixman_image_t *orig, *resized;
|
||||||
|
pixman_transform_t transform;
|
||||||
|
FpImage *newimg;
|
||||||
|
|
||||||
|
orig = pixman_image_create_bits (PIXMAN_a8, orig_img->width, orig_img->height, (uint32_t *) orig_img->data, orig_img->width);
|
||||||
|
resized = pixman_image_create_bits (PIXMAN_a8, new_width, new_height, NULL, new_width);
|
||||||
|
|
||||||
|
pixman_transform_init_identity (&transform);
|
||||||
|
pixman_transform_scale (NULL, &transform, pixman_int_to_fixed (w_factor), pixman_int_to_fixed (h_factor));
|
||||||
|
pixman_image_set_transform (orig, &transform);
|
||||||
|
pixman_image_set_filter (orig, PIXMAN_FILTER_BILINEAR, NULL, 0);
|
||||||
|
pixman_image_composite32 (PIXMAN_OP_SRC,
|
||||||
|
orig, /* src */
|
||||||
|
NULL, /* mask */
|
||||||
|
resized, /* dst */
|
||||||
|
0, 0, /* src x y */
|
||||||
|
0, 0, /* mask x y */
|
||||||
|
0, 0, /* dst x y */
|
||||||
|
new_width, new_height /* width height */
|
||||||
|
);
|
||||||
|
|
||||||
|
newimg = fp_image_new (new_width, new_height);
|
||||||
|
newimg->flags = orig_img->flags;
|
||||||
|
|
||||||
|
memcpy (newimg->data, pixman_image_get_data (resized), new_width * new_height);
|
||||||
|
|
||||||
|
pixman_image_unref (orig);
|
||||||
|
pixman_image_unref (resized);
|
||||||
|
|
||||||
|
return newimg;
|
||||||
|
}
|
||||||
|
#endif
|
59
libfprint/fp-image.h
Normal file
59
libfprint/fp-image.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* FPrint Image
|
||||||
|
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define FP_TYPE_IMAGE (fp_image_get_type ())
|
||||||
|
|
||||||
|
typedef struct fp_minutia FpMinutia;
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (FpImage, fp_image, FP, IMAGE, GObject)
|
||||||
|
|
||||||
|
FpImage *fp_image_new (gint width,
|
||||||
|
gint height);
|
||||||
|
|
||||||
|
guint fp_image_get_width (FpImage *self);
|
||||||
|
guint fp_image_get_height (FpImage *self);
|
||||||
|
gdouble fp_image_get_ppmm (FpImage *self);
|
||||||
|
|
||||||
|
GPtrArray * fp_image_get_minutiae (FpImage *self);
|
||||||
|
|
||||||
|
void fp_image_detect_minutiae (FpImage *self,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
gboolean fp_image_detect_minutiae_finish (FpImage *self,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
const guchar * fp_image_get_data (FpImage *self,
|
||||||
|
gsize *len);
|
||||||
|
const guchar * fp_image_get_binarized (FpImage *self,
|
||||||
|
gsize *len);
|
||||||
|
|
||||||
|
void fp_minutia_get_coords (FpMinutia *min,
|
||||||
|
gint *x,
|
||||||
|
gint *y);
|
||||||
|
|
||||||
|
G_END_DECLS
|
1118
libfprint/fp-print.c
Normal file
1118
libfprint/fp-print.c
Normal file
File diff suppressed because it is too large
Load diff
101
libfprint/fp-print.h
Normal file
101
libfprint/fp-print.h
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* FPrint Print handling
|
||||||
|
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "fp-image.h"
|
||||||
|
#include "fp-enums.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define FP_TYPE_PRINT (fp_print_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (FpPrint, fp_print, FP, PRINT, GInitiallyUnowned)
|
||||||
|
|
||||||
|
#include "fp-device.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpFinger:
|
||||||
|
* @FP_FINGER_UNKNOWN: The finger is unknown
|
||||||
|
* @FP_FINGER_LEFT_THUMB: Left thumb
|
||||||
|
* @FP_FINGER_LEFT_INDEX: Left index finger
|
||||||
|
* @FP_FINGER_LEFT_MIDDLE: Left middle finger
|
||||||
|
* @FP_FINGER_LEFT_RING: Left ring finger
|
||||||
|
* @FP_FINGER_LEFT_LITTLE: Left little finger
|
||||||
|
* @FP_FINGER_RIGHT_THUMB: Right thumb
|
||||||
|
* @FP_FINGER_RIGHT_INDEX: Right index finger
|
||||||
|
* @FP_FINGER_RIGHT_MIDDLE: Right middle finger
|
||||||
|
* @FP_FINGER_RIGHT_RING: Right ring finger
|
||||||
|
* @FP_FINGER_RIGHT_LITTLE: Right little finger
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FP_FINGER_UNKNOWN = 0,
|
||||||
|
FP_FINGER_LEFT_THUMB,
|
||||||
|
FP_FINGER_LEFT_INDEX,
|
||||||
|
FP_FINGER_LEFT_MIDDLE,
|
||||||
|
FP_FINGER_LEFT_RING,
|
||||||
|
FP_FINGER_LEFT_LITTLE,
|
||||||
|
FP_FINGER_RIGHT_THUMB,
|
||||||
|
FP_FINGER_RIGHT_INDEX,
|
||||||
|
FP_FINGER_RIGHT_MIDDLE,
|
||||||
|
FP_FINGER_RIGHT_RING,
|
||||||
|
FP_FINGER_RIGHT_LITTLE,
|
||||||
|
} FpFinger;
|
||||||
|
|
||||||
|
FpPrint *fp_print_new (FpDevice *device);
|
||||||
|
|
||||||
|
FpPrint *fp_print_new_from_data (guchar *data,
|
||||||
|
gsize length);
|
||||||
|
gboolean fp_print_to_data (guchar **data,
|
||||||
|
gsize length);
|
||||||
|
|
||||||
|
const gchar *fp_print_get_driver (FpPrint *print);
|
||||||
|
const gchar *fp_print_get_device_id (FpPrint *print);
|
||||||
|
FpImage *fp_print_get_image (FpPrint *print);
|
||||||
|
|
||||||
|
FpFinger fp_print_get_finger (FpPrint *print);
|
||||||
|
const gchar *fp_print_get_username (FpPrint *print);
|
||||||
|
const gchar *fp_print_get_description (FpPrint *print);
|
||||||
|
const GDate *fp_print_get_enroll_date (FpPrint *print);
|
||||||
|
gboolean fp_print_get_device_stored (FpPrint *print);
|
||||||
|
|
||||||
|
void fp_print_set_finger (FpPrint *print,
|
||||||
|
FpFinger finger);
|
||||||
|
void fp_print_set_username (FpPrint *print,
|
||||||
|
const gchar *username);
|
||||||
|
void fp_print_set_description (FpPrint *print,
|
||||||
|
const gchar *description);
|
||||||
|
void fp_print_set_enroll_date (FpPrint *print,
|
||||||
|
const GDate *enroll_date);
|
||||||
|
|
||||||
|
gboolean fp_print_compatible (FpPrint *self,
|
||||||
|
FpDevice *device);
|
||||||
|
gboolean fp_print_equal (FpPrint *self,
|
||||||
|
FpPrint *other);
|
||||||
|
|
||||||
|
gboolean fp_print_serialize (FpPrint *print,
|
||||||
|
guchar **data,
|
||||||
|
gsize *length,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
FpPrint *fp_print_deserialize (const guchar *data,
|
||||||
|
gsize length,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
G_END_DECLS
|
|
@ -20,147 +20,10 @@
|
||||||
#ifndef __FPRINT_INTERNAL_H__
|
#ifndef __FPRINT_INTERNAL_H__
|
||||||
#define __FPRINT_INTERNAL_H__
|
#define __FPRINT_INTERNAL_H__
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include "nbis-helpers.h"
|
|
||||||
#include "fprint.h"
|
|
||||||
#include "fpi-dev.h"
|
|
||||||
#include "fpi-core.h"
|
|
||||||
#include "fpi-log.h"
|
#include "fpi-log.h"
|
||||||
#include "fpi-dev-img.h"
|
#include "nbis-helpers.h"
|
||||||
#include "fpi-data.h"
|
#include "fpi-image.h"
|
||||||
#include "fpi-img.h"
|
#include "fpi-image-device.h"
|
||||||
#include "drivers/driver_ids.h"
|
|
||||||
|
|
||||||
/* Global variables */
|
|
||||||
extern libusb_context *fpi_usb_ctx;
|
|
||||||
extern GSList *opened_devices;
|
|
||||||
|
|
||||||
/* fp_print_data structure definition */
|
|
||||||
enum fp_print_data_type {
|
|
||||||
PRINT_DATA_RAW = 0, /* memset-imposed default */
|
|
||||||
PRINT_DATA_NBIS_MINUTIAE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fp_print_data {
|
|
||||||
uint16_t driver_id;
|
|
||||||
uint32_t devtype;
|
|
||||||
enum fp_print_data_type type;
|
|
||||||
GSList *prints;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* fp_dev structure definition */
|
|
||||||
enum fp_dev_state {
|
|
||||||
DEV_STATE_INITIAL = 0,
|
|
||||||
DEV_STATE_ERROR,
|
|
||||||
DEV_STATE_INITIALIZING,
|
|
||||||
DEV_STATE_INITIALIZED,
|
|
||||||
DEV_STATE_DEINITIALIZING,
|
|
||||||
DEV_STATE_DEINITIALIZED,
|
|
||||||
DEV_STATE_ENROLL_STARTING,
|
|
||||||
DEV_STATE_ENROLLING,
|
|
||||||
DEV_STATE_ENROLL_STOPPING,
|
|
||||||
DEV_STATE_VERIFY_STARTING,
|
|
||||||
DEV_STATE_VERIFYING,
|
|
||||||
DEV_STATE_VERIFY_DONE,
|
|
||||||
DEV_STATE_VERIFY_STOPPING,
|
|
||||||
DEV_STATE_IDENTIFY_STARTING,
|
|
||||||
DEV_STATE_IDENTIFYING,
|
|
||||||
DEV_STATE_IDENTIFY_DONE,
|
|
||||||
DEV_STATE_IDENTIFY_STOPPING,
|
|
||||||
DEV_STATE_CAPTURE_STARTING,
|
|
||||||
DEV_STATE_CAPTURING,
|
|
||||||
DEV_STATE_CAPTURE_DONE,
|
|
||||||
DEV_STATE_CAPTURE_STOPPING,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fp_dev {
|
|
||||||
struct fp_driver *drv;
|
|
||||||
uint32_t devtype;
|
|
||||||
|
|
||||||
/* only valid if drv->type == DRIVER_IMAGING */
|
|
||||||
struct fp_img_dev *img_dev;
|
|
||||||
/* Link to the instance specific struct */
|
|
||||||
void *instance_data;
|
|
||||||
|
|
||||||
int nr_enroll_stages;
|
|
||||||
|
|
||||||
/* FIXME: This will eventually have a bus type */
|
|
||||||
libusb_device_handle *udev;
|
|
||||||
|
|
||||||
/* read-only to drivers */
|
|
||||||
struct fp_print_data *verify_data;
|
|
||||||
|
|
||||||
/* drivers should not mess with any of the below */
|
|
||||||
enum fp_dev_state state;
|
|
||||||
int __enroll_stage;
|
|
||||||
int unconditional_capture;
|
|
||||||
|
|
||||||
/* async I/O callbacks and data */
|
|
||||||
/* FIXME: convert this to generic state operational data mechanism? */
|
|
||||||
fp_dev_open_cb open_cb;
|
|
||||||
void *open_cb_data;
|
|
||||||
fp_operation_stop_cb close_cb;
|
|
||||||
void *close_cb_data;
|
|
||||||
fp_enroll_stage_cb enroll_stage_cb;
|
|
||||||
void *enroll_stage_cb_data;
|
|
||||||
fp_operation_stop_cb enroll_stop_cb;
|
|
||||||
void *enroll_stop_cb_data;
|
|
||||||
fp_img_operation_cb verify_cb;
|
|
||||||
void *verify_cb_data;
|
|
||||||
fp_operation_stop_cb verify_stop_cb;
|
|
||||||
void *verify_stop_cb_data;
|
|
||||||
fp_identify_cb identify_cb;
|
|
||||||
void *identify_cb_data;
|
|
||||||
fp_operation_stop_cb identify_stop_cb;
|
|
||||||
void *identify_stop_cb_data;
|
|
||||||
fp_img_operation_cb capture_cb;
|
|
||||||
void *capture_cb_data;
|
|
||||||
fp_operation_stop_cb capture_stop_cb;
|
|
||||||
void *capture_stop_cb_data;
|
|
||||||
|
|
||||||
/* FIXME: better place to put this? */
|
|
||||||
struct fp_print_data **identify_gallery;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* fp_img_dev structure definition */
|
|
||||||
struct fp_img_dev {
|
|
||||||
struct fp_dev *parent;
|
|
||||||
|
|
||||||
enum fp_imgdev_action action;
|
|
||||||
int action_state;
|
|
||||||
|
|
||||||
struct fp_print_data *acquire_data;
|
|
||||||
struct fp_print_data *enroll_data;
|
|
||||||
struct fp_img *acquire_img;
|
|
||||||
int enroll_stage;
|
|
||||||
int action_result;
|
|
||||||
|
|
||||||
/* FIXME: better place to put this? */
|
|
||||||
size_t identify_match_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* fp_driver structure definition */
|
|
||||||
|
|
||||||
/* fp_img_driver structure definition */
|
|
||||||
#define container_of(ptr, type, member) ({ \
|
|
||||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
|
||||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
|
||||||
#define fpi_driver_to_img_driver(drv) \
|
|
||||||
container_of((drv), struct fp_img_driver, driver)
|
|
||||||
|
|
||||||
/* fp_dscv_dev structure definition */
|
|
||||||
struct fp_dscv_dev {
|
|
||||||
struct libusb_device *udev;
|
|
||||||
struct fp_driver *drv;
|
|
||||||
unsigned long driver_data;
|
|
||||||
uint32_t devtype;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* fp_minutia structure definition */
|
/* fp_minutia structure definition */
|
||||||
struct fp_minutia {
|
struct fp_minutia {
|
||||||
|
@ -185,48 +48,5 @@ struct fp_minutiae {
|
||||||
struct fp_minutia **list;
|
struct fp_minutia **list;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Defined in fpi-dev-img.c */
|
|
||||||
void fpi_img_driver_setup(struct fp_img_driver *idriver);
|
|
||||||
int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev);
|
|
||||||
int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev);
|
|
||||||
|
|
||||||
/* Exported for use in command-line tools
|
|
||||||
* Defined in fpi-core.c */
|
|
||||||
struct fp_driver **fprint_get_drivers (void);
|
|
||||||
|
|
||||||
/* Defined in fpi-core.c */
|
|
||||||
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv);
|
|
||||||
|
|
||||||
/* Defined in fpi-data.c */
|
|
||||||
gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1,
|
|
||||||
enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2,
|
|
||||||
enum fp_print_data_type type2);
|
|
||||||
|
|
||||||
/* Defined in fpi-img.c */
|
|
||||||
gboolean fpi_img_is_sane(struct fp_img *img);
|
|
||||||
int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
|
|
||||||
struct fp_print_data **ret);
|
|
||||||
int fpi_img_compare_print_data(struct fp_print_data *enrolled_print,
|
|
||||||
struct fp_print_data *new_print);
|
|
||||||
int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print,
|
|
||||||
struct fp_print_data **gallery, int match_threshold, size_t *match_offset);
|
|
||||||
|
|
||||||
/* Defined in fpi-poll.c */
|
|
||||||
void fpi_timeout_cancel_all_for_dev(struct fp_dev *dev);
|
|
||||||
void fpi_poll_init(void);
|
|
||||||
void fpi_poll_exit(void);
|
|
||||||
|
|
||||||
/* Defined in fpi-async.c */
|
|
||||||
void fpi_drvcb_capture_started(struct fp_dev *dev, int status);
|
|
||||||
void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
|
|
||||||
struct fp_img *img);
|
|
||||||
void fpi_drvcb_capture_stopped(struct fp_dev *dev);
|
|
||||||
|
|
||||||
void fpi_drvcb_identify_started(struct fp_dev *dev, int status);
|
|
||||||
void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
|
||||||
size_t match_offset, struct fp_img *img);
|
|
||||||
void fpi_drvcb_identify_stopped(struct fp_dev *dev);
|
|
||||||
|
|
||||||
#include "drivers_definitions.h"
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,12 +23,8 @@
|
||||||
|
|
||||||
#include "fp_internal.h"
|
#include "fp_internal.h"
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#include "fpi-assembling.h"
|
#include "fpi-assembling.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,7 +38,8 @@
|
||||||
* data in small stripes.
|
* data in small stripes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static unsigned int calc_error(struct fpi_frame_asmbl_ctx *ctx,
|
static unsigned int
|
||||||
|
calc_error (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
struct fpi_frame *first_frame,
|
struct fpi_frame *first_frame,
|
||||||
struct fpi_frame *second_frame,
|
struct fpi_frame *second_frame,
|
||||||
int dx,
|
int dx,
|
||||||
|
@ -58,27 +55,31 @@ static unsigned int calc_error(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
y2 = dy;
|
y2 = dy;
|
||||||
i = 0;
|
i = 0;
|
||||||
err = 0;
|
err = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
x1 = dx < 0 ? 0 : dx;
|
x1 = dx < 0 ? 0 : dx;
|
||||||
x2 = dx < 0 ? -dx : 0;
|
x2 = dx < 0 ? -dx : 0;
|
||||||
j = 0;
|
j = 0;
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
unsigned char v1, v2;
|
unsigned char v1, v2;
|
||||||
|
|
||||||
|
|
||||||
v1 = ctx->get_pixel(ctx, first_frame, x1, y1);
|
v1 = ctx->get_pixel (ctx, first_frame, x1, y1);
|
||||||
v2 = ctx->get_pixel(ctx, second_frame, x2, y2);
|
v2 = ctx->get_pixel (ctx, second_frame, x2, y2);
|
||||||
err += v1 > v2 ? v1 - v2 : v2 - v1;
|
err += v1 > v2 ? v1 - v2 : v2 - v1;
|
||||||
j++;
|
j++;
|
||||||
x1++;
|
x1++;
|
||||||
x2++;
|
x2++;
|
||||||
|
|
||||||
} while (j < width);
|
}
|
||||||
|
while (j < width);
|
||||||
i++;
|
i++;
|
||||||
y1++;
|
y1++;
|
||||||
y2++;
|
y2++;
|
||||||
} while (i < height);
|
}
|
||||||
|
while (i < height);
|
||||||
|
|
||||||
/* Normalize error */
|
/* Normalize error */
|
||||||
err *= (ctx->frame_height * ctx->frame_width);
|
err *= (ctx->frame_height * ctx->frame_width);
|
||||||
|
@ -93,13 +94,15 @@ static unsigned int calc_error(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
/* This function is rather CPU-intensive. It's better to use hardware
|
/* This function is rather CPU-intensive. It's better to use hardware
|
||||||
* to detect movement direction when possible.
|
* to detect movement direction when possible.
|
||||||
*/
|
*/
|
||||||
static void find_overlap(struct fpi_frame_asmbl_ctx *ctx,
|
static void
|
||||||
|
find_overlap (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
struct fpi_frame *first_frame,
|
struct fpi_frame *first_frame,
|
||||||
struct fpi_frame *second_frame,
|
struct fpi_frame *second_frame,
|
||||||
unsigned int *min_error)
|
unsigned int *min_error)
|
||||||
{
|
{
|
||||||
int dx, dy;
|
int dx, dy;
|
||||||
unsigned int err;
|
unsigned int err;
|
||||||
|
|
||||||
*min_error = 255 * ctx->frame_height * ctx->frame_width;
|
*min_error = 255 * ctx->frame_height * ctx->frame_width;
|
||||||
|
|
||||||
/* Seeking in horizontal and vertical dimensions,
|
/* Seeking in horizontal and vertical dimensions,
|
||||||
|
@ -107,11 +110,14 @@ static void find_overlap(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
* in both directions. For vertical direction diff is
|
* in both directions. For vertical direction diff is
|
||||||
* rarely less than 2, so start with it.
|
* rarely less than 2, so start with it.
|
||||||
*/
|
*/
|
||||||
for (dy = 2; dy < ctx->frame_height; dy++) {
|
for (dy = 2; dy < ctx->frame_height; dy++)
|
||||||
for (dx = -8; dx < 8; dx++) {
|
{
|
||||||
err = calc_error(ctx, first_frame, second_frame,
|
for (dx = -8; dx < 8; dx++)
|
||||||
|
{
|
||||||
|
err = calc_error (ctx, first_frame, second_frame,
|
||||||
dx, dy);
|
dx, dy);
|
||||||
if (err < *min_error) {
|
if (err < *min_error)
|
||||||
|
{
|
||||||
*min_error = err;
|
*min_error = err;
|
||||||
second_frame->delta_x = -dx;
|
second_frame->delta_x = -dx;
|
||||||
second_frame->delta_y = dy;
|
second_frame->delta_y = dy;
|
||||||
|
@ -120,7 +126,8 @@ static void find_overlap(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
static unsigned int
|
||||||
|
do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
GSList *stripes, size_t num_stripes,
|
GSList *stripes, size_t num_stripes,
|
||||||
gboolean reverse)
|
gboolean reverse)
|
||||||
{
|
{
|
||||||
|
@ -135,30 +142,35 @@ static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
*/
|
*/
|
||||||
unsigned long long total_error = 0;
|
unsigned long long total_error = 0;
|
||||||
|
|
||||||
list_entry = g_slist_next(list_entry);
|
list_entry = g_slist_next (list_entry);
|
||||||
|
|
||||||
timer = g_timer_new();
|
timer = g_timer_new ();
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
struct fpi_frame *cur_stripe = list_entry->data;
|
struct fpi_frame *cur_stripe = list_entry->data;
|
||||||
|
|
||||||
if (reverse) {
|
if (reverse)
|
||||||
find_overlap(ctx, prev_stripe, cur_stripe, &min_error);
|
{
|
||||||
|
find_overlap (ctx, prev_stripe, cur_stripe, &min_error);
|
||||||
cur_stripe->delta_y = -cur_stripe->delta_y;
|
cur_stripe->delta_y = -cur_stripe->delta_y;
|
||||||
cur_stripe->delta_x = -cur_stripe->delta_x;
|
cur_stripe->delta_x = -cur_stripe->delta_x;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
find_overlap(ctx, cur_stripe, prev_stripe, &min_error);
|
{
|
||||||
|
find_overlap (ctx, cur_stripe, prev_stripe, &min_error);
|
||||||
|
}
|
||||||
total_error += min_error;
|
total_error += min_error;
|
||||||
|
|
||||||
frame++;
|
frame++;
|
||||||
prev_stripe = cur_stripe;
|
prev_stripe = cur_stripe;
|
||||||
list_entry = g_slist_next(list_entry);
|
list_entry = g_slist_next (list_entry);
|
||||||
|
|
||||||
} while (frame < num_stripes);
|
}
|
||||||
|
while (frame < num_stripes);
|
||||||
|
|
||||||
g_timer_stop(timer);
|
g_timer_stop (timer);
|
||||||
fp_dbg("calc delta completed in %f secs", g_timer_elapsed(timer, NULL));
|
fp_dbg ("calc delta completed in %f secs", g_timer_elapsed (timer, NULL));
|
||||||
g_timer_destroy(timer);
|
g_timer_destroy (timer);
|
||||||
|
|
||||||
return total_error / num_stripes;
|
return total_error / num_stripes;
|
||||||
}
|
}
|
||||||
|
@ -179,20 +191,22 @@ static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
* Note that @num_stripes might be shorter than the length of the list,
|
* Note that @num_stripes might be shorter than the length of the list,
|
||||||
* if some stripes should be skipped.
|
* if some stripes should be skipped.
|
||||||
*/
|
*/
|
||||||
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
void
|
||||||
|
fpi_do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
GSList *stripes, size_t num_stripes)
|
GSList *stripes, size_t num_stripes)
|
||||||
{
|
{
|
||||||
int err, rev_err;
|
int err, rev_err;
|
||||||
err = do_movement_estimation(ctx, stripes, num_stripes, FALSE);
|
|
||||||
rev_err = do_movement_estimation(ctx, stripes, num_stripes, TRUE);
|
err = do_movement_estimation (ctx, stripes, num_stripes, FALSE);
|
||||||
fp_dbg("errors: %d rev: %d", err, rev_err);
|
rev_err = do_movement_estimation (ctx, stripes, num_stripes, TRUE);
|
||||||
if (err < rev_err) {
|
fp_dbg ("errors: %d rev: %d", err, rev_err);
|
||||||
do_movement_estimation(ctx, stripes, num_stripes, FALSE);
|
if (err < rev_err)
|
||||||
}
|
do_movement_estimation (ctx, stripes, num_stripes, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx,
|
static inline void
|
||||||
struct fp_img *img,
|
aes_blit_stripe (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
|
FpImage *img,
|
||||||
struct fpi_frame *stripe,
|
struct fpi_frame *stripe,
|
||||||
int x, int y)
|
int x, int y)
|
||||||
{
|
{
|
||||||
|
@ -201,11 +215,14 @@ static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
unsigned int width, height;
|
unsigned int width, height;
|
||||||
|
|
||||||
/* Find intersection */
|
/* Find intersection */
|
||||||
if (x < 0) {
|
if (x < 0)
|
||||||
|
{
|
||||||
width = ctx->frame_width + x;
|
width = ctx->frame_width + x;
|
||||||
ix = 0;
|
ix = 0;
|
||||||
fx = -x;
|
fx = -x;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ix = x;
|
ix = x;
|
||||||
fx = 0;
|
fx = 0;
|
||||||
width = ctx->frame_width;
|
width = ctx->frame_width;
|
||||||
|
@ -213,11 +230,14 @@ static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
if ((ix + width) > img->width)
|
if ((ix + width) > img->width)
|
||||||
width = img->width - ix;
|
width = img->width - ix;
|
||||||
|
|
||||||
if (y < 0) {
|
if (y < 0)
|
||||||
|
{
|
||||||
iy = 0;
|
iy = 0;
|
||||||
fy = -y;
|
fy = -y;
|
||||||
height = ctx->frame_height + y;
|
height = ctx->frame_height + y;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
iy = y;
|
iy = y;
|
||||||
fy = 0;
|
fy = 0;
|
||||||
height = ctx->frame_height;
|
height = ctx->frame_height;
|
||||||
|
@ -238,17 +258,20 @@ static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
if ((iy + height) > img->height)
|
if ((iy + height) > img->height)
|
||||||
height = img->height - iy;
|
height = img->height - iy;
|
||||||
|
|
||||||
for (; fy < height; fy++, iy++) {
|
for (; fy < height; fy++, iy++)
|
||||||
if (x < 0) {
|
{
|
||||||
|
if (x < 0)
|
||||||
|
{
|
||||||
ix = 0;
|
ix = 0;
|
||||||
fx = -x;
|
fx = -x;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ix = x;
|
ix = x;
|
||||||
fx = 0;
|
fx = 0;
|
||||||
}
|
}
|
||||||
for (; fx < width; fx++, ix++) {
|
for (; fx < width; fx++, ix++)
|
||||||
img->data[ix + (iy * img->width)] = ctx->get_pixel(ctx, stripe, fx, fy);
|
img->data[ix + (iy * img->width)] = ctx->get_pixel (ctx, stripe, fx, fy);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,19 +289,20 @@ static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
*
|
*
|
||||||
* Returns: a newly allocated #fp_img.
|
* Returns: a newly allocated #fp_img.
|
||||||
*/
|
*/
|
||||||
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
FpImage *
|
||||||
|
fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
GSList *stripes, size_t num_stripes)
|
GSList *stripes, size_t num_stripes)
|
||||||
{
|
{
|
||||||
GSList *stripe;
|
GSList *stripe;
|
||||||
struct fp_img *img;
|
FpImage *img;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
int i, y, x;
|
int i, y, x;
|
||||||
gboolean reverse = FALSE;
|
gboolean reverse = FALSE;
|
||||||
struct fpi_frame *fpi_frame;
|
struct fpi_frame *fpi_frame;
|
||||||
|
|
||||||
//FIXME g_return_if_fail
|
//FIXME g_return_if_fail
|
||||||
BUG_ON(num_stripes == 0);
|
BUG_ON (num_stripes == 0);
|
||||||
BUG_ON(ctx->image_width < ctx->frame_width);
|
BUG_ON (ctx->image_width < ctx->frame_width);
|
||||||
|
|
||||||
/* Calculate height */
|
/* Calculate height */
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -288,17 +312,20 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
fpi_frame = stripe->data;
|
fpi_frame = stripe->data;
|
||||||
fpi_frame->delta_x = 0;
|
fpi_frame->delta_x = 0;
|
||||||
fpi_frame->delta_y = 0;
|
fpi_frame->delta_y = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
fpi_frame = stripe->data;
|
fpi_frame = stripe->data;
|
||||||
|
|
||||||
height += fpi_frame->delta_y;
|
height += fpi_frame->delta_y;
|
||||||
i++;
|
i++;
|
||||||
stripe = g_slist_next(stripe);
|
stripe = g_slist_next (stripe);
|
||||||
} while (i < num_stripes);
|
}
|
||||||
|
while (i < num_stripes);
|
||||||
|
|
||||||
fp_dbg("height is %d", height);
|
fp_dbg ("height is %d", height);
|
||||||
|
|
||||||
if (height < 0) {
|
if (height < 0)
|
||||||
|
{
|
||||||
reverse = TRUE;
|
reverse = TRUE;
|
||||||
height = -height;
|
height = -height;
|
||||||
}
|
}
|
||||||
|
@ -307,9 +334,9 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
height += ctx->frame_height;
|
height += ctx->frame_height;
|
||||||
|
|
||||||
/* Create buffer big enough for max image */
|
/* Create buffer big enough for max image */
|
||||||
img = fpi_img_new(ctx->image_width * height);
|
img = fp_image_new (ctx->image_width, height);
|
||||||
img->flags = FP_IMG_COLORS_INVERTED;
|
img->flags = FPI_IMAGE_COLORS_INVERTED;
|
||||||
img->flags |= reverse ? 0 : FP_IMG_H_FLIPPED | FP_IMG_V_FLIPPED;
|
img->flags |= reverse ? 0 : FPI_IMAGE_H_FLIPPED | FPI_IMAGE_V_FLIPPED;
|
||||||
img->width = ctx->image_width;
|
img->width = ctx->image_width;
|
||||||
img->height = height;
|
img->height = height;
|
||||||
|
|
||||||
|
@ -319,32 +346,38 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
y = reverse ? (height - ctx->frame_height) : 0;
|
y = reverse ? (height - ctx->frame_height) : 0;
|
||||||
x = (ctx->image_width - ctx->frame_width) / 2;
|
x = (ctx->image_width - ctx->frame_width) / 2;
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
fpi_frame = stripe->data;
|
fpi_frame = stripe->data;
|
||||||
|
|
||||||
if(reverse) {
|
if(reverse)
|
||||||
|
{
|
||||||
y += fpi_frame->delta_y;
|
y += fpi_frame->delta_y;
|
||||||
x += fpi_frame->delta_x;
|
x += fpi_frame->delta_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
aes_blit_stripe(ctx, img, fpi_frame, x, y);
|
aes_blit_stripe (ctx, img, fpi_frame, x, y);
|
||||||
|
|
||||||
if(!reverse) {
|
if(!reverse)
|
||||||
|
{
|
||||||
y += fpi_frame->delta_y;
|
y += fpi_frame->delta_y;
|
||||||
x += fpi_frame->delta_x;
|
x += fpi_frame->delta_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
stripe = g_slist_next(stripe);
|
stripe = g_slist_next (stripe);
|
||||||
i++;
|
i++;
|
||||||
} while (i < num_stripes);
|
}
|
||||||
|
while (i < num_stripes);
|
||||||
|
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmpint(const void *p1, const void *p2, gpointer data)
|
static int
|
||||||
|
cmpint (const void *p1, const void *p2, gpointer data)
|
||||||
{
|
{
|
||||||
int a = *((int *)p1);
|
int a = *((int *) p1);
|
||||||
int b = *((int *)p2);
|
int b = *((int *) p2);
|
||||||
|
|
||||||
if (a < b)
|
if (a < b)
|
||||||
return -1;
|
return -1;
|
||||||
else if (a == b)
|
else if (a == b)
|
||||||
|
@ -353,28 +386,32 @@ static int cmpint(const void *p1, const void *p2, gpointer data)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void median_filter(int *data, int size, int filtersize)
|
static void
|
||||||
|
median_filter (int *data, int size, int filtersize)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int *result = (int *)g_malloc0(size*sizeof(int));
|
int *result = (int *) g_malloc0 (size * sizeof (int));
|
||||||
int *sortbuf = (int *)g_malloc0(filtersize*sizeof(int));
|
int *sortbuf = (int *) g_malloc0 (filtersize * sizeof (int));
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
int i1 = i - (filtersize-1)/2;
|
for (i = 0; i < size; i++)
|
||||||
int i2 = i + (filtersize-1)/2;
|
{
|
||||||
|
int i1 = i - (filtersize - 1) / 2;
|
||||||
|
int i2 = i + (filtersize - 1) / 2;
|
||||||
if (i1 < 0)
|
if (i1 < 0)
|
||||||
i1 = 0;
|
i1 = 0;
|
||||||
if (i2 >= size)
|
if (i2 >= size)
|
||||||
i2 = size-1;
|
i2 = size - 1;
|
||||||
memmove(sortbuf, data+i1, (i2-i1+1)*sizeof(int));
|
memmove (sortbuf, data + i1, (i2 - i1 + 1) * sizeof (int));
|
||||||
g_qsort_with_data(sortbuf, i2-i1+1, sizeof(int), cmpint, NULL);
|
g_qsort_with_data (sortbuf, i2 - i1 + 1, sizeof (int), cmpint, NULL);
|
||||||
result[i] = sortbuf[(i2-i1+1)/2];
|
result[i] = sortbuf[(i2 - i1 + 1) / 2];
|
||||||
}
|
}
|
||||||
memmove(data, result, size*sizeof(int));
|
memmove (data, result, size * sizeof (int));
|
||||||
g_free(result);
|
g_free (result);
|
||||||
g_free(sortbuf);
|
g_free (sortbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void interpolate_lines(struct fpi_line_asmbl_ctx *ctx,
|
static void
|
||||||
|
interpolate_lines (struct fpi_line_asmbl_ctx *ctx,
|
||||||
GSList *line1, float y1, GSList *line2,
|
GSList *line1, float y1, GSList *line2,
|
||||||
float y2, unsigned char *output, float yi, int size)
|
float y2, unsigned char *output, float yi, int size)
|
||||||
{
|
{
|
||||||
|
@ -384,11 +421,12 @@ static void interpolate_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||||
if (!line1 || !line2)
|
if (!line1 || !line2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++)
|
||||||
p1 = ctx->get_pixel(ctx, line1, i);
|
{
|
||||||
p2 = ctx->get_pixel(ctx, line2, i);
|
p1 = ctx->get_pixel (ctx, line1, i);
|
||||||
output[i] = (float)p1
|
p2 = ctx->get_pixel (ctx, line2, i);
|
||||||
+ (yi - y1)/(y2 - y1)*(p2 - p1);
|
output[i] = (float) p1
|
||||||
|
+ (yi - y1) / (y2 - y1) * (p2 - p1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +444,8 @@ static void interpolate_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||||
*
|
*
|
||||||
* Returns: a newly allocated #fp_img.
|
* Returns: a newly allocated #fp_img.
|
||||||
*/
|
*/
|
||||||
struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
FpImage *
|
||||||
|
fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx,
|
||||||
GSList *lines, size_t num_lines)
|
GSList *lines, size_t num_lines)
|
||||||
{
|
{
|
||||||
/* Number of output lines per distance between two scanners */
|
/* Number of output lines per distance between two scanners */
|
||||||
|
@ -414,58 +453,64 @@ struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||||
GSList *row1, *row2;
|
GSList *row1, *row2;
|
||||||
float y = 0.0;
|
float y = 0.0;
|
||||||
int line_ind = 0;
|
int line_ind = 0;
|
||||||
int *offsets = (int *)g_malloc0((num_lines / 2) * sizeof(int));
|
int *offsets = (int *) g_malloc0 ((num_lines / 2) * sizeof (int));
|
||||||
unsigned char *output = g_malloc0(ctx->line_width * ctx->max_height);
|
unsigned char *output = g_malloc0 (ctx->line_width * ctx->max_height);
|
||||||
struct fp_img *img;
|
FpImage *img;
|
||||||
|
|
||||||
g_return_val_if_fail (lines != NULL, NULL);
|
g_return_val_if_fail (lines != NULL, NULL);
|
||||||
g_return_val_if_fail (num_lines >= 2, NULL);
|
g_return_val_if_fail (num_lines >= 2, NULL);
|
||||||
|
|
||||||
fp_dbg("%"G_GINT64_FORMAT, g_get_real_time());
|
fp_dbg ("%"G_GINT64_FORMAT, g_get_real_time ());
|
||||||
|
|
||||||
row1 = lines;
|
row1 = lines;
|
||||||
for (i = 0; (i < num_lines - 1) && row1; i += 2) {
|
for (i = 0; (i < num_lines - 1) && row1; i += 2)
|
||||||
|
{
|
||||||
int bestmatch = i;
|
int bestmatch = i;
|
||||||
int bestdiff = 0;
|
int bestdiff = 0;
|
||||||
int j, firstrow, lastrow;
|
int j, firstrow, lastrow;
|
||||||
|
|
||||||
firstrow = i + 1;
|
firstrow = i + 1;
|
||||||
lastrow = MIN(i + ctx->max_search_offset, num_lines - 1);
|
lastrow = MIN (i + ctx->max_search_offset, num_lines - 1);
|
||||||
|
|
||||||
row2 = g_slist_next(row1);
|
row2 = g_slist_next (row1);
|
||||||
for (j = firstrow; j <= lastrow; j++) {
|
for (j = firstrow; j <= lastrow; j++)
|
||||||
int diff = ctx->get_deviation(ctx,
|
{
|
||||||
|
int diff = ctx->get_deviation (ctx,
|
||||||
row1,
|
row1,
|
||||||
row2);
|
row2);
|
||||||
if ((j == firstrow) || (diff < bestdiff)) {
|
if ((j == firstrow) || (diff < bestdiff))
|
||||||
|
{
|
||||||
bestdiff = diff;
|
bestdiff = diff;
|
||||||
bestmatch = j;
|
bestmatch = j;
|
||||||
}
|
}
|
||||||
row2 = g_slist_next(row2);
|
row2 = g_slist_next (row2);
|
||||||
}
|
}
|
||||||
offsets[i / 2] = bestmatch - i;
|
offsets[i / 2] = bestmatch - i;
|
||||||
fp_dbg("%d", offsets[i / 2]);
|
fp_dbg ("%d", offsets[i / 2]);
|
||||||
row1 = g_slist_next(row1);
|
row1 = g_slist_next (row1);
|
||||||
if (row1)
|
if (row1)
|
||||||
row1 = g_slist_next(row1);
|
row1 = g_slist_next (row1);
|
||||||
}
|
}
|
||||||
|
|
||||||
median_filter(offsets, (num_lines / 2) - 1, ctx->median_filter_size);
|
median_filter (offsets, (num_lines / 2) - 1, ctx->median_filter_size);
|
||||||
|
|
||||||
fp_dbg("offsets_filtered: %"G_GINT64_FORMAT, g_get_real_time());
|
fp_dbg ("offsets_filtered: %"G_GINT64_FORMAT, g_get_real_time ());
|
||||||
for (i = 0; i <= (num_lines / 2) - 1; i++)
|
for (i = 0; i <= (num_lines / 2) - 1; i++)
|
||||||
fp_dbg("%d", offsets[i]);
|
fp_dbg ("%d", offsets[i]);
|
||||||
row1 = lines;
|
row1 = lines;
|
||||||
for (i = 0; i < num_lines - 1; i++, row1 = g_slist_next(row1)) {
|
for (i = 0; i < num_lines - 1; i++, row1 = g_slist_next (row1))
|
||||||
int offset = offsets[i/2];
|
{
|
||||||
if (offset > 0) {
|
int offset = offsets[i / 2];
|
||||||
float ynext = y + (float)ctx->resolution / offset;
|
if (offset > 0)
|
||||||
while (line_ind < ynext) {
|
{
|
||||||
|
float ynext = y + (float) ctx->resolution / offset;
|
||||||
|
while (line_ind < ynext)
|
||||||
|
{
|
||||||
if (line_ind > ctx->max_height - 1)
|
if (line_ind > ctx->max_height - 1)
|
||||||
goto out;
|
goto out;
|
||||||
interpolate_lines(ctx,
|
interpolate_lines (ctx,
|
||||||
row1, y,
|
row1, y,
|
||||||
g_slist_next(row1),
|
g_slist_next (row1),
|
||||||
ynext,
|
ynext,
|
||||||
output + line_ind * ctx->line_width,
|
output + line_ind * ctx->line_width,
|
||||||
line_ind,
|
line_ind,
|
||||||
|
@ -476,12 +521,12 @@ struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
img = fpi_img_new(ctx->line_width * line_ind);
|
img = fp_image_new (ctx->line_width, line_ind);
|
||||||
img->height = line_ind;
|
img->height = line_ind;
|
||||||
img->width = ctx->line_width;
|
img->width = ctx->line_width;
|
||||||
img->flags = FP_IMG_V_FLIPPED;
|
img->flags = FPI_IMAGE_V_FLIPPED;
|
||||||
memmove(img->data, output, ctx->line_width * line_ind);
|
memmove (img->data, output, ctx->line_width * line_ind);
|
||||||
g_free(offsets);
|
g_free (offsets);
|
||||||
g_free(output);
|
g_free (output);
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,8 @@
|
||||||
* populate delta_x and delta_y if the device supports hardware movement
|
* populate delta_x and delta_y if the device supports hardware movement
|
||||||
* estimation.
|
* estimation.
|
||||||
*/
|
*/
|
||||||
struct fpi_frame {
|
struct fpi_frame
|
||||||
|
{
|
||||||
int delta_x;
|
int delta_x;
|
||||||
int delta_y;
|
int delta_y;
|
||||||
unsigned char data[0];
|
unsigned char data[0];
|
||||||
|
@ -52,7 +53,8 @@ struct fpi_frame {
|
||||||
* hardware parameters of scanner. @image_width is usually 25% wider than
|
* hardware parameters of scanner. @image_width is usually 25% wider than
|
||||||
* @frame_width to take horizontal movement into account.
|
* @frame_width to take horizontal movement into account.
|
||||||
*/
|
*/
|
||||||
struct fpi_frame_asmbl_ctx {
|
struct fpi_frame_asmbl_ctx
|
||||||
|
{
|
||||||
unsigned int frame_width;
|
unsigned int frame_width;
|
||||||
unsigned int frame_height;
|
unsigned int frame_height;
|
||||||
unsigned int image_width;
|
unsigned int image_width;
|
||||||
|
@ -62,11 +64,13 @@ struct fpi_frame_asmbl_ctx {
|
||||||
unsigned int y);
|
unsigned int y);
|
||||||
};
|
};
|
||||||
|
|
||||||
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
void fpi_do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
GSList *stripes, size_t num_stripes);
|
GSList *stripes,
|
||||||
|
size_t num_stripes);
|
||||||
|
|
||||||
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
FpImage *fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
GSList *stripes, size_t num_stripes);
|
GSList *stripes,
|
||||||
|
size_t num_stripes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_line_asmbl_ctx:
|
* fpi_line_asmbl_ctx:
|
||||||
|
@ -96,20 +100,23 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
* returns two lines at a time, this function should be used to estimate the
|
* returns two lines at a time, this function should be used to estimate the
|
||||||
* difference between pairs of lines.
|
* difference between pairs of lines.
|
||||||
*/
|
*/
|
||||||
struct fpi_line_asmbl_ctx {
|
struct fpi_line_asmbl_ctx
|
||||||
|
{
|
||||||
unsigned int line_width;
|
unsigned int line_width;
|
||||||
unsigned int max_height;
|
unsigned int max_height;
|
||||||
unsigned int resolution;
|
unsigned int resolution;
|
||||||
unsigned int median_filter_size;
|
unsigned int median_filter_size;
|
||||||
unsigned int max_search_offset;
|
unsigned int max_search_offset;
|
||||||
int (*get_deviation)(struct fpi_line_asmbl_ctx *ctx,
|
int (*get_deviation)(struct fpi_line_asmbl_ctx *ctx,
|
||||||
GSList *line1, GSList *line2);
|
GSList *line1,
|
||||||
|
GSList *line2);
|
||||||
unsigned char (*get_pixel)(struct fpi_line_asmbl_ctx *ctx,
|
unsigned char (*get_pixel)(struct fpi_line_asmbl_ctx *ctx,
|
||||||
GSList *line,
|
GSList *line,
|
||||||
unsigned int x);
|
unsigned int x);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
FpImage *fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx,
|
||||||
GSList *lines, size_t num_lines);
|
GSList *lines,
|
||||||
|
size_t num_lines);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,706 +0,0 @@
|
||||||
/*
|
|
||||||
* Asynchronous I/O functionality
|
|
||||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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 "async"
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
#include "fpi-async.h"
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SECTION:fpi-async
|
|
||||||
* @title: Asynchronous operations reporting
|
|
||||||
* @short_description: Asynchronous operations reporting functions
|
|
||||||
*
|
|
||||||
* Those functions are used by primitive drivers to report back their
|
|
||||||
* current status. Most drivers, imaging ones, do not need to use them.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Drivers call this when device initialisation has completed */
|
|
||||||
void fpi_drvcb_open_complete(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
fp_dbg("status %d", status);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_INITIALIZING);
|
|
||||||
dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_INITIALIZED;
|
|
||||||
opened_devices = g_slist_prepend(opened_devices, dev);
|
|
||||||
if (dev->open_cb)
|
|
||||||
dev->open_cb(dev, status, dev->open_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_dev_open:
|
|
||||||
* @ddev: the struct #fp_dscv_dev discovered device to open
|
|
||||||
* @callback: the callback to call when the device has been opened
|
|
||||||
* @user_data: user data to pass to the callback
|
|
||||||
*
|
|
||||||
* Opens and initialises a device. This is the function you call in order
|
|
||||||
* to convert a #fp_dscv_dev discovered device into an actual device handle
|
|
||||||
* that you can perform operations with.
|
|
||||||
*
|
|
||||||
* The error status of the opening will be provided as an argument to the
|
|
||||||
* #fp_dev_open_cb callback.
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb callback,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
struct fp_dev *dev;
|
|
||||||
libusb_device_handle *udevh;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(ddev != NULL, -ENODEV);
|
|
||||||
g_return_val_if_fail (callback != NULL, -EINVAL);
|
|
||||||
|
|
||||||
drv = ddev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
r = libusb_open(ddev->udev, &udevh);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("usb_open failed, error %d", r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = g_malloc0(sizeof(*dev));
|
|
||||||
dev->drv = drv;
|
|
||||||
dev->udev = udevh;
|
|
||||||
dev->__enroll_stage = -1;
|
|
||||||
dev->state = DEV_STATE_INITIALIZING;
|
|
||||||
dev->open_cb = callback;
|
|
||||||
dev->open_cb_data = user_data;
|
|
||||||
|
|
||||||
if (!drv->open) {
|
|
||||||
fpi_drvcb_open_complete(dev, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_INITIALIZING;
|
|
||||||
r = drv->open(dev, ddev->driver_data);
|
|
||||||
if (r) {
|
|
||||||
fp_err("device initialisation failed, driver=%s", drv->name);
|
|
||||||
libusb_close(udevh);
|
|
||||||
g_free(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when device deinitialisation has completed */
|
|
||||||
void fpi_drvcb_close_complete(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
BUG_ON(dev->state != DEV_STATE_DEINITIALIZING);
|
|
||||||
dev->state = DEV_STATE_DEINITIALIZED;
|
|
||||||
fpi_timeout_cancel_all_for_dev(dev);
|
|
||||||
libusb_close(dev->udev);
|
|
||||||
if (dev->close_cb)
|
|
||||||
dev->close_cb(dev, dev->close_cb_data);
|
|
||||||
g_free(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_dev_close:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @callback: the callback to call when the device has been closed
|
|
||||||
* @user_data: user data to pass to the callback
|
|
||||||
*
|
|
||||||
* Closes a device. You must call this function when you have finished using
|
|
||||||
* a fingerprint device.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_async_dev_close(struct fp_dev *dev,
|
|
||||||
fp_operation_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
|
|
||||||
g_return_if_fail (dev != NULL);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
g_return_if_fail (drv->close != NULL);
|
|
||||||
|
|
||||||
if (g_slist_index(opened_devices, (gconstpointer) dev) == -1)
|
|
||||||
fp_err("device %p not in opened list!", dev);
|
|
||||||
opened_devices = g_slist_remove(opened_devices, (gconstpointer) dev);
|
|
||||||
|
|
||||||
dev->close_cb = callback;
|
|
||||||
dev->close_cb_data = user_data;
|
|
||||||
dev->state = DEV_STATE_DEINITIALIZING;
|
|
||||||
drv->close(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when enrollment has started */
|
|
||||||
void fpi_drvcb_enroll_started(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
fp_dbg("status %d", status);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ENROLL_STARTING);
|
|
||||||
if (status) {
|
|
||||||
if (status > 0) {
|
|
||||||
status = -status;
|
|
||||||
fp_dbg("adjusted to %d", status);
|
|
||||||
}
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
if (dev->enroll_stage_cb)
|
|
||||||
dev->enroll_stage_cb(dev, status, NULL, NULL,
|
|
||||||
dev->enroll_stage_cb_data);
|
|
||||||
} else {
|
|
||||||
dev->state = DEV_STATE_ENROLLING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_enroll_start:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @callback: the callback to call for each stage of the enrollment
|
|
||||||
* @user_data: user data to pass to the callback
|
|
||||||
*
|
|
||||||
* Starts an enrollment and calls @callback for each enrollment stage.
|
|
||||||
* See [Enrolling](libfprint-Devices-operations.html#enrolling)
|
|
||||||
* for an explanation of enroll stages.
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_enroll_start(struct fp_dev *dev,
|
|
||||||
fp_enroll_stage_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
g_return_val_if_fail (callback != NULL, -EINVAL);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
if (!dev->nr_enroll_stages || !drv->enroll_start) {
|
|
||||||
fp_err("driver %s has 0 enroll stages or no enroll func",
|
|
||||||
drv->name);
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_dbg("starting enrollment");
|
|
||||||
dev->enroll_stage_cb = callback;
|
|
||||||
dev->enroll_stage_cb_data = user_data;
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_ENROLL_STARTING;
|
|
||||||
r = drv->enroll_start(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
dev->enroll_stage_cb = NULL;
|
|
||||||
fp_err("failed to start enrollment");
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when an enroll stage has completed */
|
|
||||||
void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
|
||||||
struct fp_print_data *data, struct fp_img *img)
|
|
||||||
{
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ENROLLING);
|
|
||||||
fp_dbg("result %d", result);
|
|
||||||
if (!dev->enroll_stage_cb) {
|
|
||||||
fp_dbg("ignoring enroll result as no callback is subscribed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (result == FP_ENROLL_COMPLETE && !data) {
|
|
||||||
fp_err("BUG: complete but no data?");
|
|
||||||
result = FP_ENROLL_FAIL;
|
|
||||||
}
|
|
||||||
dev->enroll_stage_cb(dev, result, data, img, dev->enroll_stage_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when enrollment has stopped */
|
|
||||||
void fpi_drvcb_enroll_stopped(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ENROLL_STOPPING);
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
if (dev->enroll_stop_cb)
|
|
||||||
dev->enroll_stop_cb(dev, dev->enroll_stop_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_enroll_stop:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @callback: the callback to call when the enrollment has been cancelled
|
|
||||||
* @user_data: user data to pass to the callback
|
|
||||||
*
|
|
||||||
* Stops an ongoing enrollment started with fp_async_enroll_start().
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev,
|
|
||||||
fp_operation_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
if (!drv->enroll_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
|
|
||||||
dev->enroll_stage_cb = NULL;
|
|
||||||
dev->enroll_stop_cb = callback;
|
|
||||||
dev->enroll_stop_cb_data = user_data;
|
|
||||||
dev->state = DEV_STATE_ENROLL_STOPPING;
|
|
||||||
|
|
||||||
if (!drv->enroll_stop) {
|
|
||||||
fpi_drvcb_enroll_stopped(dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = drv->enroll_stop(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("failed to stop enrollment");
|
|
||||||
dev->enroll_stop_cb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_verify_start:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @data: the print to verify against. Must have been previously
|
|
||||||
* enrolled with a device compatible to the device selected to perform the scan
|
|
||||||
* @callback: the callback to call when the verification has finished
|
|
||||||
* @user_data: user data to pass to the callback
|
|
||||||
*
|
|
||||||
* Starts a verification and calls @callback when the verification has
|
|
||||||
* finished. See fp_verify_finger_img() for the synchronous API. When the
|
|
||||||
* @callback has been called, you must call fp_async_verify_stop().
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_verify_start(struct fp_dev *dev,
|
|
||||||
struct fp_print_data *data, fp_img_operation_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
g_return_val_if_fail (callback != NULL, -EINVAL);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
if (!drv->verify_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_VERIFY_STARTING;
|
|
||||||
dev->verify_cb = callback;
|
|
||||||
dev->verify_cb_data = user_data;
|
|
||||||
dev->verify_data = data;
|
|
||||||
|
|
||||||
r = drv->verify_start(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
dev->verify_cb = NULL;
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
fp_err("failed to start verification, error %d", r);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when verification has started */
|
|
||||||
void fpi_drvcb_verify_started(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
BUG_ON(dev->state != DEV_STATE_VERIFY_STARTING);
|
|
||||||
if (status) {
|
|
||||||
if (status > 0) {
|
|
||||||
status = -status;
|
|
||||||
fp_dbg("adjusted to %d", status);
|
|
||||||
}
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
if (dev->verify_cb)
|
|
||||||
dev->verify_cb(dev, status, NULL, dev->verify_cb_data);
|
|
||||||
} else {
|
|
||||||
dev->state = DEV_STATE_VERIFYING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this to report a verify result (which might mark completion) */
|
|
||||||
void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
|
||||||
struct fp_img *img)
|
|
||||||
{
|
|
||||||
fp_dbg("result %d", result);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_VERIFYING);
|
|
||||||
if (result < 0 || result == FP_VERIFY_NO_MATCH
|
|
||||||
|| result == FP_VERIFY_MATCH)
|
|
||||||
dev->state = DEV_STATE_VERIFY_DONE;
|
|
||||||
|
|
||||||
if (dev->verify_cb)
|
|
||||||
dev->verify_cb(dev, result, img, dev->verify_cb_data);
|
|
||||||
else
|
|
||||||
fp_dbg("ignoring verify result as no callback is subscribed");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when verification has stopped */
|
|
||||||
void fpi_drvcb_verify_stopped(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
BUG_ON(dev->state != DEV_STATE_VERIFY_STOPPING);
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
if (dev->verify_stop_cb)
|
|
||||||
dev->verify_stop_cb(dev, dev->verify_stop_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_verify_stop:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @callback: the callback to call to finish a verification
|
|
||||||
* @user_data: user data to pass to the callback
|
|
||||||
*
|
|
||||||
* Finishes an ongoing verification started with fp_async_verify_start().
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev,
|
|
||||||
fp_operation_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
gboolean iterating = (dev->state == DEV_STATE_VERIFYING);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
|
|
||||||
if (dev->state == DEV_STATE_VERIFY_STOPPING) {
|
|
||||||
fp_dbg ("Already stopping verification, returning -EINPROGRESS");
|
|
||||||
return -EINPROGRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dev->state == DEV_STATE_INITIALIZED) {
|
|
||||||
if (callback)
|
|
||||||
callback(dev, user_data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ERROR
|
|
||||||
&& dev->state != DEV_STATE_VERIFYING
|
|
||||||
&& dev->state != DEV_STATE_VERIFY_DONE);
|
|
||||||
|
|
||||||
dev->verify_cb = NULL;
|
|
||||||
dev->verify_stop_cb = callback;
|
|
||||||
dev->verify_stop_cb_data = user_data;
|
|
||||||
dev->state = DEV_STATE_VERIFY_STOPPING;
|
|
||||||
|
|
||||||
if (!drv->verify_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
if (!drv->verify_stop) {
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
fpi_drvcb_verify_stopped(dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = drv->verify_stop(dev, iterating);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("failed to stop verification");
|
|
||||||
dev->verify_stop_cb = NULL;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_identify_start:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @gallery: NULL-terminated array of pointers to the prints to
|
|
||||||
* identify against. Each one must have been previously enrolled with a device
|
|
||||||
* compatible to the device selected to perform the scan
|
|
||||||
* @callback: the callback to call when the identification has finished
|
|
||||||
* @user_data: user data to pass to the callback
|
|
||||||
*
|
|
||||||
* Performs a new scan and verifies it against a previously enrolled print.
|
|
||||||
* See also: fp_verify_finger_img()
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_identify_start(struct fp_dev *dev,
|
|
||||||
struct fp_print_data **gallery, fp_identify_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
g_return_val_if_fail (callback != NULL, -EINVAL);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
if (!drv->identify_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
dev->state = DEV_STATE_IDENTIFY_STARTING;
|
|
||||||
dev->identify_cb = callback;
|
|
||||||
dev->identify_cb_data = user_data;
|
|
||||||
dev->identify_gallery = gallery;
|
|
||||||
|
|
||||||
r = drv->identify_start(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("identify_start failed with error %d", r);
|
|
||||||
dev->identify_cb = NULL;
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: identification has started, expect results soon */
|
|
||||||
void fpi_drvcb_identify_started(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
fp_dbg("status %d", status);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STARTING);
|
|
||||||
if (status) {
|
|
||||||
if (status > 0) {
|
|
||||||
status = -status;
|
|
||||||
fp_dbg("adjusted to %d", status);
|
|
||||||
}
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
if (dev->identify_cb)
|
|
||||||
dev->identify_cb(dev, status, 0, NULL, dev->identify_cb_data);
|
|
||||||
} else {
|
|
||||||
dev->state = DEV_STATE_IDENTIFYING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers report an identify result (which might mark completion) */
|
|
||||||
void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
|
||||||
size_t match_offset, struct fp_img *img)
|
|
||||||
{
|
|
||||||
fp_dbg("result %d", result);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
|
|
||||||
&& dev->state != DEV_STATE_ERROR);
|
|
||||||
if (result < 0 || result == FP_VERIFY_NO_MATCH
|
|
||||||
|| result == FP_VERIFY_MATCH)
|
|
||||||
dev->state = DEV_STATE_IDENTIFY_DONE;
|
|
||||||
|
|
||||||
if (dev->identify_cb)
|
|
||||||
dev->identify_cb(dev, result, match_offset, img, dev->identify_cb_data);
|
|
||||||
else
|
|
||||||
fp_dbg("ignoring verify result as no callback is subscribed");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_identify_stop:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @callback: the callback to call when the identification has stopped
|
|
||||||
* @user_data: user data to pass to the callback
|
|
||||||
*
|
|
||||||
* Stops an ongoing identification started with fp_async_identify_start().
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev,
|
|
||||||
fp_operation_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
gboolean iterating = (dev->state == DEV_STATE_IDENTIFYING);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
|
|
||||||
if (dev->state == DEV_STATE_IDENTIFY_STOPPING) {
|
|
||||||
fp_dbg ("Already stopping identification, returning -EINPROGRESS");
|
|
||||||
return -EINPROGRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dev->state == DEV_STATE_INITIALIZED) {
|
|
||||||
if (callback)
|
|
||||||
callback(dev, user_data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
|
|
||||||
&& dev->state != DEV_STATE_IDENTIFY_DONE);
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_IDENTIFY_STOPPING;
|
|
||||||
dev->identify_cb = NULL;
|
|
||||||
dev->identify_stop_cb = callback;
|
|
||||||
dev->identify_stop_cb_data = user_data;
|
|
||||||
|
|
||||||
if (!drv->identify_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
if (!drv->identify_stop) {
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
fpi_drvcb_identify_stopped(dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = drv->identify_stop(dev, iterating);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("failed to stop identification");
|
|
||||||
dev->identify_stop_cb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when identification has stopped */
|
|
||||||
void fpi_drvcb_identify_stopped(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STOPPING);
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
if (dev->identify_stop_cb)
|
|
||||||
dev->identify_stop_cb(dev, dev->identify_stop_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_capture_start:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @unconditional: whether to unconditionally capture an image, or to only capture when a finger is detected
|
|
||||||
* @callback: the callback to call when the capture has finished
|
|
||||||
* @user_data: user data to pass to the callback
|
|
||||||
*
|
|
||||||
* Start the capture of an #fp_img from a device. When the @callback has been called,
|
|
||||||
* you must call fp_async_capture_stop().
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error. -ENOTSUP indicates that either the
|
|
||||||
* @unconditional flag was set but the device does not support this, or that the•
|
|
||||||
* device does not support imaging
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional,
|
|
||||||
fp_img_operation_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
g_return_val_if_fail (callback != NULL, -EINVAL);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
if (!drv->capture_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_CAPTURE_STARTING;
|
|
||||||
dev->capture_cb = callback;
|
|
||||||
dev->capture_cb_data = user_data;
|
|
||||||
dev->unconditional_capture = unconditional;
|
|
||||||
|
|
||||||
r = drv->capture_start(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
dev->capture_cb = NULL;
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
fp_err("failed to start capture, error %d", r);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when capture has started */
|
|
||||||
void fpi_drvcb_capture_started(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
BUG_ON(dev->state != DEV_STATE_CAPTURE_STARTING);
|
|
||||||
if (status) {
|
|
||||||
if (status > 0) {
|
|
||||||
status = -status;
|
|
||||||
fp_dbg("adjusted to %d", status);
|
|
||||||
}
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
if (dev->capture_cb)
|
|
||||||
dev->capture_cb(dev, status, NULL, dev->capture_cb_data);
|
|
||||||
} else {
|
|
||||||
dev->state = DEV_STATE_CAPTURING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this to report a capture result (which might mark completion) */
|
|
||||||
void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
|
|
||||||
struct fp_img *img)
|
|
||||||
{
|
|
||||||
fp_dbg("result %d", result);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_CAPTURING);
|
|
||||||
if (result < 0 || result == FP_CAPTURE_COMPLETE)
|
|
||||||
dev->state = DEV_STATE_CAPTURE_DONE;
|
|
||||||
|
|
||||||
if (dev->capture_cb)
|
|
||||||
dev->capture_cb(dev, result, img, dev->capture_cb_data);
|
|
||||||
else
|
|
||||||
fp_dbg("ignoring capture result as no callback is subscribed");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when capture has stopped */
|
|
||||||
void fpi_drvcb_capture_stopped(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
BUG_ON(dev->state != DEV_STATE_CAPTURE_STOPPING);
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
if (dev->capture_stop_cb)
|
|
||||||
dev->capture_stop_cb(dev, dev->capture_stop_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_capture_stop:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @callback: the callback to call when the capture has been stopped
|
|
||||||
* @user_data: user data to pass to the callback
|
|
||||||
*
|
|
||||||
* Stops an ongoing verification started with fp_async_capture_start().
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
|
|
||||||
fp_operation_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ERROR
|
|
||||||
&& dev->state != DEV_STATE_CAPTURING
|
|
||||||
&& dev->state != DEV_STATE_CAPTURE_DONE);
|
|
||||||
|
|
||||||
dev->capture_cb = NULL;
|
|
||||||
dev->capture_stop_cb = callback;
|
|
||||||
dev->capture_stop_cb_data = user_data;
|
|
||||||
dev->state = DEV_STATE_CAPTURE_STOPPING;
|
|
||||||
|
|
||||||
if (!drv->capture_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
if (!drv->capture_stop) {
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
fpi_drvcb_capture_stopped(dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = drv->capture_stop(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("failed to stop capture");
|
|
||||||
dev->capture_stop_cb = NULL;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __FPI_ASYNC_H__
|
|
||||||
#define __FPI_ASYNC_H__
|
|
||||||
|
|
||||||
#include "fpi-dev.h"
|
|
||||||
#include "fpi-data.h"
|
|
||||||
|
|
||||||
void fpi_drvcb_open_complete(struct fp_dev *dev, int status);
|
|
||||||
void fpi_drvcb_close_complete(struct fp_dev *dev);
|
|
||||||
|
|
||||||
void fpi_drvcb_enroll_started(struct fp_dev *dev, int status);
|
|
||||||
void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
|
||||||
struct fp_print_data *data, struct fp_img *img);
|
|
||||||
void fpi_drvcb_enroll_stopped(struct fp_dev *dev);
|
|
||||||
|
|
||||||
void fpi_drvcb_verify_started(struct fp_dev *dev, int status);
|
|
||||||
void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
|
||||||
struct fp_img *img);
|
|
||||||
void fpi_drvcb_verify_stopped(struct fp_dev *dev);
|
|
||||||
|
|
||||||
#endif
|
|
33
libfprint/fpi-context.h
Normal file
33
libfprint/fpi-context.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* FpContext - A FPrint context
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gusb.h>
|
||||||
|
#include "fp-context.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_get_driver_types:
|
||||||
|
* @drivers: #GArray to be filled with all driver types
|
||||||
|
*
|
||||||
|
* This function is purely for private used. It is solely part of the public
|
||||||
|
* API as it is useful during build time.
|
||||||
|
*
|
||||||
|
* Stability: private
|
||||||
|
*/
|
||||||
|
void fpi_get_driver_types (GArray *drivers);
|
|
@ -1,730 +0,0 @@
|
||||||
/*
|
|
||||||
* Core functions for libfprint
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
|
|
||||||
libusb_context *fpi_usb_ctx = NULL;
|
|
||||||
GSList *opened_devices = NULL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:discovery
|
|
||||||
* @title: Device discovery
|
|
||||||
* @short_description: Device discovery functions
|
|
||||||
*
|
|
||||||
* These functions allow you to scan the system for supported fingerprint
|
|
||||||
* scanning hardware. This is your starting point when integrating libfprint
|
|
||||||
* into your software.
|
|
||||||
*
|
|
||||||
* When you've identified a discovered device that you would like to control,
|
|
||||||
* you can open it with fp_dev_open(). Note that discovered devices may no
|
|
||||||
* longer be available at the time when you want to open them, for example
|
|
||||||
* the user may have unplugged the device.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:drv
|
|
||||||
* @title: Driver operations
|
|
||||||
* @short_description: Driver operation functions
|
|
||||||
*
|
|
||||||
* Internally, libfprint is abstracted into various drivers to communicate
|
|
||||||
* with the different types of supported fingerprint readers. libfprint works
|
|
||||||
* hard so that you don't have to care about these internal abstractions,
|
|
||||||
* however there are some situations where you may be interested in a little
|
|
||||||
* behind-the-scenes driver info.
|
|
||||||
*
|
|
||||||
* You can obtain the driver for a device using fp_dev_get_driver(), which
|
|
||||||
* you can pass to the functions documented on this page.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:dev
|
|
||||||
* @title: Devices operations
|
|
||||||
* @short_description: Device operation functions
|
|
||||||
*
|
|
||||||
* In order to interact with fingerprint scanners, your software will
|
|
||||||
* interface primarily with libfprint's representation of devices, detailed
|
|
||||||
* on this page.
|
|
||||||
*
|
|
||||||
* # Enrolling # {#enrolling}
|
|
||||||
*
|
|
||||||
* Enrolling is represented within libfprint as a multi-stage process. This
|
|
||||||
* slightly complicates things for application developers, but is required
|
|
||||||
* for a smooth process.
|
|
||||||
*
|
|
||||||
* Some devices require the user to scan their finger multiple times in
|
|
||||||
* order to complete the enrollment process. libfprint must return control
|
|
||||||
* to your application in-between each scan in order for your application to
|
|
||||||
* instruct the user to swipe their finger again. Each scan is referred to
|
|
||||||
* as a stage, so a device that requires 3 scans for enrollment corresponds
|
|
||||||
* to you running 3 enrollment stages using libfprint.
|
|
||||||
*
|
|
||||||
* The fp_dev_get_nr_enroll_stages() function can be used to find out how
|
|
||||||
* many enroll stages are needed.
|
|
||||||
*
|
|
||||||
* In order to complete an enroll stage, you call an enroll function such
|
|
||||||
* as fp_enroll_finger(). The return of this function does not necessarily
|
|
||||||
* indicate that a stage has completed though, as the user may not have
|
|
||||||
* produced a good enough scan. Each stage may have to be retried several
|
|
||||||
* times.
|
|
||||||
*
|
|
||||||
* The exact semantics of the enroll functions are described in the
|
|
||||||
* fp_enroll_finger() documentation. You should pay careful attention to the
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* # Imaging # {#imaging}
|
|
||||||
*
|
|
||||||
* libfprint provides you with some ways to retrieve images of scanned
|
|
||||||
* fingers, such as the fp_dev_img_capture() function, or some enroll/verify
|
|
||||||
* function variants which provide images. You may wish to do something with
|
|
||||||
* such images in your application.
|
|
||||||
*
|
|
||||||
* However, you must be aware that not all hardware supported by libfprint
|
|
||||||
* operates like this. Most hardware does operate simply by sending
|
|
||||||
* fingerprint images to the host computer for further processing, but some
|
|
||||||
* devices do all fingerprint processing in hardware and do not present images
|
|
||||||
* to the host computer.
|
|
||||||
*
|
|
||||||
* You can use fp_dev_supports_imaging() to see if image capture is possible
|
|
||||||
* on a particular device. Your application must be able to cope with the
|
|
||||||
* fact that libfprint does support regular operations (e.g. enrolling and
|
|
||||||
* verification) on some devices which do not provide images.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:fpi-core
|
|
||||||
* @title: Driver structures
|
|
||||||
* @short_description: Driver structures
|
|
||||||
*
|
|
||||||
* Driver structures need to be defined inside each driver in
|
|
||||||
* order for the core library to know what function to call, and the capabilities
|
|
||||||
* of the driver and the devices it supports.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:fpi-core-img
|
|
||||||
* @title: Image driver structures
|
|
||||||
* @short_description: Image driver structures
|
|
||||||
*
|
|
||||||
* Image driver structures need to be defined inside each image driver in
|
|
||||||
* order for the core library to know what function to call, and the capabilities
|
|
||||||
* of the driver and the devices it supports. Its structure is based off the
|
|
||||||
* #fp_driver struct.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static GSList *registered_drivers = NULL;
|
|
||||||
|
|
||||||
static void register_driver(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
if (drv->id == 0) {
|
|
||||||
fp_err("not registering driver %s: driver ID is 0", drv->name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
registered_drivers = g_slist_prepend(registered_drivers, (gpointer) drv);
|
|
||||||
fp_dbg("registered driver %s", drv->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "drivers_arrays.h"
|
|
||||||
|
|
||||||
static void register_drivers(void)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++)
|
|
||||||
register_driver(primitive_drivers[i]);
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(img_drivers); i++) {
|
|
||||||
struct fp_img_driver *imgdriver = img_drivers[i];
|
|
||||||
fpi_img_driver_setup(imgdriver);
|
|
||||||
register_driver(&imgdriver->driver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
API_EXPORTED struct fp_driver **fprint_get_drivers (void)
|
|
||||||
{
|
|
||||||
GPtrArray *array;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
array = g_ptr_array_new ();
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++)
|
|
||||||
g_ptr_array_add (array, primitive_drivers[i]);
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(img_drivers); i++)
|
|
||||||
g_ptr_array_add (array, &(img_drivers[i]->driver));
|
|
||||||
|
|
||||||
/* Add a null item terminating the array */
|
|
||||||
g_ptr_array_add (array, NULL);
|
|
||||||
|
|
||||||
return (struct fp_driver **) g_ptr_array_free (array, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_driver *find_supporting_driver(libusb_device *udev,
|
|
||||||
const struct usb_id **usb_id, uint32_t *devtype)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
GSList *elem = registered_drivers;
|
|
||||||
struct libusb_device_descriptor dsc;
|
|
||||||
|
|
||||||
const struct usb_id *best_usb_id;
|
|
||||||
struct fp_driver *best_drv;
|
|
||||||
uint32_t best_devtype;
|
|
||||||
int drv_score = 0;
|
|
||||||
|
|
||||||
ret = libusb_get_device_descriptor(udev, &dsc);
|
|
||||||
if (ret < 0) {
|
|
||||||
fp_err("Failed to get device descriptor");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
best_drv = NULL;
|
|
||||||
best_devtype = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
struct fp_driver *drv = elem->data;
|
|
||||||
uint32_t type = 0;
|
|
||||||
const struct usb_id *id;
|
|
||||||
|
|
||||||
for (id = drv->id_table; id->vendor; id++) {
|
|
||||||
if (dsc.idVendor == id->vendor && dsc.idProduct == id->product) {
|
|
||||||
if (drv->discover) {
|
|
||||||
int r = drv->discover(&dsc, &type);
|
|
||||||
if (r < 0)
|
|
||||||
fp_err("%s discover failed, code %d", drv->name, r);
|
|
||||||
if (r <= 0)
|
|
||||||
continue;
|
|
||||||
/* Has a discover function, and matched our device */
|
|
||||||
drv_score = 100;
|
|
||||||
} else {
|
|
||||||
/* Already got a driver as good */
|
|
||||||
if (drv_score >= 50)
|
|
||||||
continue;
|
|
||||||
drv_score = 50;
|
|
||||||
}
|
|
||||||
fp_dbg("driver %s supports USB device %04x:%04x",
|
|
||||||
drv->name, id->vendor, id->product);
|
|
||||||
best_usb_id = id;
|
|
||||||
best_drv = drv;
|
|
||||||
best_devtype = type;
|
|
||||||
|
|
||||||
/* We found the best possible driver */
|
|
||||||
if (drv_score == 100)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while ((elem = g_slist_next(elem)));
|
|
||||||
|
|
||||||
if (best_drv != NULL) {
|
|
||||||
fp_dbg("selected driver %s supports USB device %04x:%04x",
|
|
||||||
best_drv->name, dsc.idVendor, dsc.idProduct);
|
|
||||||
*devtype = best_devtype;
|
|
||||||
*usb_id = best_usb_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return best_drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_dscv_dev *discover_dev(libusb_device *udev)
|
|
||||||
{
|
|
||||||
const struct usb_id *usb_id;
|
|
||||||
struct fp_driver *drv;
|
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
uint32_t devtype;
|
|
||||||
|
|
||||||
drv = find_supporting_driver(udev, &usb_id, &devtype);
|
|
||||||
|
|
||||||
if (!drv)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ddev = g_malloc0(sizeof(*ddev));
|
|
||||||
ddev->drv = drv;
|
|
||||||
ddev->udev = udev;
|
|
||||||
ddev->driver_data = usb_id->driver_data;
|
|
||||||
ddev->devtype = devtype;
|
|
||||||
return ddev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_discover_devs:
|
|
||||||
*
|
|
||||||
* Scans the system and returns a list of discovered devices. This is your
|
|
||||||
* entry point into finding a fingerprint reader to operate. Note that %NULL
|
|
||||||
* is only returned on error. When there are no supported readers available,
|
|
||||||
* an empty list is returned instead.
|
|
||||||
*
|
|
||||||
* Returns: a nul-terminated list of discovered devices or %NULL on error.
|
|
||||||
* Must be freed with fp_dscv_devs_free() after use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
|
|
||||||
{
|
|
||||||
GPtrArray *tmparray;
|
|
||||||
libusb_device *udev;
|
|
||||||
libusb_device **devs;
|
|
||||||
int r;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
g_return_val_if_fail (registered_drivers != NULL, NULL);
|
|
||||||
|
|
||||||
r = libusb_get_device_list(fpi_usb_ctx, &devs);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("couldn't enumerate USB devices, error %d", r);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmparray = g_ptr_array_new ();
|
|
||||||
|
|
||||||
/* Check each device against each driver, temporarily storing successfully
|
|
||||||
* discovered devices in a GPtrArray. */
|
|
||||||
while ((udev = devs[i++]) != NULL) {
|
|
||||||
struct fp_dscv_dev *ddev = discover_dev(udev);
|
|
||||||
if (!ddev)
|
|
||||||
continue;
|
|
||||||
/* discover_dev() doesn't hold a reference to the udev,
|
|
||||||
* so increase the reference for ddev to hold this ref */
|
|
||||||
libusb_ref_device(udev);
|
|
||||||
g_ptr_array_add (tmparray, (gpointer) ddev);
|
|
||||||
}
|
|
||||||
libusb_free_device_list(devs, 1);
|
|
||||||
|
|
||||||
/* Convert our temporary array into a standard NULL-terminated pointer
|
|
||||||
* array. */
|
|
||||||
g_ptr_array_add (tmparray, NULL);
|
|
||||||
return (struct fp_dscv_dev **) g_ptr_array_free (tmparray, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_devs_free:
|
|
||||||
* @devs: the list of discovered devices. If %NULL, function simply
|
|
||||||
* returns.
|
|
||||||
*
|
|
||||||
* Free a list of discovered devices. This function destroys the list and all
|
|
||||||
* discovered devices that it included, so make sure you have opened your
|
|
||||||
* discovered device <emphasis role="strong">before</emphasis> freeing the list.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
if (!devs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; devs[i]; i++) {
|
|
||||||
libusb_unref_device(devs[i]->udev);
|
|
||||||
g_free(devs[i]);
|
|
||||||
}
|
|
||||||
g_free(devs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_dev_get_driver:
|
|
||||||
* @dev: the discovered device
|
|
||||||
*
|
|
||||||
* Gets the #fp_driver for a discovered device.
|
|
||||||
*
|
|
||||||
* Returns: the driver backing the device
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(dev, NULL);
|
|
||||||
|
|
||||||
return dev->drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_dev_get_driver_id:
|
|
||||||
* @dev: a discovered fingerprint device
|
|
||||||
*
|
|
||||||
* Returns a unique driver identifier for the underlying driver
|
|
||||||
* for that device.
|
|
||||||
*
|
|
||||||
* Returns: the ID for #dev
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(dev, 0);
|
|
||||||
|
|
||||||
return fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_dev_get_devtype:
|
|
||||||
* @dev: the discovered device
|
|
||||||
*
|
|
||||||
* Gets the [devtype](advanced-topics.html#device-types) for a discovered device.
|
|
||||||
*
|
|
||||||
* Returns: the devtype of the device
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(dev, 0);
|
|
||||||
|
|
||||||
return dev->devtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
switch (drv->type) {
|
|
||||||
case DRIVER_PRIMITIVE:
|
|
||||||
return PRINT_DATA_RAW;
|
|
||||||
case DRIVER_IMAGING:
|
|
||||||
return PRINT_DATA_NBIS_MINUTIAE;
|
|
||||||
default:
|
|
||||||
fp_err("unrecognised drv type %d", drv->type);
|
|
||||||
return PRINT_DATA_RAW;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_dev_supports_print_data:
|
|
||||||
* @dev: the discovered device
|
|
||||||
* @print: the print for compatibility checking
|
|
||||||
*
|
|
||||||
* Determines if a specific #fp_print_data stored print appears to be
|
|
||||||
* compatible with a discovered device.
|
|
||||||
*
|
|
||||||
* Returns: 1 if the print is compatible with the device, 0 otherwise
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev,
|
|
||||||
struct fp_print_data *print)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(dev, 0);
|
|
||||||
g_return_val_if_fail(print, 0);
|
|
||||||
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
|
||||||
fpi_driver_get_data_type(dev->drv), print->driver_id, print->devtype,
|
|
||||||
print->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_get_driver:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
*
|
|
||||||
* Get the #fp_driver for a fingerprint device.
|
|
||||||
*
|
|
||||||
* Returns: the driver controlling the device
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_driver *fp_dev_get_driver(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(dev, NULL);
|
|
||||||
|
|
||||||
return dev->drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_get_nr_enroll_stages:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
*
|
|
||||||
* Gets the number of [enroll stages](intro.html#enrollment) required to enroll a
|
|
||||||
* fingerprint with the device.
|
|
||||||
*
|
|
||||||
* Returns: the number of enroll stages
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_get_nr_enroll_stages(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(dev, 0);
|
|
||||||
|
|
||||||
return dev->nr_enroll_stages;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_get_devtype:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
*
|
|
||||||
* Gets the [devtype](advanced-topics.html#device-types) for a device.
|
|
||||||
*
|
|
||||||
* Returns: the devtype
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint32_t fp_dev_get_devtype(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(dev, 0);
|
|
||||||
|
|
||||||
return dev->devtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_supports_print_data:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @data: the stored print
|
|
||||||
*
|
|
||||||
* Determines if a stored print is compatible with a certain device.
|
|
||||||
*
|
|
||||||
* Returns: 1 if the print is compatible with the device, 0 if not
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_supports_print_data(struct fp_dev *dev,
|
|
||||||
struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(dev, 0);
|
|
||||||
g_return_val_if_fail(data, 0);
|
|
||||||
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
|
||||||
fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype,
|
|
||||||
data->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_driver_get_name:
|
|
||||||
* @drv: the driver
|
|
||||||
*
|
|
||||||
* Retrieves the name of the driver. For example: "upekts"
|
|
||||||
*
|
|
||||||
* Returns: the driver name. Must not be modified or freed.
|
|
||||||
*/
|
|
||||||
API_EXPORTED const char *fp_driver_get_name(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(drv, NULL);
|
|
||||||
|
|
||||||
return drv->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_driver_get_full_name:
|
|
||||||
* @drv: the driver
|
|
||||||
*
|
|
||||||
* Retrieves a descriptive name of the driver. For example: "UPEK TouchStrip"
|
|
||||||
*
|
|
||||||
* Returns: the descriptive name. Must not be modified or freed.
|
|
||||||
*/
|
|
||||||
API_EXPORTED const char *fp_driver_get_full_name(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(drv, NULL);
|
|
||||||
|
|
||||||
return drv->full_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_driver_get_driver_id:
|
|
||||||
* @drv: the driver
|
|
||||||
*
|
|
||||||
* Retrieves the driver ID code for a driver.
|
|
||||||
*
|
|
||||||
* Returns: the driver ID
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint16_t fp_driver_get_driver_id(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(drv, 0);
|
|
||||||
|
|
||||||
return drv->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_driver_get_scan_type:
|
|
||||||
* @drv: the driver
|
|
||||||
*
|
|
||||||
* Retrieves the scan type for the devices associated with the driver.
|
|
||||||
*
|
|
||||||
* Returns: the scan type
|
|
||||||
*/
|
|
||||||
API_EXPORTED enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(drv, FP_SCAN_TYPE_PRESS);
|
|
||||||
|
|
||||||
return drv->scan_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_driver_supports_imaging:
|
|
||||||
* @drv: the driver
|
|
||||||
*
|
|
||||||
* Determines if a driver has imaging capabilities. If a driver has imaging
|
|
||||||
* capabilities you are able to perform imaging operations such as retrieving
|
|
||||||
* scan images using fp_dev_img_capture(). However, not all drivers support
|
|
||||||
* imaging devices – some do all processing in hardware. This function will
|
|
||||||
* indicate which class a device in question falls into.
|
|
||||||
*
|
|
||||||
* Returns: 1 if the device is an imaging device, 0 if the device does not
|
|
||||||
* provide images to the host computer
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_driver_supports_imaging(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(drv, 0);
|
|
||||||
|
|
||||||
return drv->capture_start != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_supports_imaging:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
*
|
|
||||||
* Determines if a device has imaging capabilities. If a device has imaging
|
|
||||||
* capabilities you are able to perform imaging operations such as retrieving
|
|
||||||
* scan images using fp_dev_img_capture(). However, not all devices are
|
|
||||||
* imaging devices – some do all processing in hardware. This function will
|
|
||||||
* indicate which class a device in question falls into.
|
|
||||||
*
|
|
||||||
* Returns: 1 if the device is an imaging device, 0 if the device does not
|
|
||||||
* provide images to the host computer
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(dev, 0);
|
|
||||||
|
|
||||||
return dev->drv->capture_start != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_supports_identification:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
*
|
|
||||||
* Determines if a device is capable of [identification](intro.html#identification)
|
|
||||||
* through fp_identify_finger() and similar. Not all devices support this
|
|
||||||
* functionality.
|
|
||||||
*
|
|
||||||
* Returns: 1 if the device is capable of identification, 0 otherwise.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(dev, 0);
|
|
||||||
|
|
||||||
return dev->drv->identify_start != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_get_img_width:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
*
|
|
||||||
* Gets the expected width of images that will be captured from the device.
|
|
||||||
* This function will return -1 for devices that are not
|
|
||||||
* [imaging devices](libfprint-Devices-operations.html#imaging). If the width of images from this device
|
|
||||||
* can vary, 0 will be returned.
|
|
||||||
*
|
|
||||||
* Returns: the expected image width, or 0 for variable, or -1 for non-imaging
|
|
||||||
* devices.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_get_img_width(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(dev, -1);
|
|
||||||
|
|
||||||
if (!dev->img_dev) {
|
|
||||||
fp_dbg("get image width for non-imaging device");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fpi_imgdev_get_img_width(dev->img_dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_get_img_height:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
*
|
|
||||||
* Gets the expected height of images that will be captured from the device.
|
|
||||||
* This function will return -1 for devices that are not
|
|
||||||
* [imaging devices](libfprint-Devices-operations.html#imaging). If the height of images from this device
|
|
||||||
* can vary, 0 will be returned.
|
|
||||||
*
|
|
||||||
* Returns: the expected image height, or 0 for variable, or -1 for non-imaging
|
|
||||||
* devices.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_get_img_height(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(dev, -1);
|
|
||||||
|
|
||||||
if (!dev->img_dev) {
|
|
||||||
fp_dbg("get image height for non-imaging device");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fpi_imgdev_get_img_height(dev->img_dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_set_debug:
|
|
||||||
* @level: the verbosity level
|
|
||||||
*
|
|
||||||
* This call does nothing, see fp_init() for details.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_set_debug(int level)
|
|
||||||
{
|
|
||||||
/* Nothing */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_init:
|
|
||||||
*
|
|
||||||
* Initialise libfprint. This function must be called before you attempt to
|
|
||||||
* use the library in any way.
|
|
||||||
*
|
|
||||||
* To enable debug output of libfprint specifically, use GLib's `G_MESSAGES_DEBUG`
|
|
||||||
* environment variable as explained in [Running and debugging GLib Applications](https://developer.gnome.org/glib/stable/glib-running.html#G_MESSAGES_DEBUG).
|
|
||||||
*
|
|
||||||
* The log domains used in libfprint are either `libfprint` or `libfprint-FP_COMPONENT`
|
|
||||||
* where `FP_COMPONENT` is defined in the source code for each driver, or component
|
|
||||||
* of the library. Starting with `all` and trimming down is advised.
|
|
||||||
*
|
|
||||||
* To enable debugging of libusb, for USB-based fingerprint reader drivers, use
|
|
||||||
* libusb's `LIBUSB_DEBUG` environment variable as explained in the
|
|
||||||
* [libusb-1.0 API Reference](http://libusb.sourceforge.net/api-1.0/#msglog).
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* LIBUSB_DEBUG=4 G_MESSAGES_DEBUG=all my-libfprint-application
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_init(void)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
|
|
||||||
r = libusb_init(&fpi_usb_ctx);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
register_drivers();
|
|
||||||
fpi_poll_init();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_exit:
|
|
||||||
*
|
|
||||||
* Deinitialise libfprint. This function should be called during your program
|
|
||||||
* exit sequence. You must not use any libfprint functions after calling this
|
|
||||||
* function, unless you call fp_init() again.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_exit(void)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
|
|
||||||
if (opened_devices) {
|
|
||||||
GSList *copy = g_slist_copy(opened_devices);
|
|
||||||
GSList *elem = copy;
|
|
||||||
fp_dbg("naughty app left devices open on exit!");
|
|
||||||
|
|
||||||
do
|
|
||||||
fp_dev_close((struct fp_dev *) elem->data);
|
|
||||||
while ((elem = g_slist_next(elem)));
|
|
||||||
|
|
||||||
g_slist_free(copy);
|
|
||||||
g_slist_free(opened_devices);
|
|
||||||
opened_devices = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_poll_exit();
|
|
||||||
g_slist_free(registered_drivers);
|
|
||||||
registered_drivers = NULL;
|
|
||||||
libusb_exit(fpi_usb_ctx);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __FPI_CORE_H__
|
|
||||||
#define __FPI_CORE_H__
|
|
||||||
|
|
||||||
#include <fprint.h>
|
|
||||||
#include "fpi-dev-img.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* usb_id:
|
|
||||||
* @vendor: the USB vendor ID
|
|
||||||
* @product: the USB product ID
|
|
||||||
* @driver_data: data to differentiate devices of different
|
|
||||||
* vendor and product IDs.
|
|
||||||
*
|
|
||||||
* The struct #usb_id is used to declare devices supported by a
|
|
||||||
* particular driver. The @driver_data information is used to
|
|
||||||
* differentiate different models of devices which only need
|
|
||||||
* small changes compared to the default driver behaviour to function.
|
|
||||||
*
|
|
||||||
* For example, a device might have a different initialisation from
|
|
||||||
* the stock device, so the driver could do:
|
|
||||||
*
|
|
||||||
* |[<!-- language="C" -->
|
|
||||||
* if (driver_data == MY_DIFFERENT_DEVICE_QUIRK) {
|
|
||||||
* ...
|
|
||||||
* } else {
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
* ]|
|
|
||||||
*
|
|
||||||
* The default value is zero, so the @driver_data needs to be a
|
|
||||||
* non-zero to be useful.
|
|
||||||
*/
|
|
||||||
struct usb_id {
|
|
||||||
uint16_t vendor;
|
|
||||||
uint16_t product;
|
|
||||||
unsigned long driver_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_driver_type:
|
|
||||||
* @DRIVER_PRIMITIVE: primitive, non-imaging, driver
|
|
||||||
* @DRIVER_IMAGING: imaging driver
|
|
||||||
*
|
|
||||||
* The type of device the driver supports.
|
|
||||||
*/
|
|
||||||
enum fp_driver_type {
|
|
||||||
DRIVER_PRIMITIVE = 0,
|
|
||||||
DRIVER_IMAGING = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fp_driver {
|
|
||||||
const uint16_t id;
|
|
||||||
const char *name;
|
|
||||||
const char *full_name;
|
|
||||||
const struct usb_id * const id_table;
|
|
||||||
enum fp_driver_type type;
|
|
||||||
enum fp_scan_type scan_type;
|
|
||||||
|
|
||||||
/* Device operations */
|
|
||||||
int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype);
|
|
||||||
int (*open)(struct fp_dev *dev, unsigned long driver_data);
|
|
||||||
void (*close)(struct fp_dev *dev);
|
|
||||||
int (*enroll_start)(struct fp_dev *dev);
|
|
||||||
int (*enroll_stop)(struct fp_dev *dev);
|
|
||||||
int (*verify_start)(struct fp_dev *dev);
|
|
||||||
int (*verify_stop)(struct fp_dev *dev, gboolean iterating);
|
|
||||||
int (*identify_start)(struct fp_dev *dev);
|
|
||||||
int (*identify_stop)(struct fp_dev *dev, gboolean iterating);
|
|
||||||
int (*capture_start)(struct fp_dev *dev);
|
|
||||||
int (*capture_stop)(struct fp_dev *dev);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FpiImgDriverFlags:
|
|
||||||
* @FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE: Whether the driver supports
|
|
||||||
* unconditional image capture. No driver currently does.
|
|
||||||
*
|
|
||||||
* Flags used in the #fp_img_driver to advertise the capabilities of drivers.
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE = 1 << 0
|
|
||||||
} FpiImgDriverFlags;
|
|
||||||
|
|
||||||
struct fp_img_driver {
|
|
||||||
struct fp_driver driver;
|
|
||||||
FpiImgDriverFlags flags;
|
|
||||||
int img_width;
|
|
||||||
int img_height;
|
|
||||||
int bz3_threshold;
|
|
||||||
|
|
||||||
/* Device operations */
|
|
||||||
int (*open)(struct fp_img_dev *dev, unsigned long driver_data);
|
|
||||||
void (*close)(struct fp_img_dev *dev);
|
|
||||||
int (*activate)(struct fp_img_dev *dev);
|
|
||||||
int (*change_state)(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
|
||||||
void (*deactivate)(struct fp_img_dev *dev);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,340 +0,0 @@
|
||||||
/*
|
|
||||||
* Fingerprint data handling and storage
|
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <glib/gstdio.h>
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
|
|
||||||
#define DIR_PERMS 0700
|
|
||||||
|
|
||||||
struct fpi_print_data_fp2 {
|
|
||||||
char prefix[3];
|
|
||||||
uint16_t driver_id;
|
|
||||||
uint32_t devtype;
|
|
||||||
unsigned char data_type;
|
|
||||||
unsigned char data[0];
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
|
|
||||||
struct fpi_print_data_item_fp2 {
|
|
||||||
uint32_t length;
|
|
||||||
unsigned char data[0];
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION: print_data
|
|
||||||
* @title: Stored prints
|
|
||||||
* @short_description: Stored prints functions
|
|
||||||
*
|
|
||||||
* Stored prints are represented by a structure named #fp_print_data.
|
|
||||||
* Stored prints are originally obtained from an enrollment function such as
|
|
||||||
* fp_enroll_finger().
|
|
||||||
*
|
|
||||||
* This page documents the various operations you can do with a stored print.
|
|
||||||
* Note that by default, "stored prints" are not actually stored anywhere
|
|
||||||
* except in RAM. Storage needs to be handled by the API user by using the
|
|
||||||
* fp_print_data_get_data() and fp_print_data_from_data(). This API allows
|
|
||||||
* to convert print data into byte strings, and to reconstruct stored prints
|
|
||||||
* from such data at a later point. You are welcome to store these byte strings
|
|
||||||
* in any fashion that suits you.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SECTION: fpi-data
|
|
||||||
* @title: Stored prints creation
|
|
||||||
* @short_description: Stored prints creation functions
|
|
||||||
*
|
|
||||||
* Stored print can be loaded and created by certain drivers which do their own
|
|
||||||
* print matching in hardware. Most drivers will not be using those functions.
|
|
||||||
* See #fp_print_data for the public API counterpart.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FP_FINGER_IS_VALID(finger) \
|
|
||||||
((finger) >= LEFT_THUMB && (finger) <= RIGHT_LITTLE)
|
|
||||||
|
|
||||||
static struct fp_print_data *print_data_new(uint16_t driver_id,
|
|
||||||
uint32_t devtype, enum fp_print_data_type type)
|
|
||||||
{
|
|
||||||
struct fp_print_data *data = g_malloc0(sizeof(*data));
|
|
||||||
fp_dbg("driver=%02x devtype=%04x", driver_id, devtype);
|
|
||||||
data->driver_id = driver_id;
|
|
||||||
data->devtype = devtype;
|
|
||||||
data->type = type;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fpi_print_data_item_free(struct fp_print_data_item *item)
|
|
||||||
{
|
|
||||||
g_free(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_print_data_item *fpi_print_data_item_new(size_t length)
|
|
||||||
{
|
|
||||||
struct fp_print_data_item *item = g_malloc0(sizeof(*item) + length);
|
|
||||||
item->length = length;
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return print_data_new(dev->drv->id, dev->devtype,
|
|
||||||
fpi_driver_get_data_type(dev->drv));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_print_data_item *
|
|
||||||
fpi_print_data_get_item(struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
return data->prints->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpi_print_data_add_item(struct fp_print_data *data,
|
|
||||||
struct fp_print_data_item *item)
|
|
||||||
{
|
|
||||||
data->prints = g_slist_prepend(data->prints, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_get_data:
|
|
||||||
* @data: the stored print
|
|
||||||
* @ret: output location for the data buffer. Must be freed with free()
|
|
||||||
* after use.
|
|
||||||
|
|
||||||
* Convert a stored print into a unified representation inside a data buffer.
|
|
||||||
* You can then store this data buffer in any way that suits you, and load
|
|
||||||
* it back at some later time using fp_print_data_from_data().
|
|
||||||
*
|
|
||||||
* Returns: the size of the freshly allocated buffer, or 0 on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
|
|
||||||
unsigned char **ret)
|
|
||||||
{
|
|
||||||
struct fpi_print_data_fp2 *out_data;
|
|
||||||
struct fpi_print_data_item_fp2 *out_item;
|
|
||||||
struct fp_print_data_item *item;
|
|
||||||
size_t buflen = 0;
|
|
||||||
GSList *list_item;
|
|
||||||
unsigned char *buf;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
|
|
||||||
list_item = data->prints;
|
|
||||||
while (list_item) {
|
|
||||||
item = list_item->data;
|
|
||||||
buflen += sizeof(*out_item);
|
|
||||||
buflen += item->length;
|
|
||||||
list_item = g_slist_next(list_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
buflen += sizeof(*out_data);
|
|
||||||
out_data = g_malloc(buflen);
|
|
||||||
|
|
||||||
*ret = (unsigned char *) out_data;
|
|
||||||
buf = out_data->data;
|
|
||||||
out_data->prefix[0] = 'F';
|
|
||||||
out_data->prefix[1] = 'P';
|
|
||||||
out_data->prefix[2] = '2';
|
|
||||||
out_data->driver_id = GUINT16_TO_LE(data->driver_id);
|
|
||||||
out_data->devtype = GUINT32_TO_LE(data->devtype);
|
|
||||||
out_data->data_type = data->type;
|
|
||||||
|
|
||||||
list_item = data->prints;
|
|
||||||
while (list_item) {
|
|
||||||
item = list_item->data;
|
|
||||||
out_item = (struct fpi_print_data_item_fp2 *)buf;
|
|
||||||
out_item->length = GUINT32_TO_LE(item->length);
|
|
||||||
/* FIXME: fp_print_data_item->data content is not endianness agnostic */
|
|
||||||
memcpy(out_item->data, item->data, item->length);
|
|
||||||
buf += sizeof(*out_item);
|
|
||||||
buf += item->length;
|
|
||||||
list_item = g_slist_next(list_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buflen;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_print_data *fpi_print_data_from_fp1_data(unsigned char *buf,
|
|
||||||
size_t buflen)
|
|
||||||
{
|
|
||||||
size_t print_data_len;
|
|
||||||
struct fp_print_data *data;
|
|
||||||
struct fp_print_data_item *item;
|
|
||||||
struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
|
|
||||||
|
|
||||||
print_data_len = buflen - sizeof(*raw);
|
|
||||||
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
|
|
||||||
GUINT32_FROM_LE(raw->devtype), raw->data_type);
|
|
||||||
item = fpi_print_data_item_new(print_data_len);
|
|
||||||
/* FIXME: fp_print_data->data content is not endianness agnostic */
|
|
||||||
memcpy(item->data, raw->data, print_data_len);
|
|
||||||
data->prints = g_slist_prepend(data->prints, item);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf,
|
|
||||||
size_t buflen)
|
|
||||||
{
|
|
||||||
size_t total_data_len, item_len;
|
|
||||||
struct fp_print_data *data;
|
|
||||||
struct fp_print_data_item *item;
|
|
||||||
struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
|
|
||||||
unsigned char *raw_buf;
|
|
||||||
struct fpi_print_data_item_fp2 *raw_item;
|
|
||||||
|
|
||||||
total_data_len = buflen - sizeof(*raw);
|
|
||||||
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
|
|
||||||
GUINT32_FROM_LE(raw->devtype), raw->data_type);
|
|
||||||
raw_buf = raw->data;
|
|
||||||
while (total_data_len) {
|
|
||||||
if (total_data_len < sizeof(*raw_item))
|
|
||||||
break;
|
|
||||||
total_data_len -= sizeof(*raw_item);
|
|
||||||
|
|
||||||
raw_item = (struct fpi_print_data_item_fp2 *)raw_buf;
|
|
||||||
item_len = GUINT32_FROM_LE(raw_item->length);
|
|
||||||
fp_dbg("item len %d, total_data_len %d", (int) item_len, (int) total_data_len);
|
|
||||||
if (total_data_len < item_len) {
|
|
||||||
fp_err("corrupted fingerprint data");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
total_data_len -= item_len;
|
|
||||||
|
|
||||||
item = fpi_print_data_item_new(item_len);
|
|
||||||
/* FIXME: fp_print_data->data content is not endianness agnostic */
|
|
||||||
memcpy(item->data, raw_item->data, item_len);
|
|
||||||
data->prints = g_slist_prepend(data->prints, item);
|
|
||||||
|
|
||||||
raw_buf += sizeof(*raw_item);
|
|
||||||
raw_buf += item_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_slist_length(data->prints) == 0) {
|
|
||||||
fp_print_data_free(data);
|
|
||||||
data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_from_data:
|
|
||||||
* @buf: the data buffer
|
|
||||||
* @buflen: the length of the buffer
|
|
||||||
|
|
||||||
* Load a stored print from a data buffer. The contents of said buffer must
|
|
||||||
* be the untouched contents of a buffer previously supplied to you by the
|
|
||||||
* fp_print_data_get_data() function.
|
|
||||||
*
|
|
||||||
* Returns: the stored print represented by the data, or %NULL on error. Must
|
|
||||||
* be freed with fp_print_data_free() after use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
|
|
||||||
size_t buflen)
|
|
||||||
{
|
|
||||||
struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
|
|
||||||
|
|
||||||
fp_dbg("buffer size %zd", buflen);
|
|
||||||
if (buflen < sizeof(*raw))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (strncmp(raw->prefix, "FP1", 3) == 0) {
|
|
||||||
return fpi_print_data_from_fp1_data(buf, buflen);
|
|
||||||
} else if (strncmp(raw->prefix, "FP2", 3) == 0) {
|
|
||||||
return fpi_print_data_from_fp2_data(buf, buflen);
|
|
||||||
} else {
|
|
||||||
fp_dbg("bad header prefix");
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1,
|
|
||||||
enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2,
|
|
||||||
enum fp_print_data_type type2)
|
|
||||||
{
|
|
||||||
if (driver_id1 != driver_id2) {
|
|
||||||
fp_dbg("driver ID mismatch: %02x vs %02x", driver_id1, driver_id2);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (devtype1 != devtype2) {
|
|
||||||
fp_dbg("devtype mismatch: %04x vs %04x", devtype1, devtype2);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type1 != type2) {
|
|
||||||
fp_dbg("type mismatch: %d vs %d", type1, type2);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_free:
|
|
||||||
* @data: the stored print to destroy. If NULL, function simply returns.
|
|
||||||
*
|
|
||||||
* Frees a stored print. Must be called when you are finished using the print.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
if (data)
|
|
||||||
g_slist_free_full(data->prints, (GDestroyNotify)fpi_print_data_item_free);
|
|
||||||
g_free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_get_driver_id:
|
|
||||||
* @data: the stored print
|
|
||||||
|
|
||||||
* Gets the [driver ID](advanced-topics.html#driver_id) for a stored print. The driver ID
|
|
||||||
* indicates which driver the print originally came from. The print is
|
|
||||||
* only usable with a device controlled by that driver.
|
|
||||||
*
|
|
||||||
* Returns: the driver ID of the driver compatible with the print
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint16_t fp_print_data_get_driver_id(struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
return data->driver_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_get_devtype:
|
|
||||||
* @data: the stored print
|
|
||||||
|
|
||||||
* Gets the [devtype](advanced-topics.html#device-types) for a stored print. The devtype represents
|
|
||||||
* which type of device under the parent driver is compatible with the print.
|
|
||||||
*
|
|
||||||
* Returns: the devtype of the device range compatible with the print
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
return data->devtype;
|
|
||||||
}
|
|
|
@ -1,660 +0,0 @@
|
||||||
/*
|
|
||||||
* Core imaging device functions for libfprint
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#include "fpi-dev-img.h"
|
|
||||||
#include "fpi-async.h"
|
|
||||||
#include "fp_internal.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:fpi-dev-img
|
|
||||||
* @title: Image device operations
|
|
||||||
* @short_description: Image device operation functions
|
|
||||||
*
|
|
||||||
* As drivers work through different operations, they need to report back
|
|
||||||
* to the core as to their internal state, so errors and successes can be
|
|
||||||
* reported back to front-ends.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MIN_ACCEPTABLE_MINUTIAE 10
|
|
||||||
#define BOZORTH3_DEFAULT_THRESHOLD 40
|
|
||||||
#define IMG_ENROLL_STAGES 5
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_imgdev_get_action_state:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
*
|
|
||||||
* Returns the state of an imaging device while enrolling a fingerprint.
|
|
||||||
*
|
|
||||||
* Returns: a enum #fp_imgdev_enroll_state
|
|
||||||
*/
|
|
||||||
enum fp_imgdev_enroll_state
|
|
||||||
fpi_imgdev_get_action_state(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
return imgdev->action_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_imgdev_get_action:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
*
|
|
||||||
* Returns the current action being performed by an imaging device.
|
|
||||||
*
|
|
||||||
* Returns: a enum #fp_imgdev_action
|
|
||||||
*/
|
|
||||||
enum fp_imgdev_action
|
|
||||||
fpi_imgdev_get_action(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
return imgdev->action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_imgdev_get_action_result:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
*
|
|
||||||
* Returns an integer representing the result of an action. Which enum
|
|
||||||
* the result code is taken from depends on the current action being performed.
|
|
||||||
* See #fp_capture_result, #fp_enroll_result and #fp_verify_result.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
fpi_imgdev_get_action_result(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
return imgdev->action_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_imgdev_set_action_result:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
* @action_result: an action result
|
|
||||||
*
|
|
||||||
* Drivers should use fpi_imgdev_image_captured() instead. This function
|
|
||||||
* should not be used, and will be removed soon.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_imgdev_set_action_result(struct fp_img_dev *imgdev,
|
|
||||||
int action_result)
|
|
||||||
{
|
|
||||||
imgdev->action_result = action_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int img_dev_open(struct fp_dev *dev, unsigned long driver_data)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *imgdev = g_malloc0(sizeof(*imgdev));
|
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
|
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
/* Set up back pointers */
|
|
||||||
dev->img_dev = imgdev;
|
|
||||||
imgdev->parent = dev;
|
|
||||||
|
|
||||||
imgdev->enroll_stage = 0;
|
|
||||||
dev->nr_enroll_stages = IMG_ENROLL_STAGES;
|
|
||||||
|
|
||||||
if (imgdrv->open) {
|
|
||||||
r = imgdrv->open(imgdev, driver_data);
|
|
||||||
if (r)
|
|
||||||
goto err;
|
|
||||||
} else {
|
|
||||||
fpi_drvcb_open_complete(dev, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
err:
|
|
||||||
g_free(imgdev);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_imgdev_open_complete:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
* @status: an error code
|
|
||||||
*
|
|
||||||
* Function to call when the device has been opened, whether
|
|
||||||
* successfully of not.
|
|
||||||
*/
|
|
||||||
void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status)
|
|
||||||
{
|
|
||||||
fpi_drvcb_open_complete(FP_DEV(imgdev), status);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void img_dev_close(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
|
|
||||||
|
|
||||||
if (imgdrv->close)
|
|
||||||
imgdrv->close(dev->img_dev);
|
|
||||||
else
|
|
||||||
fpi_drvcb_close_complete(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_imgdev_close_complete:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
*
|
|
||||||
* Function to call when the device has been closed.
|
|
||||||
*/
|
|
||||||
void fpi_imgdev_close_complete(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
fpi_drvcb_close_complete(FP_DEV(imgdev));
|
|
||||||
g_free(imgdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dev_change_state(struct fp_img_dev *imgdev,
|
|
||||||
enum fp_imgdev_state state)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
|
||||||
|
|
||||||
if (!imgdrv->change_state)
|
|
||||||
return 0;
|
|
||||||
return imgdrv->change_state(imgdev, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check image properties and resize it if necessary. potentially returns a new
|
|
||||||
* image after freeing the old one. */
|
|
||||||
static int sanitize_image(struct fp_img_dev *imgdev, struct fp_img **_img)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
|
||||||
struct fp_img *img = *_img;
|
|
||||||
|
|
||||||
if (imgdrv->img_width > 0) {
|
|
||||||
img->width = imgdrv->img_width;
|
|
||||||
} else if (img->width <= 0) {
|
|
||||||
fp_err("no image width assigned");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imgdrv->img_height > 0) {
|
|
||||||
img->height = imgdrv->img_height;
|
|
||||||
} else if (img->height <= 0) {
|
|
||||||
fp_err("no image height assigned");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fpi_img_is_sane(img)) {
|
|
||||||
fp_err("image is not sane!");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_imgdev_report_finger_status:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
* @present: whether the finger is present on the sensor
|
|
||||||
*
|
|
||||||
* Reports from the driver whether the user's finger is on
|
|
||||||
* the sensor.
|
|
||||||
*/
|
|
||||||
void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
|
||||||
gboolean present)
|
|
||||||
{
|
|
||||||
int r = imgdev->action_result;
|
|
||||||
struct fp_print_data *data = imgdev->acquire_data;
|
|
||||||
struct fp_img *img = imgdev->acquire_img;
|
|
||||||
|
|
||||||
fp_dbg(present ? "finger on sensor" : "finger removed");
|
|
||||||
|
|
||||||
if (present && imgdev->action_state == IMG_ACQUIRE_STATE_AWAIT_FINGER_ON) {
|
|
||||||
dev_change_state(imgdev, IMGDEV_STATE_CAPTURE);
|
|
||||||
imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_IMAGE;
|
|
||||||
return;
|
|
||||||
} else if (present
|
|
||||||
|| imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF) {
|
|
||||||
fp_dbg("ignoring status report");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clear these before reporting results to avoid complications with
|
|
||||||
* call cascading in and out of the library */
|
|
||||||
imgdev->acquire_img = NULL;
|
|
||||||
imgdev->acquire_data = NULL;
|
|
||||||
|
|
||||||
/* finger removed, report results */
|
|
||||||
switch (imgdev->action) {
|
|
||||||
case IMG_ACTION_ENROLL:
|
|
||||||
fp_dbg("reporting enroll result");
|
|
||||||
data = imgdev->enroll_data;
|
|
||||||
if (r == FP_ENROLL_COMPLETE) {
|
|
||||||
imgdev->enroll_data = NULL;
|
|
||||||
}
|
|
||||||
fpi_drvcb_enroll_stage_completed(FP_DEV(imgdev), r,
|
|
||||||
r == FP_ENROLL_COMPLETE ? data : NULL,
|
|
||||||
img);
|
|
||||||
/* the callback can cancel enrollment, so recheck current
|
|
||||||
* action and the status to see if retry is needed */
|
|
||||||
if (imgdev->action == IMG_ACTION_ENROLL &&
|
|
||||||
r > 0 && r != FP_ENROLL_COMPLETE && r != FP_ENROLL_FAIL) {
|
|
||||||
imgdev->action_result = 0;
|
|
||||||
imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON;
|
|
||||||
dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_VERIFY:
|
|
||||||
fpi_drvcb_report_verify_result(FP_DEV(imgdev), r, img);
|
|
||||||
imgdev->action_result = 0;
|
|
||||||
fp_print_data_free(data);
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_IDENTIFY:
|
|
||||||
fpi_drvcb_report_identify_result(FP_DEV(imgdev), r,
|
|
||||||
imgdev->identify_match_offset, img);
|
|
||||||
imgdev->action_result = 0;
|
|
||||||
fp_print_data_free(data);
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_CAPTURE:
|
|
||||||
fpi_drvcb_report_capture_result(FP_DEV(imgdev), r, img);
|
|
||||||
imgdev->action_result = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fp_err("unhandled action %d", imgdev->action);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void verify_process_img(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv);
|
|
||||||
int match_score = imgdrv->bz3_threshold;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (match_score == 0)
|
|
||||||
match_score = BOZORTH3_DEFAULT_THRESHOLD;
|
|
||||||
|
|
||||||
r = fpi_img_compare_print_data(FP_DEV(imgdev)->verify_data,
|
|
||||||
imgdev->acquire_data);
|
|
||||||
|
|
||||||
if (r >= match_score)
|
|
||||||
r = FP_VERIFY_MATCH;
|
|
||||||
else if (r >= 0)
|
|
||||||
r = FP_VERIFY_NO_MATCH;
|
|
||||||
|
|
||||||
imgdev->action_result = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void identify_process_img(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv);
|
|
||||||
int match_score = imgdrv->bz3_threshold;
|
|
||||||
size_t match_offset;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (match_score == 0)
|
|
||||||
match_score = BOZORTH3_DEFAULT_THRESHOLD;
|
|
||||||
|
|
||||||
r = fpi_img_compare_print_data_to_gallery(imgdev->acquire_data,
|
|
||||||
FP_DEV(imgdev)->identify_gallery, match_score, &match_offset);
|
|
||||||
|
|
||||||
imgdev->action_result = r;
|
|
||||||
imgdev->identify_match_offset = match_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_imgdev_abort_scan:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
* @result: the scan result
|
|
||||||
*
|
|
||||||
* Aborts a scan after an error, and set the action result. See
|
|
||||||
* fpi_imgdev_get_action_result() for possible values.
|
|
||||||
*/
|
|
||||||
void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result)
|
|
||||||
{
|
|
||||||
imgdev->action_result = result;
|
|
||||||
imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF;
|
|
||||||
dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_imgdev_image_captured:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
* @img: an #fp_img image
|
|
||||||
*
|
|
||||||
* Report to the core that the driver captured this image from the sensor.
|
|
||||||
*/
|
|
||||||
void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
|
|
||||||
{
|
|
||||||
struct fp_print_data *print = NULL;
|
|
||||||
int r;
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
|
|
||||||
if (imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_IMAGE) {
|
|
||||||
fp_dbg("ignoring due to current state %d", imgdev->action_state);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imgdev->action_result) {
|
|
||||||
fp_dbg("not overwriting existing action result");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = sanitize_image(imgdev, &img);
|
|
||||||
if (r < 0) {
|
|
||||||
imgdev->action_result = r;
|
|
||||||
fp_img_free(img);
|
|
||||||
goto next_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_img_standardize(img);
|
|
||||||
imgdev->acquire_img = img;
|
|
||||||
if (imgdev->action != IMG_ACTION_CAPTURE) {
|
|
||||||
r = fpi_img_to_print_data(imgdev, img, &print);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_dbg("image to print data conversion error: %d", r);
|
|
||||||
imgdev->action_result = FP_ENROLL_RETRY;
|
|
||||||
goto next_state;
|
|
||||||
} else if (img->minutiae->num < MIN_ACCEPTABLE_MINUTIAE) {
|
|
||||||
fp_dbg("not enough minutiae, %d/%d", img->minutiae->num,
|
|
||||||
MIN_ACCEPTABLE_MINUTIAE);
|
|
||||||
fp_print_data_free(print);
|
|
||||||
/* depends on FP_ENROLL_RETRY == FP_VERIFY_RETRY */
|
|
||||||
imgdev->action_result = FP_ENROLL_RETRY;
|
|
||||||
goto next_state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
imgdev->acquire_data = print;
|
|
||||||
switch (imgdev->action) {
|
|
||||||
case IMG_ACTION_ENROLL:
|
|
||||||
if (!imgdev->enroll_data) {
|
|
||||||
imgdev->enroll_data = fpi_print_data_new(FP_DEV(imgdev));
|
|
||||||
}
|
|
||||||
BUG_ON(g_slist_length(print->prints) != 1);
|
|
||||||
/* Move print data from acquire data into enroll_data */
|
|
||||||
imgdev->enroll_data->prints =
|
|
||||||
g_slist_prepend(imgdev->enroll_data->prints, print->prints->data);
|
|
||||||
print->prints = g_slist_remove(print->prints, print->prints->data);
|
|
||||||
|
|
||||||
fp_print_data_free(imgdev->acquire_data);
|
|
||||||
imgdev->acquire_data = NULL;
|
|
||||||
imgdev->enroll_stage++;
|
|
||||||
if (imgdev->enroll_stage == FP_DEV(imgdev)->nr_enroll_stages)
|
|
||||||
imgdev->action_result = FP_ENROLL_COMPLETE;
|
|
||||||
else
|
|
||||||
imgdev->action_result = FP_ENROLL_PASS;
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_VERIFY:
|
|
||||||
verify_process_img(imgdev);
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_IDENTIFY:
|
|
||||||
identify_process_img(imgdev);
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_CAPTURE:
|
|
||||||
imgdev->action_result = FP_CAPTURE_COMPLETE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BUG();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
next_state:
|
|
||||||
imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF;
|
|
||||||
dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_imgdev_session_error:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
* @error: an error code
|
|
||||||
*
|
|
||||||
* Report an error that occurred in the driver.
|
|
||||||
*/
|
|
||||||
void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error)
|
|
||||||
{
|
|
||||||
fp_dbg("error %d", error);
|
|
||||||
BUG_ON(error == 0);
|
|
||||||
switch (imgdev->action) {
|
|
||||||
case IMG_ACTION_ENROLL:
|
|
||||||
fpi_drvcb_enroll_stage_completed(FP_DEV(imgdev), error, NULL, NULL);
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_VERIFY:
|
|
||||||
fpi_drvcb_report_verify_result(FP_DEV(imgdev), error, NULL);
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_IDENTIFY:
|
|
||||||
fpi_drvcb_report_identify_result(FP_DEV(imgdev), error, 0, NULL);
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_CAPTURE:
|
|
||||||
fpi_drvcb_report_capture_result(FP_DEV(imgdev), error, NULL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fp_err("unhandled action %d", imgdev->action);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_imgdev_activate_complete:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
* @status: the activation result
|
|
||||||
*
|
|
||||||
* Marks an activation as complete, whether successful or not.
|
|
||||||
* See fpi_imgdev_get_action_result() for possible values.
|
|
||||||
*/
|
|
||||||
void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status)
|
|
||||||
{
|
|
||||||
fp_dbg("status %d", status);
|
|
||||||
|
|
||||||
switch (imgdev->action) {
|
|
||||||
case IMG_ACTION_ENROLL:
|
|
||||||
fpi_drvcb_enroll_started(FP_DEV(imgdev), status);
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_VERIFY:
|
|
||||||
fpi_drvcb_verify_started(FP_DEV(imgdev), status);
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_IDENTIFY:
|
|
||||||
fpi_drvcb_identify_started(FP_DEV(imgdev), status);
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_CAPTURE:
|
|
||||||
fpi_drvcb_capture_started(FP_DEV(imgdev), status);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fp_err("unhandled action %d", imgdev->action);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == 0) {
|
|
||||||
imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON;
|
|
||||||
dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_imgdev_deactivate_complete:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
*
|
|
||||||
* Marks a deactivation as complete.
|
|
||||||
*/
|
|
||||||
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
enum fp_imgdev_action action;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
|
|
||||||
action = imgdev->action;
|
|
||||||
imgdev->action = IMG_ACTION_NONE;
|
|
||||||
imgdev->action_state = 0;
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
case IMG_ACTION_ENROLL:
|
|
||||||
fpi_drvcb_enroll_stopped(FP_DEV(imgdev));
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_VERIFY:
|
|
||||||
fpi_drvcb_verify_stopped(FP_DEV(imgdev));
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_IDENTIFY:
|
|
||||||
fpi_drvcb_identify_stopped(FP_DEV(imgdev));
|
|
||||||
break;
|
|
||||||
case IMG_ACTION_CAPTURE:
|
|
||||||
fpi_drvcb_capture_stopped(FP_DEV(imgdev));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fp_err("unhandled action %d", imgdev->action);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
|
||||||
int width = imgdrv->img_width;
|
|
||||||
|
|
||||||
if (width == -1)
|
|
||||||
width = 0;
|
|
||||||
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
|
||||||
int height = imgdrv->img_height;
|
|
||||||
|
|
||||||
if (height == -1)
|
|
||||||
height = 0;
|
|
||||||
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
|
||||||
|
|
||||||
if (!imgdrv->activate)
|
|
||||||
return 0;
|
|
||||||
return imgdrv->activate(imgdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
|
||||||
|
|
||||||
if (!imgdrv->deactivate)
|
|
||||||
return;
|
|
||||||
return imgdrv->deactivate(imgdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int generic_acquire_start(struct fp_dev *dev, int action)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *imgdev = dev->img_dev;
|
|
||||||
int r;
|
|
||||||
fp_dbg("action %d", action);
|
|
||||||
imgdev->action = action;
|
|
||||||
imgdev->action_state = IMG_ACQUIRE_STATE_ACTIVATING;
|
|
||||||
imgdev->enroll_stage = 0;
|
|
||||||
|
|
||||||
r = dev_activate(imgdev);
|
|
||||||
if (r < 0)
|
|
||||||
fp_err("activation failed with error %d", r);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void generic_acquire_stop(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
imgdev->action_state = IMG_ACQUIRE_STATE_DEACTIVATING;
|
|
||||||
dev_deactivate(imgdev);
|
|
||||||
|
|
||||||
fp_print_data_free(imgdev->acquire_data);
|
|
||||||
fp_print_data_free(imgdev->enroll_data);
|
|
||||||
fp_img_free(imgdev->acquire_img);
|
|
||||||
imgdev->acquire_data = NULL;
|
|
||||||
imgdev->enroll_data = NULL;
|
|
||||||
imgdev->acquire_img = NULL;
|
|
||||||
imgdev->action_result = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int img_dev_enroll_start(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return generic_acquire_start(dev, IMG_ACTION_ENROLL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int img_dev_verify_start(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return generic_acquire_start(dev, IMG_ACTION_VERIFY);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int img_dev_identify_start(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return generic_acquire_start(dev, IMG_ACTION_IDENTIFY);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int img_dev_capture_start(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
/* Unconditional capture is not supported yet */
|
|
||||||
if (dev->unconditional_capture)
|
|
||||||
return -ENOTSUP;
|
|
||||||
return generic_acquire_start(dev, IMG_ACTION_CAPTURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int img_dev_enroll_stop(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *imgdev = dev->img_dev;
|
|
||||||
BUG_ON(imgdev->action != IMG_ACTION_ENROLL);
|
|
||||||
generic_acquire_stop(imgdev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int img_dev_verify_stop(struct fp_dev *dev, gboolean iterating)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *imgdev = dev->img_dev;
|
|
||||||
BUG_ON(imgdev->action != IMG_ACTION_VERIFY);
|
|
||||||
generic_acquire_stop(imgdev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *imgdev = dev->img_dev;
|
|
||||||
BUG_ON(imgdev->action != IMG_ACTION_IDENTIFY);
|
|
||||||
generic_acquire_stop(imgdev);
|
|
||||||
imgdev->identify_match_offset = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int img_dev_capture_stop(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *imgdev = dev->img_dev;
|
|
||||||
BUG_ON(imgdev->action != IMG_ACTION_CAPTURE);
|
|
||||||
generic_acquire_stop(imgdev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fpi_img_driver_setup(struct fp_img_driver *idriver)
|
|
||||||
{
|
|
||||||
idriver->driver.type = DRIVER_IMAGING;
|
|
||||||
idriver->driver.open = img_dev_open;
|
|
||||||
idriver->driver.close = img_dev_close;
|
|
||||||
idriver->driver.enroll_start = img_dev_enroll_start;
|
|
||||||
idriver->driver.enroll_stop = img_dev_enroll_stop;
|
|
||||||
idriver->driver.verify_start = img_dev_verify_start;
|
|
||||||
idriver->driver.verify_stop = img_dev_verify_stop;
|
|
||||||
idriver->driver.identify_start = img_dev_identify_start;
|
|
||||||
idriver->driver.identify_stop = img_dev_identify_stop;
|
|
||||||
idriver->driver.capture_start = img_dev_capture_start;
|
|
||||||
idriver->driver.capture_stop = img_dev_capture_stop;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __FPI_DEV_IMG_H__
|
|
||||||
#define __FPI_DEV_IMG_H__
|
|
||||||
|
|
||||||
#include "fpi-dev.h"
|
|
||||||
#include "fpi-img.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_imgdev_action:
|
|
||||||
* @IMG_ACTION_NONE: no action
|
|
||||||
* @IMG_ACTION_ENROLL: device action is enrolling
|
|
||||||
* @IMG_ACTION_VERIFY: device action is verifying
|
|
||||||
* @IMG_ACTION_IDENTIFY: device action is identifying
|
|
||||||
* @IMG_ACTION_CAPTURE: device action is capturing
|
|
||||||
*
|
|
||||||
* The current action being performed by an imaging device. The current
|
|
||||||
* action can be gathered inside the driver using fpi_imgdev_get_action().
|
|
||||||
*/
|
|
||||||
enum fp_imgdev_action {
|
|
||||||
IMG_ACTION_NONE = 0,
|
|
||||||
IMG_ACTION_ENROLL,
|
|
||||||
IMG_ACTION_VERIFY,
|
|
||||||
IMG_ACTION_IDENTIFY,
|
|
||||||
IMG_ACTION_CAPTURE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_imgdev_state:
|
|
||||||
* @IMGDEV_STATE_INACTIVE: inactive
|
|
||||||
* @IMGDEV_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
|
|
||||||
* @IMGDEV_STATE_CAPTURE: capturing an image
|
|
||||||
* @IMGDEV_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
|
|
||||||
*
|
|
||||||
* The state of an imaging device while doing a capture. The state is
|
|
||||||
* passed through to the driver using the ::activate() or ::change_state() vfuncs.
|
|
||||||
*/
|
|
||||||
enum fp_imgdev_state {
|
|
||||||
IMGDEV_STATE_INACTIVE,
|
|
||||||
IMGDEV_STATE_AWAIT_FINGER_ON,
|
|
||||||
IMGDEV_STATE_CAPTURE,
|
|
||||||
IMGDEV_STATE_AWAIT_FINGER_OFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_imgdev_enroll_state:
|
|
||||||
* @IMG_ACQUIRE_STATE_NONE: doing nothing
|
|
||||||
* @IMG_ACQUIRE_STATE_ACTIVATING: activating the device
|
|
||||||
* @IMG_ACQUIRE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
|
|
||||||
* @IMG_ACQUIRE_STATE_AWAIT_IMAGE: waiting for the image to be captured
|
|
||||||
* @IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
|
|
||||||
* @IMG_ACQUIRE_STATE_DONE: enrollment has all the images it needs
|
|
||||||
* @IMG_ACQUIRE_STATE_DEACTIVATING: deactivating the device
|
|
||||||
*
|
|
||||||
* The state of an imaging device while enrolling a fingerprint. Given that enrollment
|
|
||||||
* requires multiple captures, a number of those states will be repeated before
|
|
||||||
* the state is @IMG_ACQUIRE_STATE_DONE.
|
|
||||||
*/
|
|
||||||
enum fp_imgdev_enroll_state {
|
|
||||||
IMG_ACQUIRE_STATE_NONE = 0,
|
|
||||||
IMG_ACQUIRE_STATE_ACTIVATING,
|
|
||||||
IMG_ACQUIRE_STATE_AWAIT_FINGER_ON,
|
|
||||||
IMG_ACQUIRE_STATE_AWAIT_IMAGE,
|
|
||||||
IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF,
|
|
||||||
IMG_ACQUIRE_STATE_DONE,
|
|
||||||
IMG_ACQUIRE_STATE_DEACTIVATING,
|
|
||||||
};
|
|
||||||
|
|
||||||
void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status);
|
|
||||||
void fpi_imgdev_close_complete(struct fp_img_dev *imgdev);
|
|
||||||
void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status);
|
|
||||||
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev);
|
|
||||||
void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
|
||||||
gboolean present);
|
|
||||||
void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img);
|
|
||||||
void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result);
|
|
||||||
void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error);
|
|
||||||
|
|
||||||
enum fp_imgdev_enroll_state fpi_imgdev_get_action_state(struct fp_img_dev *imgdev);
|
|
||||||
enum fp_imgdev_action fpi_imgdev_get_action(struct fp_img_dev *imgdev);
|
|
||||||
int fpi_imgdev_get_action_result(struct fp_img_dev *imgdev);
|
|
||||||
void fpi_imgdev_set_action_result(struct fp_img_dev *imgdev, int action_result);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,150 +0,0 @@
|
||||||
/*
|
|
||||||
* fp_dev types manipulation
|
|
||||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:fpi-dev
|
|
||||||
* @title: Device operations
|
|
||||||
* @short_description: Device operation functions
|
|
||||||
*
|
|
||||||
* Those macros and functions will help get access to and from struct #fp_dev,
|
|
||||||
* and struct #fp_img_dev types, as well as get and set the instance struct
|
|
||||||
* data, eg. the structure containing the data specific to each driver.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FP_DEV:
|
|
||||||
* @dev: a struct #fp_img_dev
|
|
||||||
*
|
|
||||||
* Returns the struct #fp_dev associated with @dev, or %NULL on failure.
|
|
||||||
*
|
|
||||||
* Returns: a struct #fp_dev or %NULL
|
|
||||||
*/
|
|
||||||
struct fp_dev *
|
|
||||||
FP_DEV(struct fp_img_dev *dev)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *imgdev;
|
|
||||||
|
|
||||||
g_return_val_if_fail (dev, NULL);
|
|
||||||
imgdev = (struct fp_img_dev *) dev;
|
|
||||||
return imgdev->parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FP_IMG_DEV:
|
|
||||||
* @dev: a struct #fp_dev representing an imaging device.
|
|
||||||
*
|
|
||||||
* Returns a struct #fp_img_dev associated with @dev, or %NULL on failure.
|
|
||||||
*
|
|
||||||
* Returns: a struct #fp_img_dev or %NULL
|
|
||||||
*/
|
|
||||||
struct fp_img_dev *
|
|
||||||
FP_IMG_DEV(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (dev, NULL);
|
|
||||||
g_return_val_if_fail (dev->drv, NULL);
|
|
||||||
g_return_val_if_fail (dev->drv->type == DRIVER_IMAGING, NULL);
|
|
||||||
return dev->img_dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_set_instance_data:
|
|
||||||
* @dev: a struct #fp_dev
|
|
||||||
* @instance_data: a pointer to the instance data
|
|
||||||
*
|
|
||||||
* Set the instance data for a struct #fp_dev. This is usually a structure
|
|
||||||
* private to the driver used to keep state and pass it as user_data to
|
|
||||||
* asynchronous functions.
|
|
||||||
*
|
|
||||||
* The core does not do any memory management for this data, so the driver
|
|
||||||
* itself will have to create and free its own structure when appropriate.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fp_dev_set_instance_data (struct fp_dev *dev,
|
|
||||||
void *instance_data)
|
|
||||||
{
|
|
||||||
g_return_if_fail (dev);
|
|
||||||
g_return_if_fail (instance_data != NULL);
|
|
||||||
g_return_if_fail (dev->instance_data == NULL);
|
|
||||||
|
|
||||||
dev->instance_data = instance_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FP_INSTANCE_DATA:
|
|
||||||
* @dev: a struct #fp_dev
|
|
||||||
*
|
|
||||||
* Returns the instance data set using fp_dev_set_instance_data().
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
FP_INSTANCE_DATA (struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (dev, NULL);
|
|
||||||
|
|
||||||
return dev->instance_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_dev_get_usb_dev:
|
|
||||||
* @dev: a struct #fp_dev
|
|
||||||
*
|
|
||||||
* Returns the #libusb_device_handle associated with @dev or %NULL
|
|
||||||
* if none are associated.
|
|
||||||
*
|
|
||||||
* Returns: a #libusb_device_handle pointer or %NULL
|
|
||||||
*/
|
|
||||||
libusb_device_handle *
|
|
||||||
fpi_dev_get_usb_dev(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->udev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_dev_set_nr_enroll_stages:
|
|
||||||
* @dev: a struct #fp_dev
|
|
||||||
* @nr_enroll_stages: the number of enroll stages
|
|
||||||
*
|
|
||||||
* Sets the number of enroll stages that this device uses. This is
|
|
||||||
* usually only necessary for primitive devices which have a hard-coded
|
|
||||||
* number of enroll stages baked into their protocol.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_dev_set_nr_enroll_stages(struct fp_dev *dev,
|
|
||||||
int nr_enroll_stages)
|
|
||||||
{
|
|
||||||
dev->nr_enroll_stages = nr_enroll_stages;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_dev_get_verify_data:
|
|
||||||
* @dev: a struct #fp_dev
|
|
||||||
*
|
|
||||||
* Returns the verify data associated with @dev.
|
|
||||||
* This is usually only necessary for primitive devices which need to
|
|
||||||
* have access to the raw verify data as it might have been stored on disk.
|
|
||||||
*
|
|
||||||
* Returns: a struct #fp_print_data pointer or %NULL
|
|
||||||
*/
|
|
||||||
struct fp_print_data *
|
|
||||||
fpi_dev_get_verify_data(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->verify_data;
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __FPI_DEV_H__
|
|
||||||
#define __FPI_DEV_H__
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
#include <fprint.h>
|
|
||||||
|
|
||||||
struct fp_dev;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_img_dev:
|
|
||||||
*
|
|
||||||
* #fp_img_dev is an opaque structure type. You must access it using the
|
|
||||||
* appropriate functions.
|
|
||||||
*/
|
|
||||||
struct fp_img_dev;
|
|
||||||
|
|
||||||
struct fp_dev *FP_DEV (struct fp_img_dev *dev);
|
|
||||||
struct fp_img_dev *FP_IMG_DEV (struct fp_dev *dev);
|
|
||||||
|
|
||||||
void fp_dev_set_instance_data (struct fp_dev *dev,
|
|
||||||
void *instance_data);
|
|
||||||
void *FP_INSTANCE_DATA (struct fp_dev *dev);
|
|
||||||
|
|
||||||
libusb_device_handle *fpi_dev_get_usb_dev(struct fp_dev *dev);
|
|
||||||
void fpi_dev_set_nr_enroll_stages(struct fp_dev *dev,
|
|
||||||
int nr_enroll_stages);
|
|
||||||
struct fp_print_data *fpi_dev_get_verify_data(struct fp_dev *dev);
|
|
||||||
|
|
||||||
#endif
|
|
252
libfprint/fpi-device.h
Normal file
252
libfprint/fpi-device.h
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
/*
|
||||||
|
* FpDevice - A fingerprint reader device
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gusb.h>
|
||||||
|
#include "fp-device.h"
|
||||||
|
#include "fp-image.h"
|
||||||
|
#include "fpi-print.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpIdEntry:
|
||||||
|
*
|
||||||
|
* An entry in the table of supported hardware. For USB devices, the product ID
|
||||||
|
* and vendor ID should be provided. The optional @driver_data field defaults
|
||||||
|
* to 0 and can be used as a simple flag for device quirks.
|
||||||
|
*/
|
||||||
|
typedef struct _FpIdEntry FpIdEntry;
|
||||||
|
|
||||||
|
struct _FpIdEntry
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
guint pid;
|
||||||
|
guint vid;
|
||||||
|
};
|
||||||
|
const gchar *virtual_envvar;
|
||||||
|
};
|
||||||
|
guint64 driver_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpDeviceClass:
|
||||||
|
* @id: ID string for the driver. Should be a valid C identifier and should
|
||||||
|
* match the drivers file name.
|
||||||
|
* @full_name: Human readable description of the driver
|
||||||
|
* @type: The type of driver
|
||||||
|
* @id_table: The table of IDs to bind the driver to
|
||||||
|
* @nr_enroll_stages: The number of enroll stages supported devices need; use
|
||||||
|
* fpi_device_set_nr_enroll_stages() from @probe if this is dynamic.
|
||||||
|
* @scan_type: The scan type of supported devices; use
|
||||||
|
* fpi_device_set_scan_type() from @probe if this is dynamic.
|
||||||
|
* @usb_discover: Class method to check whether a USB device is supported by
|
||||||
|
* the driver. Should return 0 if the device is unsupported and a positive
|
||||||
|
* score otherwise. The default score is 50 and the driver with the highest
|
||||||
|
* score will be loaded.
|
||||||
|
* @probe: Called immediately for all devices. Most drivers will not need to
|
||||||
|
* implement this. Drivers should setup the device identifier from the probe
|
||||||
|
* callback which will be used to verify the compatibility of stored
|
||||||
|
* #FpPrint's. It is permissable to temporarily open the USB device if this
|
||||||
|
* is required for the operation. If an error is returned, then the device
|
||||||
|
* will be destroyed again immediately and never reported to the API user.
|
||||||
|
* @open: Open the device for futher operations. Any of the normal actions are
|
||||||
|
* guaranteed to only happen when the device is open (this includes delete).
|
||||||
|
* @close: Close the device again
|
||||||
|
* @enroll: Start an enroll operation
|
||||||
|
* @verify: Start a verify operation
|
||||||
|
* @identify: Start an identify operation
|
||||||
|
* @capture: Start a capture operation
|
||||||
|
* @list: List prints stored on the device
|
||||||
|
* @delete: Delete a print from the device
|
||||||
|
* @cancel: Called on cancellation, this is a convenience to not need to handle
|
||||||
|
* the #GCancellable directly by using fpi_device_get_cancellable().
|
||||||
|
*
|
||||||
|
* NOTE: If your driver is image based, then you should subclass #FpImageDevice
|
||||||
|
* instead. #FpImageDevice based drivers use a different way of interacting
|
||||||
|
* with libfprint.
|
||||||
|
*
|
||||||
|
* These are the main entry points for drivers to implement. Drivers may not
|
||||||
|
* implement all of these entry points if they do not support the operation
|
||||||
|
* (or a default implementation is sufficient).
|
||||||
|
*
|
||||||
|
* Drivers must eventually call the corresponding function to finish the
|
||||||
|
* operation. It is also acceptable to call the generic
|
||||||
|
* fpi_device_action_error() function but doing so is not recommended in most
|
||||||
|
* usecases.
|
||||||
|
*
|
||||||
|
* Drivers must also handle cancellation properly for any long running
|
||||||
|
* operation (i.e. any operation that requires capturing). It is entirely fine
|
||||||
|
* to ignore cancellation requests for short operations (e.g. open/close).
|
||||||
|
*
|
||||||
|
* This API is solely intended for drivers. It is purely internal and neither
|
||||||
|
* API nor ABI stable.
|
||||||
|
*/
|
||||||
|
struct _FpDeviceClass
|
||||||
|
{
|
||||||
|
/*< private >*/
|
||||||
|
GObjectClass parent_class;
|
||||||
|
|
||||||
|
/*< public >*/
|
||||||
|
/* Static information about the driver. */
|
||||||
|
const gchar *id;
|
||||||
|
const gchar *full_name;
|
||||||
|
FpDeviceType type;
|
||||||
|
const FpIdEntry *id_table;
|
||||||
|
|
||||||
|
/* Defaults for device properties */
|
||||||
|
gint nr_enroll_stages;
|
||||||
|
FpScanType scan_type;
|
||||||
|
|
||||||
|
/* Callbacks */
|
||||||
|
gint (*usb_discover) (GUsbDevice *usb_device);
|
||||||
|
void (*probe) (FpDevice *device);
|
||||||
|
void (*open) (FpDevice *device);
|
||||||
|
void (*close) (FpDevice *device);
|
||||||
|
void (*enroll) (FpDevice *device);
|
||||||
|
void (*verify) (FpDevice *device);
|
||||||
|
void (*identify) (FpDevice *device);
|
||||||
|
void (*capture) (FpDevice *device);
|
||||||
|
void (*list) (FpDevice *device);
|
||||||
|
void (*delete) (FpDevice * device);
|
||||||
|
|
||||||
|
void (*cancel) (FpDevice *device);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpTimeoutFunc:
|
||||||
|
* @device: The #FpDevice passed to fpi_device_add_timeout()
|
||||||
|
* @user_data: the data passed to fpi_device_add_timeout()
|
||||||
|
*
|
||||||
|
* The prototype of the callback function for fpi_device_add_timeout().
|
||||||
|
*/
|
||||||
|
typedef void (*FpTimeoutFunc) (FpDevice *device,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpDeviceAction:
|
||||||
|
* @FP_DEVICE_ACTION_NONE: No action is active.
|
||||||
|
* @FP_DEVICE_ACTION_PROBE: Probe device for support and information.
|
||||||
|
* @FP_DEVICE_ACTION_OPEN: Device is currently being opened.
|
||||||
|
* @FP_DEVICE_ACTION_CLOSE: Device is currently being closed.
|
||||||
|
* @FP_DEVICE_ACTION_ENROLL: Device is currently enrolling.
|
||||||
|
* @FP_DEVICE_ACTION_VERIFY: Device is currently verifying.
|
||||||
|
* @FP_DEVICE_ACTION_IDENTIFY: Device is currently identifying.
|
||||||
|
* @FP_DEVICE_ACTION_CAPTURE: Device is currently capturing an image.
|
||||||
|
* @FP_DEVICE_ACTION_LIST: Device stored prints are being queried.
|
||||||
|
* @FP_DEVICE_ACTION_DELETE: Device stored print is being deleted.
|
||||||
|
*
|
||||||
|
* Current active action of the device. A driver can retrieve the action.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FP_DEVICE_ACTION_NONE = 0,
|
||||||
|
FP_DEVICE_ACTION_PROBE,
|
||||||
|
FP_DEVICE_ACTION_OPEN,
|
||||||
|
FP_DEVICE_ACTION_CLOSE,
|
||||||
|
FP_DEVICE_ACTION_ENROLL,
|
||||||
|
FP_DEVICE_ACTION_VERIFY,
|
||||||
|
FP_DEVICE_ACTION_IDENTIFY,
|
||||||
|
FP_DEVICE_ACTION_CAPTURE,
|
||||||
|
FP_DEVICE_ACTION_LIST,
|
||||||
|
FP_DEVICE_ACTION_DELETE,
|
||||||
|
} FpDeviceAction;
|
||||||
|
|
||||||
|
GUsbDevice *fpi_device_get_usb_device (FpDevice *device);
|
||||||
|
const gchar *fpi_device_get_virtual_env (FpDevice *device);
|
||||||
|
//const gchar *fpi_device_get_spi_dev (FpDevice *device);
|
||||||
|
|
||||||
|
|
||||||
|
FpDeviceAction fpi_device_get_current_action (FpDevice *device);
|
||||||
|
gboolean fpi_device_action_is_cancelled (FpDevice *device);
|
||||||
|
|
||||||
|
GError * fpi_device_retry_new (FpDeviceRetry error);
|
||||||
|
GError * fpi_device_error_new (FpDeviceError error);
|
||||||
|
|
||||||
|
GError * fpi_device_retry_new_msg (FpDeviceRetry error,
|
||||||
|
const gchar *msg);
|
||||||
|
GError * fpi_device_error_new_msg (FpDeviceError error,
|
||||||
|
const gchar *msg);
|
||||||
|
|
||||||
|
guint64 fpi_device_get_driver_data (FpDevice *device);
|
||||||
|
|
||||||
|
void fpi_device_get_enroll_data (FpDevice *device,
|
||||||
|
FpPrint **print);
|
||||||
|
|
||||||
|
void fpi_device_get_capture_data (FpDevice *device,
|
||||||
|
gboolean *wait_for_finger);
|
||||||
|
void fpi_device_get_verify_data (FpDevice *device,
|
||||||
|
FpPrint **print);
|
||||||
|
void fpi_device_get_identify_data (FpDevice *device,
|
||||||
|
GPtrArray **prints);
|
||||||
|
void fpi_device_get_delete_data (FpDevice *device,
|
||||||
|
FpPrint **print);
|
||||||
|
GCancellable *fpi_device_get_cancellable (FpDevice *device);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GSource * fpi_device_add_timeout (FpDevice *device,
|
||||||
|
gint interval,
|
||||||
|
FpTimeoutFunc func,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void fpi_device_set_nr_enroll_stages (FpDevice *device,
|
||||||
|
gint enroll_stages);
|
||||||
|
|
||||||
|
void fpi_device_set_scan_type (FpDevice *device,
|
||||||
|
FpScanType scan_type);
|
||||||
|
|
||||||
|
void fpi_device_action_error (FpDevice *device,
|
||||||
|
GError *error);
|
||||||
|
|
||||||
|
void fpi_device_probe_complete (FpDevice *device,
|
||||||
|
const gchar *device_id,
|
||||||
|
const gchar *device_name,
|
||||||
|
GError *error);
|
||||||
|
void fpi_device_open_complete (FpDevice *device,
|
||||||
|
GError *error);
|
||||||
|
void fpi_device_close_complete (FpDevice *device,
|
||||||
|
GError *error);
|
||||||
|
void fpi_device_enroll_complete (FpDevice *device,
|
||||||
|
FpPrint *print,
|
||||||
|
GError *error);
|
||||||
|
void fpi_device_verify_complete (FpDevice *device,
|
||||||
|
FpiMatchResult result,
|
||||||
|
FpPrint *print,
|
||||||
|
GError *error);
|
||||||
|
void fpi_device_identify_complete (FpDevice *device,
|
||||||
|
FpPrint *match,
|
||||||
|
FpPrint *print,
|
||||||
|
GError *error);
|
||||||
|
void fpi_device_capture_complete (FpDevice *device,
|
||||||
|
FpImage *image,
|
||||||
|
GError *error);
|
||||||
|
void fpi_device_delete_complete (FpDevice *device,
|
||||||
|
GError *error);
|
||||||
|
void fpi_device_list_complete (FpDevice *device,
|
||||||
|
GPtrArray *prints,
|
||||||
|
GError *error);
|
||||||
|
|
||||||
|
void fpi_device_enroll_progress (FpDevice *device,
|
||||||
|
gint completed_stages,
|
||||||
|
FpPrint *print,
|
||||||
|
GError *error);
|
||||||
|
|
||||||
|
G_END_DECLS
|
118
libfprint/fpi-image-device.h
Normal file
118
libfprint/fpi-image-device.h
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* FpImageDevice - An image based fingerprint reader device
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "fpi-device.h"
|
||||||
|
#include "fp-image-device.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpImageDeviceState:
|
||||||
|
* @FP_IMAGE_DEVICE_STATE_INACTIVE: inactive
|
||||||
|
* @FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
|
||||||
|
* @FP_IMAGE_DEVICE_STATE_CAPTURE: capturing an image
|
||||||
|
* @FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
|
||||||
|
*
|
||||||
|
* The state of an imaging device while doing a capture. The state is
|
||||||
|
* passed through to the driver using the ::activate() or ::change_state() vfuncs.
|
||||||
|
*
|
||||||
|
* The driver needs to call fpi_image_device_report_finger_status() to move
|
||||||
|
* between the different states. Note that the capture state might be entered
|
||||||
|
* unconditionally if the device supports raw capturing.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FP_IMAGE_DEVICE_STATE_INACTIVE,
|
||||||
|
FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON,
|
||||||
|
FP_IMAGE_DEVICE_STATE_CAPTURE,
|
||||||
|
FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF,
|
||||||
|
} FpImageDeviceState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpImageDeviceClass:
|
||||||
|
* @bz3_threshold: Threshold to consider bozorth3 score a match, default: 40
|
||||||
|
* @img_width: Width of the image, only provide if constant
|
||||||
|
* @img_height: Height of the image, only provide if constant
|
||||||
|
* @img_open: Open the device and do basic initialization
|
||||||
|
* (use this instead of the #FpDeviceClass open vfunc)
|
||||||
|
* @img_close: Close the device
|
||||||
|
* (use this instead of the #FpDeviceClass close vfunc)
|
||||||
|
* @activate: Start image capture and finger detection
|
||||||
|
* @deactivate: Stop image capture and finger detection
|
||||||
|
* @change_state: Notification about the current device state (i.e. waiting for
|
||||||
|
* finger or image capture). Implementing this is optional, it can e.g. be
|
||||||
|
* used to flash an LED when waiting for a finger.
|
||||||
|
*
|
||||||
|
* These are the main entry points for image based drivers. For all but the
|
||||||
|
* change_state vfunc, implementations *must* eventually call the corresponding
|
||||||
|
* function to finish the operation. It is also acceptable to call the generic
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* These are the main entry points for drivers to implement. Drivers may not
|
||||||
|
* implement all of these entry points if they do not support the operation
|
||||||
|
* (or a default implementation is sufficient).
|
||||||
|
*
|
||||||
|
* Drivers *must* eventually call the corresponding function to finish the
|
||||||
|
* operation. It is also acceptable to call the generic
|
||||||
|
* fpi_device_action_error() function but doing so is not recommended in most
|
||||||
|
* usecases.
|
||||||
|
*
|
||||||
|
* Drivers *must* also handle cancellation properly for any long running
|
||||||
|
* operation (i.e. any operation that requires capturing). It is entirely fine
|
||||||
|
* to ignore cancellation requests for short operations (e.g. open/close).
|
||||||
|
*
|
||||||
|
* This API is solely intended for drivers. It is purely internal and neither
|
||||||
|
* API nor ABI stable.
|
||||||
|
*/
|
||||||
|
struct _FpImageDeviceClass
|
||||||
|
{
|
||||||
|
FpDeviceClass parent_class;
|
||||||
|
|
||||||
|
gint bz3_threshold;
|
||||||
|
gint img_width;
|
||||||
|
gint img_height;
|
||||||
|
|
||||||
|
void (*img_open) (FpImageDevice *dev);
|
||||||
|
void (*img_close) (FpImageDevice *dev);
|
||||||
|
void (*activate) (FpImageDevice *dev);
|
||||||
|
void (*change_state) (FpImageDevice *dev,
|
||||||
|
FpImageDeviceState state);
|
||||||
|
void (*deactivate) (FpImageDevice *dev);
|
||||||
|
};
|
||||||
|
|
||||||
|
void fpi_image_device_set_bz3_threshold (FpImageDevice *self,
|
||||||
|
gint bz3_threshold);
|
||||||
|
|
||||||
|
void fpi_image_device_session_error (FpImageDevice *self,
|
||||||
|
GError *error);
|
||||||
|
|
||||||
|
void fpi_image_device_open_complete (FpImageDevice *self,
|
||||||
|
GError *error);
|
||||||
|
void fpi_image_device_close_complete (FpImageDevice *self,
|
||||||
|
GError *error);
|
||||||
|
void fpi_image_device_activate_complete (FpImageDevice *self,
|
||||||
|
GError *error);
|
||||||
|
void fpi_image_device_deactivate_complete (FpImageDevice *self,
|
||||||
|
GError *error);
|
||||||
|
|
||||||
|
void fpi_image_device_report_finger_status (FpImageDevice *self,
|
||||||
|
gboolean present);
|
||||||
|
void fpi_image_device_image_captured (FpImageDevice *self,
|
||||||
|
FpImage *image);
|
||||||
|
void fpi_image_device_retry_scan (FpImageDevice *self,
|
||||||
|
FpDeviceRetry retry);
|
83
libfprint/fpi-image.h
Normal file
83
libfprint/fpi-image.h
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* FPrint Image
|
||||||
|
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include "fp-image.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpiImageFlags:
|
||||||
|
* @FPI_IMAGE_V_FLIPPED: the image is vertically flipped
|
||||||
|
* @FPI_IMAGE_H_FLIPPED: the image is horizontally flipped
|
||||||
|
* @FPI_IMAGE_COLORS_INVERTED: the colours are inverted
|
||||||
|
*
|
||||||
|
* Flags used in an #FpImage structure to describe the contained image.
|
||||||
|
* This is useful for image drivers as they can simply set these flags and
|
||||||
|
* rely on the image to be normalized by libfprint before further processing.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FPI_IMAGE_V_FLIPPED = 1 << 0,
|
||||||
|
FPI_IMAGE_H_FLIPPED = 1 << 1,
|
||||||
|
FPI_IMAGE_COLORS_INVERTED = 1 << 2,
|
||||||
|
} FpiImageFlags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpImage:
|
||||||
|
* @width: Width of the image
|
||||||
|
* @height: Height of the image
|
||||||
|
* @ppmm: Pixels per millimeter
|
||||||
|
* @flags: #FpiImageFlags for required normalization
|
||||||
|
*
|
||||||
|
* Structure holding an image. The public fields are only public for internal
|
||||||
|
* use by the drivers.
|
||||||
|
*/
|
||||||
|
struct _FpImage
|
||||||
|
{
|
||||||
|
/*< private >*/
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
|
/*< public >*/
|
||||||
|
guint width;
|
||||||
|
guint height;
|
||||||
|
|
||||||
|
gdouble ppmm;
|
||||||
|
|
||||||
|
FpiImageFlags flags;
|
||||||
|
|
||||||
|
/*< private >*/
|
||||||
|
guint8 *data;
|
||||||
|
guint8 *binarized;
|
||||||
|
|
||||||
|
GPtrArray *minutiae;
|
||||||
|
guint ref_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
gint fpi_std_sq_dev (const guint8 *buf,
|
||||||
|
gint size);
|
||||||
|
gint fpi_mean_sq_diff_norm (const guint8 *buf1,
|
||||||
|
const guint8 *buf2,
|
||||||
|
gint size);
|
||||||
|
|
||||||
|
#if HAVE_PIXMAN
|
||||||
|
FpImage *fpi_image_resize (FpImage *orig,
|
||||||
|
guint w_factor,
|
||||||
|
guint h_factor);
|
||||||
|
#endif
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
* Imaging utility functions for libfprint
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2013 Vasily Khoruzhick <anarsoul@gmail.com>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <pixman.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_img_resize:
|
|
||||||
* @img: an #fp_img image
|
|
||||||
* @w_factor: horizontal factor to resize the image by
|
|
||||||
* @h_factor: vertical factor to resize the image by
|
|
||||||
*
|
|
||||||
* Resizes the #fp_img image by scaling it by @w_factor times horizontally
|
|
||||||
* and @h_factor times vertically.
|
|
||||||
*
|
|
||||||
* Returns: a newly allocated #fp_img, the original @img will not be modified
|
|
||||||
* and will also need to be freed
|
|
||||||
*/
|
|
||||||
struct fp_img *fpi_img_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor)
|
|
||||||
{
|
|
||||||
int new_width = img->width * w_factor;
|
|
||||||
int new_height = img->height * h_factor;
|
|
||||||
pixman_image_t *orig, *resized;
|
|
||||||
pixman_transform_t transform;
|
|
||||||
struct fp_img *newimg;
|
|
||||||
|
|
||||||
orig = pixman_image_create_bits(PIXMAN_a8, img->width, img->height, (uint32_t *)img->data, img->width);
|
|
||||||
resized = pixman_image_create_bits(PIXMAN_a8, new_width, new_height, NULL, new_width);
|
|
||||||
|
|
||||||
pixman_transform_init_identity(&transform);
|
|
||||||
pixman_transform_scale(NULL, &transform, pixman_int_to_fixed(w_factor), pixman_int_to_fixed(h_factor));
|
|
||||||
pixman_image_set_transform(orig, &transform);
|
|
||||||
pixman_image_set_filter(orig, PIXMAN_FILTER_BILINEAR, NULL, 0);
|
|
||||||
pixman_image_composite32(PIXMAN_OP_SRC,
|
|
||||||
orig, /* src */
|
|
||||||
NULL, /* mask */
|
|
||||||
resized, /* dst */
|
|
||||||
0, 0, /* src x y */
|
|
||||||
0, 0, /* mask x y */
|
|
||||||
0, 0, /* dst x y */
|
|
||||||
new_width, new_height /* width height */
|
|
||||||
);
|
|
||||||
|
|
||||||
newimg = fpi_img_new(new_width * new_height);
|
|
||||||
newimg->width = new_width;
|
|
||||||
newimg->height = new_height;
|
|
||||||
newimg->flags = img->flags;
|
|
||||||
|
|
||||||
memcpy(newimg->data, pixman_image_get_data(resized), new_width * new_height);
|
|
||||||
|
|
||||||
pixman_image_unref(orig);
|
|
||||||
pixman_image_unref(resized);
|
|
||||||
|
|
||||||
return newimg;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,682 +0,0 @@
|
||||||
/*
|
|
||||||
* Image management functions for libfprint
|
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
#include "nbis/include/bozorth.h"
|
|
||||||
#include "nbis/include/lfs.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:img
|
|
||||||
* @title: Image operations
|
|
||||||
* @short_description: Image operation functions
|
|
||||||
*
|
|
||||||
* libfprint offers several ways of retrieving images from imaging devices,
|
|
||||||
* one example being the fp_dev_img_capture() function. The functions
|
|
||||||
* documented below allow you to work with such images.
|
|
||||||
*
|
|
||||||
* # Image format # {#img_fmt}
|
|
||||||
* All images are represented as 8-bit greyscale data.
|
|
||||||
*
|
|
||||||
* # Image standardization # {#img_std}
|
|
||||||
* In some contexts, images you are provided through libfprint are raw images
|
|
||||||
* from the hardware. The orientation of these varies from device-to-device,
|
|
||||||
* as does the color scheme (black-on-white or white-on-black?). libfprint
|
|
||||||
* provides the fp_img_standardize() function to convert images into standard
|
|
||||||
* form, which is defined to be: finger flesh as black on white surroundings,
|
|
||||||
* natural upright orientation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:fpi-img
|
|
||||||
* @title: Driver Image operations
|
|
||||||
* @short_description: Driver image operation functions
|
|
||||||
*
|
|
||||||
* Those are the driver-specific helpers for #fp_img manipulation. See #fp_img's
|
|
||||||
* documentation for more information about data formats, and their uses in
|
|
||||||
* front-end applications.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_img_new:
|
|
||||||
* @length: the length of data to allocate
|
|
||||||
*
|
|
||||||
* Creates a new #fp_img structure with @length bytes of data allocated
|
|
||||||
* to hold the image.
|
|
||||||
*
|
|
||||||
* Returns: a new #fp_img to free with fp_img_free()
|
|
||||||
*/
|
|
||||||
struct fp_img *fpi_img_new(size_t length)
|
|
||||||
{
|
|
||||||
struct fp_img *img = g_malloc0(sizeof(*img) + length);
|
|
||||||
fp_dbg("length=%zd", length);
|
|
||||||
img->length = length;
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_img_new_for_imgdev:
|
|
||||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
|
||||||
*
|
|
||||||
* Creates a new #fp_img structure, like fpi_img_new(), but uses the
|
|
||||||
* driver's advertised height and width to calculate the size of the
|
|
||||||
* length of data to allocate.
|
|
||||||
*
|
|
||||||
* Returns: a new #fp_img to free with fp_img_free()
|
|
||||||
*/
|
|
||||||
struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev)
|
|
||||||
{
|
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv);
|
|
||||||
int width = imgdrv->img_width;
|
|
||||||
int height = imgdrv->img_height;
|
|
||||||
struct fp_img *img = fpi_img_new(width * height);
|
|
||||||
img->width = width;
|
|
||||||
img->height = height;
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_img_is_sane:
|
|
||||||
* @img: a #fp_img image
|
|
||||||
*
|
|
||||||
* Checks whether an #fp_img structure passes some basic checks, such
|
|
||||||
* as length, width and height being non-zero, and the buffer being
|
|
||||||
* big enough to hold the image of said size.
|
|
||||||
*
|
|
||||||
* Returns: %TRUE if the image is sane, %FALSE otherwise
|
|
||||||
*/
|
|
||||||
gboolean fpi_img_is_sane(struct fp_img *img)
|
|
||||||
{
|
|
||||||
guint len;
|
|
||||||
|
|
||||||
/* basic checks */
|
|
||||||
if (!img->length || img->width <= 0 || img->height <= 0)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* Are width and height just too big? */
|
|
||||||
if (!g_uint_checked_mul(&len, img->width, img->height) ||
|
|
||||||
len > G_MAXINT)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* buffer big enough? */
|
|
||||||
if (len > img->length)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_img_realloc:
|
|
||||||
* @img: an #fp_img image
|
|
||||||
* @newsize: the new length of the image
|
|
||||||
*
|
|
||||||
* Changes the size of the data part of the #fp_img.
|
|
||||||
*
|
|
||||||
* Returns: the modified #fp_img, the same as the first argument to this function
|
|
||||||
*/
|
|
||||||
struct fp_img *fpi_img_realloc(struct fp_img *img, size_t newsize)
|
|
||||||
{
|
|
||||||
return g_realloc(img, sizeof(*img) + newsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_img_free:
|
|
||||||
* @img: the image to destroy. If %NULL, function simply returns.
|
|
||||||
*
|
|
||||||
* Frees an image. Must be called when you are finished working with an image.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_img_free(struct fp_img *img)
|
|
||||||
{
|
|
||||||
if (!img)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (img->minutiae)
|
|
||||||
free_minutiae(img->minutiae);
|
|
||||||
if (img->binarized)
|
|
||||||
free(img->binarized);
|
|
||||||
g_free(img);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_img_get_height:
|
|
||||||
* @img: an image
|
|
||||||
*
|
|
||||||
* Gets the pixel height of an image.
|
|
||||||
*
|
|
||||||
* Returns: the height of the image
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_img_get_height(struct fp_img *img)
|
|
||||||
{
|
|
||||||
return img->height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_img_get_width:
|
|
||||||
* @img: an image
|
|
||||||
*
|
|
||||||
* Gets the pixel width of an image.
|
|
||||||
*
|
|
||||||
* Returns: the width of the image
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_img_get_width(struct fp_img *img)
|
|
||||||
{
|
|
||||||
return img->width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_img_get_data:
|
|
||||||
* @img: an image
|
|
||||||
*
|
|
||||||
* Gets the greyscale data for an image. This data must not be modified or
|
|
||||||
* freed, and must not be used after fp_img_free() has been called.
|
|
||||||
*
|
|
||||||
* Returns: a pointer to libfprint's internal data for the image
|
|
||||||
*/
|
|
||||||
API_EXPORTED unsigned char *fp_img_get_data(struct fp_img *img)
|
|
||||||
{
|
|
||||||
return img->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_img_save_to_file:
|
|
||||||
* @img: the image to save
|
|
||||||
* @path: the path to save the image. Existing files will be overwritten.
|
|
||||||
*
|
|
||||||
* A quick convenience function to save an image to a file in
|
|
||||||
* [PGM format](http://netpbm.sourceforge.net/doc/pgm.html).
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_img_save_to_file(struct fp_img *img, char *path)
|
|
||||||
{
|
|
||||||
FILE *fd = fopen(path, "w");
|
|
||||||
size_t write_size = img->width * img->height;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!fd) {
|
|
||||||
fp_dbg("could not open '%s' for writing: %d", path, errno);
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = fprintf(fd, "P5 %d %d 255\n", img->width, img->height);
|
|
||||||
if (r < 0) {
|
|
||||||
fclose(fd);
|
|
||||||
fp_err("pgm header write failed, error %d", r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = fwrite(img->data, 1, write_size, fd);
|
|
||||||
if (r < write_size) {
|
|
||||||
fclose(fd);
|
|
||||||
fp_err("short write (%d)", r);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fd);
|
|
||||||
fp_dbg("written to '%s'", path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vflip(struct fp_img *img)
|
|
||||||
{
|
|
||||||
int width = img->width;
|
|
||||||
int data_len = img->width * img->height;
|
|
||||||
unsigned char rowbuf[width];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < img->height / 2; i++) {
|
|
||||||
int offset = i * width;
|
|
||||||
int swap_offset = data_len - (width * (i + 1));
|
|
||||||
|
|
||||||
/* copy top row into buffer */
|
|
||||||
memcpy(rowbuf, img->data + offset, width);
|
|
||||||
|
|
||||||
/* copy lower row over upper row */
|
|
||||||
memcpy(img->data + offset, img->data + swap_offset, width);
|
|
||||||
|
|
||||||
/* copy buffer over lower row */
|
|
||||||
memcpy(img->data + swap_offset, rowbuf, width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hflip(struct fp_img *img)
|
|
||||||
{
|
|
||||||
int width = img->width;
|
|
||||||
unsigned char rowbuf[width];
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
for (i = 0; i < img->height; i++) {
|
|
||||||
int offset = i * width;
|
|
||||||
|
|
||||||
memcpy(rowbuf, img->data + offset, width);
|
|
||||||
for (j = 0; j < width; j++)
|
|
||||||
img->data[offset + j] = rowbuf[width - j - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void invert_colors(struct fp_img *img)
|
|
||||||
{
|
|
||||||
int data_len = img->width * img->height;
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < data_len; i++)
|
|
||||||
img->data[i] = 0xff - img->data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_img_standardize:
|
|
||||||
* @img: the image to standardize
|
|
||||||
*
|
|
||||||
* [Standardizes](libfprint-Image-operations.html#img_std) an image by normalizing its orientation, colors,
|
|
||||||
* etc. It is safe to call this multiple times on an image, libfprint keeps
|
|
||||||
* track of the work it needs to do to make an image standard and will not
|
|
||||||
* perform these operations more than once for a given image.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_img_standardize(struct fp_img *img)
|
|
||||||
{
|
|
||||||
if (img->flags & FP_IMG_V_FLIPPED) {
|
|
||||||
vflip(img);
|
|
||||||
img->flags &= ~FP_IMG_V_FLIPPED;
|
|
||||||
}
|
|
||||||
if (img->flags & FP_IMG_H_FLIPPED) {
|
|
||||||
hflip(img);
|
|
||||||
img->flags &= ~FP_IMG_H_FLIPPED;
|
|
||||||
}
|
|
||||||
if (img->flags & FP_IMG_COLORS_INVERTED) {
|
|
||||||
invert_colors(img);
|
|
||||||
img->flags &= ~FP_IMG_COLORS_INVERTED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Based on write_minutiae_XYTQ and bz_load */
|
|
||||||
static void minutiae_to_xyt(struct fp_minutiae *minutiae, int bwidth,
|
|
||||||
int bheight, unsigned char *buf)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
struct fp_minutia *minutia;
|
|
||||||
struct minutiae_struct c[MAX_FILE_MINUTIAE];
|
|
||||||
struct xyt_struct *xyt = (struct xyt_struct *) buf;
|
|
||||||
|
|
||||||
/* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */
|
|
||||||
int nmin = min(minutiae->num, MAX_BOZORTH_MINUTIAE);
|
|
||||||
|
|
||||||
for (i = 0; i < nmin; i++){
|
|
||||||
minutia = minutiae->list[i];
|
|
||||||
|
|
||||||
lfs2nist_minutia_XYT(&c[i].col[0], &c[i].col[1], &c[i].col[2],
|
|
||||||
minutia, bwidth, bheight);
|
|
||||||
c[i].col[3] = sround(minutia->reliability * 100.0);
|
|
||||||
|
|
||||||
if (c[i].col[2] > 180)
|
|
||||||
c[i].col[2] -= 360;
|
|
||||||
}
|
|
||||||
|
|
||||||
qsort((void *) &c, (size_t) nmin, sizeof(struct minutiae_struct),
|
|
||||||
sort_x_y);
|
|
||||||
|
|
||||||
for (i = 0; i < nmin; i++) {
|
|
||||||
xyt->xcol[i] = c[i].col[0];
|
|
||||||
xyt->ycol[i] = c[i].col[1];
|
|
||||||
xyt->thetacol[i] = c[i].col[2];
|
|
||||||
}
|
|
||||||
xyt->nrows = nmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FP_IMG_STANDARDIZATION_FLAGS (FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED \
|
|
||||||
| FP_IMG_COLORS_INVERTED)
|
|
||||||
|
|
||||||
static int fpi_img_detect_minutiae(struct fp_img *img)
|
|
||||||
{
|
|
||||||
struct fp_minutiae *minutiae;
|
|
||||||
int r;
|
|
||||||
int *direction_map, *low_contrast_map, *low_flow_map;
|
|
||||||
int *high_curve_map, *quality_map;
|
|
||||||
int map_w, map_h;
|
|
||||||
unsigned char *bdata;
|
|
||||||
int bw, bh, bd;
|
|
||||||
GTimer *timer;
|
|
||||||
|
|
||||||
if (img->flags & FP_IMG_STANDARDIZATION_FLAGS) {
|
|
||||||
fp_err("Cannot detect minutiae for non-standardized images");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 25.4 mm per inch */
|
|
||||||
timer = g_timer_new();
|
|
||||||
r = get_minutiae(&minutiae, &quality_map, &direction_map,
|
|
||||||
&low_contrast_map, &low_flow_map, &high_curve_map,
|
|
||||||
&map_w, &map_h, &bdata, &bw, &bh, &bd,
|
|
||||||
img->data, img->width, img->height, 8,
|
|
||||||
DEFAULT_PPI / (double)25.4, &g_lfsparms_V2);
|
|
||||||
g_timer_stop(timer);
|
|
||||||
fp_dbg("minutiae scan completed in %f secs", g_timer_elapsed(timer, NULL));
|
|
||||||
g_timer_destroy(timer);
|
|
||||||
if (r) {
|
|
||||||
fp_err("get minutiae failed, code %d", r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
fp_dbg("detected %d minutiae", minutiae->num);
|
|
||||||
img->minutiae = minutiae;
|
|
||||||
img->binarized = bdata;
|
|
||||||
|
|
||||||
free(quality_map);
|
|
||||||
free(direction_map);
|
|
||||||
free(low_contrast_map);
|
|
||||||
free(low_flow_map);
|
|
||||||
free(high_curve_map);
|
|
||||||
return minutiae->num;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
|
|
||||||
struct fp_print_data **ret)
|
|
||||||
{
|
|
||||||
struct fp_print_data *print;
|
|
||||||
struct fp_print_data_item *item;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!img->minutiae) {
|
|
||||||
r = fpi_img_detect_minutiae(img);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
if (!img->minutiae) {
|
|
||||||
fp_err("no minutiae after successful detection?");
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: space is wasted if we don't hit the max minutiae count. would
|
|
||||||
* be good to make this dynamic. */
|
|
||||||
print = fpi_print_data_new(FP_DEV(imgdev));
|
|
||||||
item = fpi_print_data_item_new(sizeof(struct xyt_struct));
|
|
||||||
print->type = PRINT_DATA_NBIS_MINUTIAE;
|
|
||||||
minutiae_to_xyt(img->minutiae, img->width, img->height, item->data);
|
|
||||||
print->prints = g_slist_prepend(print->prints, item);
|
|
||||||
|
|
||||||
/* FIXME: the print buffer at this point is endian-specific, and will
|
|
||||||
* only work when loaded onto machines with identical endianness. not good!
|
|
||||||
* data format should be platform-independent. */
|
|
||||||
*ret = print;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fpi_img_compare_print_data(struct fp_print_data *enrolled_print,
|
|
||||||
struct fp_print_data *new_print)
|
|
||||||
{
|
|
||||||
int score, max_score = 0, probe_len;
|
|
||||||
struct xyt_struct *pstruct = NULL;
|
|
||||||
struct xyt_struct *gstruct = NULL;
|
|
||||||
struct fp_print_data_item *data_item;
|
|
||||||
GSList *list_item;
|
|
||||||
|
|
||||||
if (enrolled_print->type != PRINT_DATA_NBIS_MINUTIAE ||
|
|
||||||
new_print->type != PRINT_DATA_NBIS_MINUTIAE) {
|
|
||||||
fp_err("invalid print format");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_slist_length(new_print->prints) != 1) {
|
|
||||||
fp_err("new_print contains more than one sample, is it enrolled print?");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
data_item = new_print->prints->data;
|
|
||||||
pstruct = (struct xyt_struct *)data_item->data;
|
|
||||||
|
|
||||||
probe_len = bozorth_probe_init(pstruct);
|
|
||||||
list_item = enrolled_print->prints;
|
|
||||||
do {
|
|
||||||
data_item = list_item->data;
|
|
||||||
gstruct = (struct xyt_struct *)data_item->data;
|
|
||||||
score = bozorth_to_gallery(probe_len, pstruct, gstruct);
|
|
||||||
fp_dbg("score %d", score);
|
|
||||||
max_score = max(score, max_score);
|
|
||||||
list_item = g_slist_next(list_item);
|
|
||||||
} while (list_item);
|
|
||||||
|
|
||||||
return max_score;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print,
|
|
||||||
struct fp_print_data **gallery, int match_threshold, size_t *match_offset)
|
|
||||||
{
|
|
||||||
struct xyt_struct *pstruct;
|
|
||||||
struct xyt_struct *gstruct;
|
|
||||||
struct fp_print_data *gallery_print;
|
|
||||||
struct fp_print_data_item *data_item;
|
|
||||||
int probe_len;
|
|
||||||
size_t i = 0;
|
|
||||||
int r;
|
|
||||||
GSList *list_item;
|
|
||||||
|
|
||||||
if (g_slist_length(print->prints) != 1) {
|
|
||||||
fp_err("new_print contains more than one sample, is it enrolled print?");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
data_item = print->prints->data;
|
|
||||||
pstruct = (struct xyt_struct *)data_item->data;
|
|
||||||
|
|
||||||
probe_len = bozorth_probe_init(pstruct);
|
|
||||||
while ((gallery_print = gallery[i++])) {
|
|
||||||
list_item = gallery_print->prints;
|
|
||||||
do {
|
|
||||||
data_item = list_item->data;
|
|
||||||
gstruct = (struct xyt_struct *)data_item->data;
|
|
||||||
r = bozorth_to_gallery(probe_len, pstruct, gstruct);
|
|
||||||
if (r >= match_threshold) {
|
|
||||||
*match_offset = i - 1;
|
|
||||||
return FP_VERIFY_MATCH;
|
|
||||||
}
|
|
||||||
list_item = g_slist_next(list_item);
|
|
||||||
} while (list_item);
|
|
||||||
}
|
|
||||||
return FP_VERIFY_NO_MATCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_img_binarize:
|
|
||||||
* @img: a standardized image
|
|
||||||
*
|
|
||||||
* Get a binarized form of a standardized scanned image. This is where the
|
|
||||||
* fingerprint image has been "enhanced" and is a set of pure black ridges
|
|
||||||
* on a pure white background. Internally, image processing happens on top
|
|
||||||
* of the binarized image.
|
|
||||||
*
|
|
||||||
* The image must have been [standardized](libfprint-Image-operations.html#img_std)
|
|
||||||
* otherwise this function will fail.
|
|
||||||
*
|
|
||||||
* It is safe to binarize an image and free the original while continuing
|
|
||||||
* to use the binarized version.
|
|
||||||
*
|
|
||||||
* You cannot binarize an image twice.
|
|
||||||
*
|
|
||||||
* Returns: a new image representing the binarized form of the original, or
|
|
||||||
* %NULL on error. Must be freed with fp_img_free() after use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_img *fp_img_binarize(struct fp_img *img)
|
|
||||||
{
|
|
||||||
struct fp_img *ret;
|
|
||||||
int height = img->height;
|
|
||||||
int width = img->width;
|
|
||||||
int imgsize = height * width;
|
|
||||||
|
|
||||||
if (img->flags & FP_IMG_BINARIZED_FORM) {
|
|
||||||
fp_err("image already binarized");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!img->binarized) {
|
|
||||||
int r = fpi_img_detect_minutiae(img);
|
|
||||||
if (r < 0)
|
|
||||||
return NULL;
|
|
||||||
if (!img->binarized) {
|
|
||||||
fp_err("no minutiae after successful detection?");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = fpi_img_new(imgsize);
|
|
||||||
ret->flags |= FP_IMG_BINARIZED_FORM;
|
|
||||||
ret->width = width;
|
|
||||||
ret->height = height;
|
|
||||||
memcpy(ret->data, img->binarized, imgsize);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_img_get_minutiae:
|
|
||||||
* @img: a standardized image
|
|
||||||
* @nr_minutiae: an output location to store minutiae list length
|
|
||||||
*
|
|
||||||
* Get a list of minutiae detected in an image. A minutia point is a feature
|
|
||||||
* detected on a fingerprint, typically where ridges end or split.
|
|
||||||
* libfprint's image processing code relies upon comparing sets of minutiae,
|
|
||||||
* so accurate placement of minutia points is critical for good imaging
|
|
||||||
* performance.
|
|
||||||
*
|
|
||||||
* The image must have been [standardized](libfprint-Image-operations.html#img_std)
|
|
||||||
* otherwise this function will fail.
|
|
||||||
*
|
|
||||||
* You cannot pass a binarized image to this function. Instead, pass the
|
|
||||||
* original image.
|
|
||||||
*
|
|
||||||
* Returns a list of pointers to minutiae, where the list is of length
|
|
||||||
* indicated in the nr_minutiae output parameter. The returned list is only
|
|
||||||
* valid while the parent image has not been freed, and the minutiae data
|
|
||||||
* must not be modified or freed.
|
|
||||||
*
|
|
||||||
* Returns: a list of minutiae points. Must not be modified or freed.
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_minutia **fp_img_get_minutiae(struct fp_img *img,
|
|
||||||
int *nr_minutiae)
|
|
||||||
{
|
|
||||||
if (img->flags & FP_IMG_BINARIZED_FORM) {
|
|
||||||
fp_err("image is binarized");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!img->minutiae) {
|
|
||||||
int r = fpi_img_detect_minutiae(img);
|
|
||||||
if (r < 0)
|
|
||||||
return NULL;
|
|
||||||
if (!img->minutiae) {
|
|
||||||
fp_err("no minutiae after successful detection?");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*nr_minutiae = img->minutiae->num;
|
|
||||||
return img->minutiae->list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_minutia_get_coords:
|
|
||||||
* @minutia: a struct #fp_minutia
|
|
||||||
* @coord_x: the return variable for the X coordinate of the minutia
|
|
||||||
* @coord_y: the return variable for the Y coordinate of the minutia
|
|
||||||
*
|
|
||||||
* Sets @coord_x and @coord_y to be the coordinates of the detected minutia, so it
|
|
||||||
* can be presented in a more verbose user interface. This is usually only
|
|
||||||
* used for debugging purposes.
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, -1 on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_minutia_get_coords(struct fp_minutia *minutia, int *coord_x, int *coord_y)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (minutia != NULL, -1);
|
|
||||||
g_return_val_if_fail (coord_x != NULL, -1);
|
|
||||||
g_return_val_if_fail (coord_y != NULL, -1);
|
|
||||||
|
|
||||||
*coord_x = minutia->x;
|
|
||||||
*coord_y = minutia->y;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_std_sq_dev:
|
|
||||||
* @buf: buffer (usually bitmap, one byte per pixel)
|
|
||||||
* @size: size of @buffer
|
|
||||||
*
|
|
||||||
* Calculates the squared standard deviation of the individual
|
|
||||||
* pixels in the buffer, as per the following formula:
|
|
||||||
* |[<!-- -->
|
|
||||||
* mean = sum (buf[0..size]) / size
|
|
||||||
* sq_dev = sum ((buf[0.size] - mean) ^ 2)
|
|
||||||
* ]|
|
|
||||||
* This function is usually used to determine whether image
|
|
||||||
* is empty.
|
|
||||||
*
|
|
||||||
* Returns: the squared standard deviation for @buffer
|
|
||||||
*/
|
|
||||||
int fpi_std_sq_dev(const unsigned char *buf, int size)
|
|
||||||
{
|
|
||||||
int res = 0, mean = 0, i;
|
|
||||||
|
|
||||||
if (size > (INT_MAX / 65536)) {
|
|
||||||
fp_err("%s: we might get an overflow!", __func__);
|
|
||||||
return -EOVERFLOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
mean += buf[i];
|
|
||||||
|
|
||||||
mean /= size;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
int dev = (int)buf[i] - mean;
|
|
||||||
res += dev*dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res / size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_mean_sq_diff_norm:
|
|
||||||
* @buf1: buffer (usually bitmap, one byte per pixel)
|
|
||||||
* @buf2: buffer (usually bitmap, one byte per pixel)
|
|
||||||
* @size: buffer size of smallest buffer
|
|
||||||
*
|
|
||||||
* This function calculates the normalized mean square difference of
|
|
||||||
* two buffers, usually two lines, as per the following formula:
|
|
||||||
* |[<!-- -->
|
|
||||||
* sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
|
|
||||||
* ]|
|
|
||||||
*
|
|
||||||
* This functions is usually used to get numerical difference
|
|
||||||
* between two images.
|
|
||||||
*
|
|
||||||
* Returns: the normalized mean squared difference between @buf1 and @buf2
|
|
||||||
*/
|
|
||||||
int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size)
|
|
||||||
{
|
|
||||||
int res = 0, i;
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
int dev = (int)buf1[i] - (int)buf2[i];
|
|
||||||
res += dev * dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res / size;
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __FPI_IMG_H__
|
|
||||||
#define __FPI_IMG_H__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
struct fp_minutiae;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FpiImgFlags:
|
|
||||||
* @FP_IMG_V_FLIPPED: the image is vertically flipped
|
|
||||||
* @FP_IMG_H_FLIPPED: the image is horizontally flipped
|
|
||||||
* @FP_IMG_COLORS_INVERTED: the colours are inverted
|
|
||||||
* @FP_IMG_BINARIZED_FORM: binarised image, see fp_img_binarize()
|
|
||||||
* @FP_IMG_PARTIAL: the image is partial, useful for driver to keep track
|
|
||||||
* of incomplete captures
|
|
||||||
*
|
|
||||||
* Flags used in the #fp_img structure to describe the image contained
|
|
||||||
* into the structure. Note that a number of functions will refuse to
|
|
||||||
* handle images which haven't been standardised through fp_img_standardize()
|
|
||||||
* (meaning the @FP_IMG_V_FLIPPED, @FP_IMG_H_FLIPPED and @FP_IMG_COLORS_INVERTED
|
|
||||||
* should all be unset when the image needs to be analysed).
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
FP_IMG_V_FLIPPED = 1 << 0,
|
|
||||||
FP_IMG_H_FLIPPED = 1 << 1,
|
|
||||||
FP_IMG_COLORS_INVERTED = 1 << 2,
|
|
||||||
FP_IMG_BINARIZED_FORM = 1 << 3,
|
|
||||||
FP_IMG_PARTIAL = 1 << 4
|
|
||||||
} FpiImgFlags;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_img:
|
|
||||||
* @width: the width of the image
|
|
||||||
* @height: the height of the image
|
|
||||||
* @length: the length of the data associated with the image
|
|
||||||
* @flags: @FpiImgFlags flags describing the image contained in the structure
|
|
||||||
* @minutiae: an opaque structure representing the detected minutiae
|
|
||||||
* @binarized: the binarized image data
|
|
||||||
* @data: the start of the image data, which will be of @length size.
|
|
||||||
*
|
|
||||||
* A structure representing a captured, or processed image. The @flags member
|
|
||||||
* will show its current state, including whether whether the binarized form
|
|
||||||
* if present, whether it is complete, and whether it needs particular changes
|
|
||||||
* before being processed.
|
|
||||||
*/
|
|
||||||
struct fp_img {
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
size_t length;
|
|
||||||
FpiImgFlags flags;
|
|
||||||
/*< private >*/
|
|
||||||
struct fp_minutiae *minutiae;
|
|
||||||
/*< public >*/
|
|
||||||
unsigned char *binarized;
|
|
||||||
unsigned char data[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fp_img *fpi_img_new(size_t length);
|
|
||||||
struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev);
|
|
||||||
struct fp_img *fpi_img_realloc(struct fp_img *img, size_t newsize);
|
|
||||||
struct fp_img *fpi_img_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor);
|
|
||||||
|
|
||||||
int fpi_std_sq_dev(const unsigned char *buf, int size);
|
|
||||||
int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,485 +0,0 @@
|
||||||
/*
|
|
||||||
* Polling/timing management
|
|
||||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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 "poll"
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
#include "fpi-poll.h"
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:events
|
|
||||||
* @title: Initialisation and events handling
|
|
||||||
* @short_description: Initialisation and events handling functions
|
|
||||||
*
|
|
||||||
* These functions are only applicable to users of libfprint's asynchronous
|
|
||||||
* API.
|
|
||||||
*
|
|
||||||
* libfprint does not create internal library threads and hence can only
|
|
||||||
* execute when your application is calling a libfprint function. However,
|
|
||||||
* libfprint often has work to be do, such as handling of completed USB
|
|
||||||
* transfers, and processing of timeouts required in order for the library
|
|
||||||
* to function. Therefore it is essential that your own application must
|
|
||||||
* regularly "phone into" libfprint so that libfprint can handle any pending
|
|
||||||
* events.
|
|
||||||
*
|
|
||||||
* The function you must call is fp_handle_events() or a variant of it. This
|
|
||||||
* function will handle any pending events, and it is from this context that
|
|
||||||
* all asynchronous event callbacks from the library will occur. You can view
|
|
||||||
* this function as a kind of iteration function.
|
|
||||||
*
|
|
||||||
* If there are no events pending, fp_handle_events() will block for a few
|
|
||||||
* seconds (and will handle any new events should anything occur in that time).
|
|
||||||
* If you wish to customise this timeout, you can use
|
|
||||||
* fp_handle_events_timeout() instead. If you wish to do a non-blocking
|
|
||||||
* iteration, call fp_handle_events_timeout() with a zero timeout.
|
|
||||||
*
|
|
||||||
* How to integrate events handling depends on your main loop implementation.
|
|
||||||
* The sister fprintd project includes an implementation of main loop handling
|
|
||||||
* that integrates into GLib's main loop. The
|
|
||||||
* [libusb documentation](http://libusb.sourceforge.net/api-1.0/group__poll.html#details)
|
|
||||||
* also includes more details about how to integrate libfprint events into
|
|
||||||
* your main loop.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:fpi-poll
|
|
||||||
* @title: Timeouts
|
|
||||||
* @short_description: Timeout handling helpers
|
|
||||||
*
|
|
||||||
* Helper functions to schedule a function call to be made after a timeout. This
|
|
||||||
* is useful to avoid making blocking calls while waiting for hardware to answer
|
|
||||||
* for example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* this is a singly-linked list of pending timers, sorted with the timer that
|
|
||||||
* is expiring soonest at the head. */
|
|
||||||
static GSList *active_timers = NULL;
|
|
||||||
|
|
||||||
/* notifiers for added or removed poll fds */
|
|
||||||
static fp_pollfd_added_cb fd_added_cb = NULL;
|
|
||||||
static fp_pollfd_removed_cb fd_removed_cb = NULL;
|
|
||||||
|
|
||||||
struct fpi_timeout {
|
|
||||||
struct timeval expiry;
|
|
||||||
fpi_timeout_fn callback;
|
|
||||||
struct fp_dev *dev;
|
|
||||||
void *data;
|
|
||||||
char *name;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int timeout_sort_fn(gconstpointer _a, gconstpointer _b)
|
|
||||||
{
|
|
||||||
fpi_timeout *a = (fpi_timeout *) _a;
|
|
||||||
fpi_timeout *b = (fpi_timeout *) _b;
|
|
||||||
struct timeval *tv_a = &a->expiry;
|
|
||||||
struct timeval *tv_b = &b->expiry;
|
|
||||||
|
|
||||||
if (timercmp(tv_a, tv_b, <))
|
|
||||||
return -1;
|
|
||||||
else if (timercmp(tv_a, tv_b, >))
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_timeout_free(fpi_timeout *timeout)
|
|
||||||
{
|
|
||||||
if (timeout == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
g_free(timeout->name);
|
|
||||||
g_free(timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_timeout_set_name:
|
|
||||||
* @timeout: a #fpi_timeout
|
|
||||||
* @name: the name to give the timeout
|
|
||||||
*
|
|
||||||
* Sets a name for a timeout, allowing that name to be printed
|
|
||||||
* along with any timeout related debug.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_timeout_set_name(fpi_timeout *timeout,
|
|
||||||
const char *name)
|
|
||||||
{
|
|
||||||
g_return_if_fail (timeout != NULL);
|
|
||||||
g_return_if_fail (name != NULL);
|
|
||||||
g_return_if_fail (timeout->name == NULL);
|
|
||||||
|
|
||||||
timeout->name = g_strdup(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_timeout_add:
|
|
||||||
* @msec: the time before calling the function, in milliseconds (1/1000ths of a second)
|
|
||||||
* @callback: function to callback
|
|
||||||
* @dev: a struct #fp_dev
|
|
||||||
* @data: data to pass to @callback, or %NULL
|
|
||||||
*
|
|
||||||
* A timeout is the asynchronous equivalent of sleeping. You create a timeout
|
|
||||||
* saying that you'd like to have a function invoked at a certain time in
|
|
||||||
* the future.
|
|
||||||
*
|
|
||||||
* Note that you should hold onto the return value of this function to cancel it
|
|
||||||
* use fpi_timeout_cancel(), otherwise the callback could be called while the driver
|
|
||||||
* is being torn down.
|
|
||||||
*
|
|
||||||
* This function can be considered to never fail.
|
|
||||||
*
|
|
||||||
* Returns: an #fpi_timeout structure
|
|
||||||
*/
|
|
||||||
fpi_timeout *fpi_timeout_add(unsigned int msec,
|
|
||||||
fpi_timeout_fn callback,
|
|
||||||
struct fp_dev *dev,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
struct timespec ts;
|
|
||||||
struct timeval add_msec;
|
|
||||||
fpi_timeout *timeout;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail (dev != NULL, NULL);
|
|
||||||
|
|
||||||
fp_dbg("in %dms", msec);
|
|
||||||
|
|
||||||
r = clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("failed to read monotonic clock, errno=%d", errno);
|
|
||||||
BUG();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeout = g_new0(fpi_timeout, 1);
|
|
||||||
timeout->callback = callback;
|
|
||||||
timeout->dev = dev;
|
|
||||||
timeout->data = data;
|
|
||||||
TIMESPEC_TO_TIMEVAL(&timeout->expiry, &ts);
|
|
||||||
|
|
||||||
/* calculate timeout expiry by adding delay to current monotonic clock */
|
|
||||||
timerclear(&add_msec);
|
|
||||||
add_msec.tv_sec = msec / 1000;
|
|
||||||
add_msec.tv_usec = (msec % 1000) * 1000;
|
|
||||||
timeradd(&timeout->expiry, &add_msec, &timeout->expiry);
|
|
||||||
|
|
||||||
active_timers = g_slist_insert_sorted(active_timers, timeout,
|
|
||||||
timeout_sort_fn);
|
|
||||||
|
|
||||||
return timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_timeout_cancel:
|
|
||||||
* @timeout: an #fpi_timeout structure
|
|
||||||
*
|
|
||||||
* Cancels a timeout scheduled with fpi_timeout_add(), and frees the
|
|
||||||
* @timeout structure.
|
|
||||||
*/
|
|
||||||
void fpi_timeout_cancel(fpi_timeout *timeout)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
active_timers = g_slist_remove(active_timers, timeout);
|
|
||||||
fpi_timeout_free(timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get the expiry time and optionally the timeout structure for the next
|
|
||||||
* timeout. returns 0 if there are no expired timers, or 1 if the
|
|
||||||
* timeval/timeout output parameters were populated. if the returned timeval
|
|
||||||
* is zero then it means the timeout has already expired and should be handled
|
|
||||||
* ASAP. */
|
|
||||||
static int get_next_timeout_expiry(struct timeval *out,
|
|
||||||
struct fpi_timeout **out_timeout)
|
|
||||||
{
|
|
||||||
struct timespec ts;
|
|
||||||
struct timeval tv;
|
|
||||||
struct fpi_timeout *next_timeout;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (active_timers == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
r = clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("failed to read monotonic clock, errno=%d", errno);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
TIMESPEC_TO_TIMEVAL(&tv, &ts);
|
|
||||||
|
|
||||||
next_timeout = active_timers->data;
|
|
||||||
if (out_timeout)
|
|
||||||
*out_timeout = next_timeout;
|
|
||||||
|
|
||||||
if (timercmp(&tv, &next_timeout->expiry, >=)) {
|
|
||||||
if (next_timeout->name)
|
|
||||||
fp_dbg("first timeout '%s' already expired", next_timeout->name);
|
|
||||||
else
|
|
||||||
fp_dbg("first timeout already expired");
|
|
||||||
timerclear(out);
|
|
||||||
} else {
|
|
||||||
timersub(&next_timeout->expiry, &tv, out);
|
|
||||||
if (next_timeout->name)
|
|
||||||
fp_dbg("next timeout '%s' in %ld.%06lds", next_timeout->name,
|
|
||||||
out->tv_sec, out->tv_usec);
|
|
||||||
else
|
|
||||||
fp_dbg("next timeout in %ld.%06lds", out->tv_sec, out->tv_usec);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* handle a timeout that has expired */
|
|
||||||
static void handle_timeout(struct fpi_timeout *timeout)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
timeout->callback(timeout->dev, timeout->data);
|
|
||||||
active_timers = g_slist_remove(active_timers, timeout);
|
|
||||||
fpi_timeout_free(timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int handle_timeouts(void)
|
|
||||||
{
|
|
||||||
struct timeval next_timeout_expiry;
|
|
||||||
struct fpi_timeout *next_timeout;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = get_next_timeout_expiry(&next_timeout_expiry, &next_timeout);
|
|
||||||
if (r <= 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (!timerisset(&next_timeout_expiry))
|
|
||||||
handle_timeout(next_timeout);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_handle_events_timeout:
|
|
||||||
* @timeout: Maximum timeout for this blocking function
|
|
||||||
*
|
|
||||||
* Handle any pending events. If a non-zero timeout is specified, the function
|
|
||||||
* will potentially block for the specified amount of time, although it may
|
|
||||||
* return sooner if events have been handled. The function acts as non-blocking
|
|
||||||
* for a zero timeout.
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_handle_events_timeout(struct timeval *timeout)
|
|
||||||
{
|
|
||||||
struct timeval next_timeout_expiry;
|
|
||||||
struct timeval select_timeout;
|
|
||||||
struct fpi_timeout *next_timeout;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = get_next_timeout_expiry(&next_timeout_expiry, &next_timeout);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (r) {
|
|
||||||
/* timer already expired? */
|
|
||||||
if (!timerisset(&next_timeout_expiry)) {
|
|
||||||
handle_timeout(next_timeout);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* choose the smallest of next URB timeout or user specified timeout */
|
|
||||||
if (timercmp(&next_timeout_expiry, timeout, <))
|
|
||||||
select_timeout = next_timeout_expiry;
|
|
||||||
else
|
|
||||||
select_timeout = *timeout;
|
|
||||||
} else {
|
|
||||||
select_timeout = *timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = libusb_handle_events_timeout(fpi_usb_ctx, &select_timeout);
|
|
||||||
*timeout = select_timeout;
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
return handle_timeouts();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_handle_events:
|
|
||||||
*
|
|
||||||
* Convenience function for calling fp_handle_events_timeout() with a sensible
|
|
||||||
* default timeout value of two seconds (subject to change if we decide another
|
|
||||||
* value is more sensible).
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_handle_events(void)
|
|
||||||
{
|
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = 2;
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
return fp_handle_events_timeout(&tv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_get_next_timeout:
|
|
||||||
* @tv: a #timeval structure containing the duration to the next timeout.
|
|
||||||
*
|
|
||||||
* A zero filled @tv timeout means events are to be handled immediately
|
|
||||||
*
|
|
||||||
* Returns: returns 0 if no timeouts active, or 1 if timeout returned.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_get_next_timeout(struct timeval *tv)
|
|
||||||
{
|
|
||||||
struct timeval fprint_timeout = { 0, 0 };
|
|
||||||
struct timeval libusb_timeout = { 0, 0 };
|
|
||||||
int r_fprint;
|
|
||||||
int r_libusb;
|
|
||||||
|
|
||||||
r_fprint = get_next_timeout_expiry(&fprint_timeout, NULL);
|
|
||||||
r_libusb = libusb_get_next_timeout(fpi_usb_ctx, &libusb_timeout);
|
|
||||||
|
|
||||||
/* if we have no pending timeouts and the same is true for libusb,
|
|
||||||
* indicate that we have no pending timouts */
|
|
||||||
if (r_fprint <= 0 && r_libusb <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* if fprint have no pending timeouts return libusb timeout */
|
|
||||||
else if (r_fprint == 0)
|
|
||||||
*tv = libusb_timeout;
|
|
||||||
|
|
||||||
/* if libusb have no pending timeouts return fprint timeout */
|
|
||||||
else if (r_libusb == 0)
|
|
||||||
*tv = fprint_timeout;
|
|
||||||
|
|
||||||
/* otherwise return the smaller of the 2 timeouts */
|
|
||||||
else if (timercmp(&fprint_timeout, &libusb_timeout, <))
|
|
||||||
*tv = fprint_timeout;
|
|
||||||
else
|
|
||||||
*tv = libusb_timeout;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_get_pollfds:
|
|
||||||
* @pollfds: output location for a list of pollfds. If non-%NULL, must be
|
|
||||||
* released with free() when done.
|
|
||||||
*
|
|
||||||
* Retrieve a list of file descriptors that should be polled for events
|
|
||||||
* interesting to libfprint. This function is only for users who wish to
|
|
||||||
* combine libfprint's file descriptor set with other event sources – more
|
|
||||||
* simplistic users will be able to call fp_handle_events() or a variant
|
|
||||||
* directly.
|
|
||||||
*
|
|
||||||
* Returns: the number of pollfds in the resultant list, or negative on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED ssize_t fp_get_pollfds(struct fp_pollfd **pollfds)
|
|
||||||
{
|
|
||||||
const struct libusb_pollfd **usbfds;
|
|
||||||
const struct libusb_pollfd *usbfd;
|
|
||||||
struct fp_pollfd *ret;
|
|
||||||
ssize_t cnt = 0;
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
g_return_val_if_fail (fpi_usb_ctx != NULL, -EIO);
|
|
||||||
|
|
||||||
usbfds = libusb_get_pollfds(fpi_usb_ctx);
|
|
||||||
if (!usbfds) {
|
|
||||||
*pollfds = NULL;
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((usbfd = usbfds[i++]) != NULL)
|
|
||||||
cnt++;
|
|
||||||
|
|
||||||
ret = g_malloc(sizeof(struct fp_pollfd) * cnt);
|
|
||||||
i = 0;
|
|
||||||
while ((usbfd = usbfds[i]) != NULL) {
|
|
||||||
ret[i].fd = usbfd->fd;
|
|
||||||
ret[i].events = usbfd->events;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
*pollfds = ret;
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_set_pollfd_notifiers:
|
|
||||||
* @added_cb: a #fp_pollfd_added_cb callback or %NULL
|
|
||||||
* @removed_cb: a #fp_pollfd_removed_cb callback or %NULL
|
|
||||||
*
|
|
||||||
* This sets the callback functions to call for every new or removed
|
|
||||||
* file descriptor used as an event source.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb,
|
|
||||||
fp_pollfd_removed_cb removed_cb)
|
|
||||||
{
|
|
||||||
fd_added_cb = added_cb;
|
|
||||||
fd_removed_cb = removed_cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_pollfd(int fd, short events, void *user_data)
|
|
||||||
{
|
|
||||||
if (fd_added_cb)
|
|
||||||
fd_added_cb(fd, events);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void remove_pollfd(int fd, void *user_data)
|
|
||||||
{
|
|
||||||
if (fd_removed_cb)
|
|
||||||
fd_removed_cb(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fpi_poll_init(void)
|
|
||||||
{
|
|
||||||
libusb_set_pollfd_notifiers(fpi_usb_ctx, add_pollfd, remove_pollfd, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fpi_poll_exit(void)
|
|
||||||
{
|
|
||||||
g_slist_free_full(active_timers, (GDestroyNotify) fpi_timeout_free);
|
|
||||||
active_timers = NULL;
|
|
||||||
fd_added_cb = NULL;
|
|
||||||
fd_removed_cb = NULL;
|
|
||||||
libusb_set_pollfd_notifiers(fpi_usb_ctx, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpi_timeout_cancel_all_for_dev(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
GSList *l;
|
|
||||||
|
|
||||||
g_return_if_fail (dev != NULL);
|
|
||||||
|
|
||||||
l = active_timers;
|
|
||||||
while (l) {
|
|
||||||
struct fpi_timeout *timeout = l->data;
|
|
||||||
GSList *current = l;
|
|
||||||
|
|
||||||
l = l->next;
|
|
||||||
if (timeout->dev == dev) {
|
|
||||||
g_free (timeout);
|
|
||||||
active_timers = g_slist_delete_link (active_timers, current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __FPI_POLL_H__
|
|
||||||
#define __FPI_POLL_H__
|
|
||||||
|
|
||||||
#include "fprint.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_timeout_fn:
|
|
||||||
* @dev: the struct #fp_dev passed to fpi_timeout_add()
|
|
||||||
* @data: the data passed to fpi_timeout_add()
|
|
||||||
*
|
|
||||||
* The prototype of the callback function for fpi_timeout_add().
|
|
||||||
* Note that after the callback is called, the #fpi_timeout structure will
|
|
||||||
* be freed.
|
|
||||||
*/
|
|
||||||
typedef void (*fpi_timeout_fn)(struct fp_dev *dev, void *data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_timeout:
|
|
||||||
*
|
|
||||||
* An opaque structure representing a scheduled function call, created with
|
|
||||||
* fpi_timeout_add().
|
|
||||||
*/
|
|
||||||
typedef struct fpi_timeout fpi_timeout;
|
|
||||||
fpi_timeout *fpi_timeout_add(unsigned int msec,
|
|
||||||
fpi_timeout_fn callback,
|
|
||||||
struct fp_dev *dev,
|
|
||||||
void *data);
|
|
||||||
void fpi_timeout_set_name(fpi_timeout *timeout,
|
|
||||||
const char *name);
|
|
||||||
void fpi_timeout_cancel(fpi_timeout *timeout);
|
|
||||||
|
|
||||||
#endif
|
|
50
libfprint/fpi-print.h
Normal file
50
libfprint/fpi-print.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "fpi-enums.h"
|
||||||
|
#include "fp-device.h"
|
||||||
|
#include "fp-print.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpPrintType:
|
||||||
|
* @FP_PRINT_UNDEFINED: Undefined type, this happens prior to enrollment
|
||||||
|
* @FP_PRINT_RAW: A raw print where the data is directly compared
|
||||||
|
* @FP_PRINT_NBIS: NBIS minutiae comparison
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FP_PRINT_UNDEFINED = 0,
|
||||||
|
FP_PRINT_RAW,
|
||||||
|
FP_PRINT_NBIS,
|
||||||
|
} FpPrintType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpiMatchResult:
|
||||||
|
* @FPI_MATCH_ERROR: An error occured during matching
|
||||||
|
* @FPI_MATCH_SUCCESS: The prints matched
|
||||||
|
* @FPI_MATCH_FAIL: The prints did not match
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FPI_MATCH_ERROR = 0,
|
||||||
|
FPI_MATCH_SUCCESS,
|
||||||
|
FPI_MATCH_FAIL,
|
||||||
|
} FpiMatchResult;
|
||||||
|
|
||||||
|
void fpi_print_add_print (FpPrint *print,
|
||||||
|
FpPrint *add);
|
||||||
|
|
||||||
|
void fpi_print_set_type (FpPrint *print,
|
||||||
|
FpPrintType type);
|
||||||
|
void fpi_print_set_device_stored (FpPrint *print,
|
||||||
|
gboolean device_stored);
|
||||||
|
|
||||||
|
gboolean fpi_print_add_from_image (FpPrint *print,
|
||||||
|
FpImage *image,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
FpiMatchResult fpi_print_bz3_match (FpPrint * template,
|
||||||
|
FpPrint *print,
|
||||||
|
gint bz3_threshold,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
G_END_DECLS
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Functions to assist with asynchronous driver <---> library communications
|
* Functions to assist with asynchronous driver <---> library communications
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -17,13 +18,11 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FP_COMPONENT "drv"
|
#define FP_COMPONENT "SSM"
|
||||||
|
|
||||||
#include "fp_internal.h"
|
#include "drivers_api.h"
|
||||||
#include "fpi-ssm.h"
|
#include "fpi-ssm.h"
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION:fpi-ssm
|
* SECTION:fpi-ssm
|
||||||
|
@ -32,7 +31,7 @@
|
||||||
*
|
*
|
||||||
* Asynchronous driver design encourages some kind of state machine behind it.
|
* Asynchronous driver design encourages some kind of state machine behind it.
|
||||||
* In most cases, the state machine is entirely linear - you only go to the
|
* In most cases, the state machine is entirely linear - you only go to the
|
||||||
* next state, you never jump or go backwards. The #fpi_ssm functions help you
|
* next state, you never jump or go backwards. The #FpiSsm functions help you
|
||||||
* implement such a machine.
|
* implement such a machine.
|
||||||
*
|
*
|
||||||
* e.g. `S1` ↦ `S2` ↦ `S3` ↦ `S4`
|
* e.g. `S1` ↦ `S2` ↦ `S3` ↦ `S4`
|
||||||
|
@ -72,20 +71,21 @@
|
||||||
* upon success (or fails).
|
* upon success (or fails).
|
||||||
*
|
*
|
||||||
* Your completion callback should examine the return value of
|
* Your completion callback should examine the return value of
|
||||||
* fpi_ssm_get_error() in order to determine whether the #fpi_ssm completed or
|
* fpi_ssm_get_error() in ordater to determine whether the #FpiSsm completed or
|
||||||
* failed. An error code of zero indicates successful completion.
|
* failed. An error code of zero indicates successful completion.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct fpi_ssm {
|
struct _FpiSsm
|
||||||
struct fp_dev *dev;
|
{
|
||||||
fpi_ssm *parentsm;
|
FpDevice *dev;
|
||||||
|
FpiSsm *parentsm;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
int nr_states;
|
int nr_states;
|
||||||
int cur_state;
|
int cur_state;
|
||||||
gboolean completed;
|
gboolean completed;
|
||||||
int error;
|
GError *error;
|
||||||
ssm_completed_fn callback;
|
FpiSsmCompletedCallback callback;
|
||||||
ssm_handler_fn handler;
|
FpiSsmHandlerCallback handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,17 +98,19 @@ struct fpi_ssm {
|
||||||
* Allocate a new ssm, with @nr_states states. The @handler callback
|
* Allocate a new ssm, with @nr_states states. The @handler callback
|
||||||
* will be called after each state transition.
|
* will be called after each state transition.
|
||||||
*
|
*
|
||||||
* Returns: a new #fpi_ssm state machine
|
* Returns: a new #FpiSsm state machine
|
||||||
*/
|
*/
|
||||||
fpi_ssm *fpi_ssm_new(struct fp_dev *dev,
|
FpiSsm *
|
||||||
ssm_handler_fn handler,
|
fpi_ssm_new (FpDevice *dev,
|
||||||
|
FpiSsmHandlerCallback handler,
|
||||||
int nr_states,
|
int nr_states,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
fpi_ssm *machine;
|
FpiSsm *machine;
|
||||||
BUG_ON(nr_states < 1);
|
|
||||||
|
|
||||||
machine = g_malloc0(sizeof(*machine));
|
BUG_ON (nr_states < 1);
|
||||||
|
|
||||||
|
machine = g_malloc0 (sizeof (*machine));
|
||||||
machine->handler = handler;
|
machine->handler = handler;
|
||||||
machine->nr_states = nr_states;
|
machine->nr_states = nr_states;
|
||||||
machine->dev = dev;
|
machine->dev = dev;
|
||||||
|
@ -119,7 +121,7 @@ fpi_ssm *fpi_ssm_new(struct fp_dev *dev,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_ssm_get_user_data:
|
* fpi_ssm_get_user_data:
|
||||||
* @machine: an #fpi_ssm state machine
|
* @machine: an #FpiSsm state machine
|
||||||
*
|
*
|
||||||
* Retrieve the pointer to user data set when fpi_ssm_new()
|
* Retrieve the pointer to user data set when fpi_ssm_new()
|
||||||
* is called.
|
* is called.
|
||||||
|
@ -127,66 +129,73 @@ fpi_ssm *fpi_ssm_new(struct fp_dev *dev,
|
||||||
* Returns: a pointer
|
* Returns: a pointer
|
||||||
*/
|
*/
|
||||||
void *
|
void *
|
||||||
fpi_ssm_get_user_data(fpi_ssm *machine)
|
fpi_ssm_get_user_data (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
return machine->user_data;
|
return machine->user_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_ssm_free:
|
* fpi_ssm_free:
|
||||||
* @machine: an #fpi_ssm state machine
|
* @machine: an #FpiSsm state machine
|
||||||
*
|
*
|
||||||
* Frees a state machine. This does not call any error or success
|
* Frees a state machine. This does not call any error or success
|
||||||
* callbacks, so you need to do this yourself.
|
* callbacks, so you need to do this yourself.
|
||||||
*/
|
*/
|
||||||
void fpi_ssm_free(fpi_ssm *machine)
|
void
|
||||||
|
fpi_ssm_free (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
if (!machine)
|
if (!machine)
|
||||||
return;
|
return;
|
||||||
g_free(machine);
|
|
||||||
|
g_clear_pointer (&machine->error, g_error_free);
|
||||||
|
g_free (machine);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invoke the state handler */
|
/* Invoke the state handler */
|
||||||
static void __ssm_call_handler(fpi_ssm *machine)
|
static void
|
||||||
|
__ssm_call_handler (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
fp_dbg("%p entering state %d", machine, machine->cur_state);
|
fp_dbg ("%p entering state %d", machine, machine->cur_state);
|
||||||
machine->handler(machine, machine->dev, machine->user_data);
|
machine->handler (machine, machine->dev, machine->user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_ssm_start:
|
* fpi_ssm_start:
|
||||||
* @ssm: an #fpi_ssm state machine
|
* @ssm: an #FpiSsm state machine
|
||||||
* @callback: the #ssm_completed_fn callback to call on completion
|
* @callback: the #FpiSsmCompletedCallback callback to call on completion
|
||||||
*
|
*
|
||||||
* Starts a state machine. You can also use this function to restart
|
* Starts a state machine. You can also use this function to restart
|
||||||
* a completed or failed state machine. The @callback will be called
|
* a completed or failed state machine. The @callback will be called
|
||||||
* on completion.
|
* on completion.
|
||||||
*/
|
*/
|
||||||
void fpi_ssm_start(fpi_ssm *ssm, ssm_completed_fn callback)
|
void
|
||||||
|
fpi_ssm_start (FpiSsm *ssm, FpiSsmCompletedCallback callback)
|
||||||
{
|
{
|
||||||
BUG_ON(!ssm->completed);
|
BUG_ON (!ssm->completed);
|
||||||
ssm->callback = callback;
|
ssm->callback = callback;
|
||||||
ssm->cur_state = 0;
|
ssm->cur_state = 0;
|
||||||
ssm->completed = FALSE;
|
ssm->completed = FALSE;
|
||||||
ssm->error = 0;
|
ssm->error = NULL;
|
||||||
__ssm_call_handler(ssm);
|
__ssm_call_handler (ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __subsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
static void
|
||||||
|
__subsm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error)
|
||||||
{
|
{
|
||||||
fpi_ssm *parent = ssm->parentsm;
|
FpiSsm *parent = ssm->parentsm;
|
||||||
BUG_ON(!parent);
|
|
||||||
if (ssm->error)
|
BUG_ON (!parent);
|
||||||
fpi_ssm_mark_failed(parent, ssm->error);
|
if (error)
|
||||||
|
fpi_ssm_mark_failed (parent, error);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(parent);
|
fpi_ssm_next_state (parent);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free (ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_ssm_start_subsm:
|
* fpi_ssm_start_subsm:
|
||||||
* @parent: an #fpi_ssm state machine
|
* @parent: an #FpiSsm state machine
|
||||||
* @child: an #fpi_ssm state machine
|
* @child: an #FpiSsm state machine
|
||||||
*
|
*
|
||||||
* Starts a state machine as a child of another. if the child completes
|
* Starts a state machine as a child of another. if the child completes
|
||||||
* successfully, the parent will be advanced to the next state. if the
|
* successfully, the parent will be advanced to the next state. if the
|
||||||
|
@ -194,124 +203,185 @@ static void __subsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
*
|
*
|
||||||
* The child will be automatically freed upon completion or failure.
|
* The child will be automatically freed upon completion or failure.
|
||||||
*/
|
*/
|
||||||
void fpi_ssm_start_subsm(fpi_ssm *parent, fpi_ssm *child)
|
void
|
||||||
|
fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child)
|
||||||
{
|
{
|
||||||
child->parentsm = parent;
|
child->parentsm = parent;
|
||||||
fpi_ssm_start(child, __subsm_complete);
|
fpi_ssm_start (child, __subsm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_ssm_mark_completed:
|
* fpi_ssm_mark_completed:
|
||||||
* @machine: an #fpi_ssm state machine
|
* @machine: an #FpiSsm state machine
|
||||||
*
|
*
|
||||||
* Mark a ssm as completed successfully. The callback set when creating
|
* Mark a ssm as completed successfully. The callback set when creating
|
||||||
* the state machine with fpi_ssm_new() will be called synchronously.
|
* the state machine with fpi_ssm_new() will be called synchronously.
|
||||||
*/
|
*/
|
||||||
void fpi_ssm_mark_completed(fpi_ssm *machine)
|
void
|
||||||
|
fpi_ssm_mark_completed (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
BUG_ON(machine->completed);
|
BUG_ON (machine->completed);
|
||||||
machine->completed = TRUE;
|
machine->completed = TRUE;
|
||||||
fp_dbg("%p completed with status %d", machine, machine->error);
|
if (machine->error)
|
||||||
|
fp_dbg ("%p completed with error: %s", machine, machine->error->message);
|
||||||
|
else
|
||||||
|
fp_dbg ("%p completed successfully", machine);
|
||||||
if (machine->callback)
|
if (machine->callback)
|
||||||
machine->callback(machine, machine->dev, machine->user_data);
|
{
|
||||||
|
GError *error = machine->error ? g_error_copy (machine->error) : NULL;
|
||||||
|
|
||||||
|
machine->callback (machine, machine->dev, machine->user_data, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_ssm_mark_failed:
|
* fpi_ssm_mark_failed:
|
||||||
* @machine: an #fpi_ssm state machine
|
* @machine: an #FpiSsm state machine
|
||||||
* @error: the error code
|
* @error: a #GError
|
||||||
*
|
*
|
||||||
* Mark a state machine as failed with @error as the error code.
|
* Mark a state machine as failed with @error as the error code.
|
||||||
*/
|
*/
|
||||||
void fpi_ssm_mark_failed(fpi_ssm *machine, int error)
|
void
|
||||||
|
fpi_ssm_mark_failed (FpiSsm *machine, GError *error)
|
||||||
{
|
{
|
||||||
fp_dbg("error %d from state %d", error, machine->cur_state);
|
g_assert (error);
|
||||||
BUG_ON(error == 0);
|
if (machine->error)
|
||||||
|
{
|
||||||
|
fp_warn ("SSM already has an error set, ignoring new error %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_dbg ("SSM failed in state %d with error: %s", machine->cur_state, error->message);
|
||||||
machine->error = error;
|
machine->error = error;
|
||||||
fpi_ssm_mark_completed(machine);
|
fpi_ssm_mark_completed (machine);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_ssm_next_state:
|
* fpi_ssm_next_state:
|
||||||
* @machine: an #fpi_ssm state machine
|
* @machine: an #FpiSsm state machine
|
||||||
*
|
*
|
||||||
* Iterate to next state of a state machine. If the current state is the
|
* Iterate to next state of a state machine. If the current state is the
|
||||||
* last state, then the state machine will be marked as completed, as
|
* last state, then the state machine will be marked as completed, as
|
||||||
* if calling fpi_ssm_mark_completed().
|
* if calling fpi_ssm_mark_completed().
|
||||||
*/
|
*/
|
||||||
void fpi_ssm_next_state(fpi_ssm *machine)
|
void
|
||||||
|
fpi_ssm_next_state (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
g_return_if_fail (machine != NULL);
|
g_return_if_fail (machine != NULL);
|
||||||
|
|
||||||
BUG_ON(machine->completed);
|
BUG_ON (machine->completed);
|
||||||
machine->cur_state++;
|
machine->cur_state++;
|
||||||
if (machine->cur_state == machine->nr_states) {
|
if (machine->cur_state == machine->nr_states)
|
||||||
fpi_ssm_mark_completed(machine);
|
fpi_ssm_mark_completed (machine);
|
||||||
} else {
|
else
|
||||||
__ssm_call_handler(machine);
|
__ssm_call_handler (machine);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_ssm_next_state_timeout_cb:
|
|
||||||
* @dev: a struct #fp_dev
|
|
||||||
* @data: a pointer to an #fpi_ssm state machine
|
|
||||||
*
|
|
||||||
* Same as fpi_ssm_next_state(), but to be used as a callback
|
|
||||||
* for an fpi_timeout_add() callback, when the state change needs
|
|
||||||
* to happen after a timeout.
|
|
||||||
*
|
|
||||||
* Make sure to pass the #fpi_ssm as the `user_data` argument
|
|
||||||
* for that fpi_timeout_add() call.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_ssm_next_state_timeout_cb(struct fp_dev *dev,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
g_return_if_fail (dev != NULL);
|
|
||||||
g_return_if_fail (data != NULL);
|
|
||||||
|
|
||||||
fpi_ssm_next_state(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_ssm_jump_to_state:
|
* fpi_ssm_jump_to_state:
|
||||||
* @machine: an #fpi_ssm state machine
|
* @machine: an #FpiSsm state machine
|
||||||
* @state: the state to jump to
|
* @state: the state to jump to
|
||||||
*
|
*
|
||||||
* Jump to the @state state, bypassing intermediary states.
|
* Jump to the @state state, bypassing intermediary states.
|
||||||
*/
|
*/
|
||||||
void fpi_ssm_jump_to_state(fpi_ssm *machine, int state)
|
void
|
||||||
|
fpi_ssm_jump_to_state (FpiSsm *machine, int state)
|
||||||
{
|
{
|
||||||
BUG_ON(machine->completed);
|
BUG_ON (machine->completed);
|
||||||
BUG_ON(state >= machine->nr_states);
|
BUG_ON (state >= machine->nr_states);
|
||||||
machine->cur_state = state;
|
machine->cur_state = state;
|
||||||
__ssm_call_handler(machine);
|
__ssm_call_handler (machine);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_ssm_get_cur_state:
|
* fpi_ssm_get_cur_state:
|
||||||
* @machine: an #fpi_ssm state machine
|
* @machine: an #FpiSsm state machine
|
||||||
*
|
*
|
||||||
* Returns the value of the current state. Note that states are
|
* Returns the value of the current state. Note that states are
|
||||||
* 0-indexed, so a value of 0 means “the first state”.
|
* 0-indexed, so a value of 0 means “the first state”.
|
||||||
*
|
*
|
||||||
* Returns: the current state.
|
* Returns: the current state.
|
||||||
*/
|
*/
|
||||||
int fpi_ssm_get_cur_state(fpi_ssm *machine)
|
int
|
||||||
|
fpi_ssm_get_cur_state (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
return machine->cur_state;
|
return machine->cur_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_ssm_get_error:
|
* fpi_ssm_get_error:
|
||||||
* @machine: an #fpi_ssm state machine
|
* @machine: an #FpiSsm state machine
|
||||||
*
|
*
|
||||||
* Returns the error code set by fpi_ssm_mark_failed().
|
* Returns the error code set by fpi_ssm_mark_failed().
|
||||||
*
|
*
|
||||||
* Returns: a error code
|
* Returns: (transfer none): a error code
|
||||||
*/
|
*/
|
||||||
int fpi_ssm_get_error(fpi_ssm *machine)
|
GError *
|
||||||
|
fpi_ssm_get_error (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
return machine->error;
|
return machine->error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_ssm_dup_error:
|
||||||
|
* @machine: an #FpiSsm state machine
|
||||||
|
*
|
||||||
|
* Returns the error code set by fpi_ssm_mark_failed().
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): a error code
|
||||||
|
*/
|
||||||
|
GError *
|
||||||
|
fpi_ssm_dup_error (FpiSsm *machine)
|
||||||
|
{
|
||||||
|
if (machine->error)
|
||||||
|
return g_error_copy (machine->error);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_ssm_next_state_timeout_cb:
|
||||||
|
* @dev: a struct #fp_dev
|
||||||
|
* @data: a pointer to an #FpiSsm state machine
|
||||||
|
*
|
||||||
|
* Same as fpi_ssm_next_state(), but to be used as a callback
|
||||||
|
* for an fpi_timeout_add() callback, when the state change needs
|
||||||
|
* to happen after a timeout.
|
||||||
|
*
|
||||||
|
* Make sure to pass the #FpiSsm as the `user_data` argument
|
||||||
|
* for that fpi_timeout_add() call.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_ssm_next_state_timeout_cb (FpDevice *dev,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
g_return_if_fail (dev != NULL);
|
||||||
|
g_return_if_fail (data != NULL);
|
||||||
|
|
||||||
|
fpi_ssm_next_state (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_ssm_usb_transfer_cb:
|
||||||
|
* @transfer: a #FpiUsbTransfer
|
||||||
|
* @device: a #FpDevice
|
||||||
|
* @user_data: User data (unused)
|
||||||
|
* @error: The #GError or %NULL
|
||||||
|
*
|
||||||
|
* Can be used in as a #FpiUsbTransfer callback handler to automatically
|
||||||
|
* advance or fail a statemachine on transfer completion.
|
||||||
|
*
|
||||||
|
* Make sure to set the #FpiSsm on the transfer.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
|
{
|
||||||
|
g_return_if_fail (transfer->ssm);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
|
else
|
||||||
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -17,70 +18,79 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __FPI_SSM_H__
|
#pragma once
|
||||||
#define __FPI_SSM_H__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include "fp-device.h"
|
||||||
#include <errno.h>
|
#include "fpi-usb-transfer.h"
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
/* async drv <--> lib comms */
|
/* async drv <--> lib comms */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_ssm:
|
* FpiSsm:
|
||||||
*
|
*
|
||||||
* Sequential state machine that iterates sequentially over
|
* Sequential state machine that iterates sequentially over
|
||||||
* a predefined series of states. Can be terminated by either completion or
|
* a predefined series of states. Can be terminated by either completion or
|
||||||
* failure error conditions.
|
* failure error conditions.
|
||||||
*/
|
*/
|
||||||
typedef struct fpi_ssm fpi_ssm;
|
typedef struct _FpiSsm FpiSsm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ssm_completed_fn:
|
* FpiSsmCompletedCallback:
|
||||||
* @ssm: a #fpi_ssm state machine
|
* @ssm: a #FpiSsm state machine
|
||||||
* @dev: the #fp_dev fingerprint device
|
* @dev: the #fp_dev fingerprint device
|
||||||
* @user_data: the user data passed to fpi_ssm_new()
|
* @user_data: the user data passed to fpi_ssm_new()
|
||||||
|
* @error: The #GError or %NULL on successful completion
|
||||||
*
|
*
|
||||||
* The callback called when a state machine completes successfully,
|
* The callback called when a state machine completes successfully,
|
||||||
* as set when calling fpi_ssm_start().
|
* as set when calling fpi_ssm_start().
|
||||||
*/
|
*/
|
||||||
typedef void (*ssm_completed_fn)(fpi_ssm *ssm,
|
typedef void (*FpiSsmCompletedCallback)(FpiSsm *ssm,
|
||||||
struct fp_dev *dev,
|
FpDevice *dev,
|
||||||
void *user_data);
|
void *user_data,
|
||||||
|
GError *error);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ssm_handler_fn:
|
* FpiSsmHandlerCallback:
|
||||||
* @ssm: a #fpi_ssm state machine
|
* @ssm: a #FpiSsm state machine
|
||||||
* @dev: the #fp_dev fingerprint device
|
* @dev: the #fp_dev fingerprint device
|
||||||
* @user_data: the user data passed to fpi_ssm_new()
|
* @user_data: the user data passed to fpi_ssm_new()
|
||||||
*
|
*
|
||||||
* The callback called when a state machine transitions from one
|
* The callback called when a state machine transitions from one
|
||||||
* state to the next, as set when calling fpi_ssm_new().
|
* state to the next, as set when calling fpi_ssm_new().
|
||||||
*/
|
*/
|
||||||
typedef void (*ssm_handler_fn)(fpi_ssm *ssm,
|
typedef void (*FpiSsmHandlerCallback)(FpiSsm *ssm,
|
||||||
struct fp_dev *dev,
|
FpDevice *dev,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
/* for library and drivers */
|
/* for library and drivers */
|
||||||
fpi_ssm *fpi_ssm_new(struct fp_dev *dev,
|
FpiSsm *fpi_ssm_new (FpDevice *dev,
|
||||||
ssm_handler_fn handler,
|
FpiSsmHandlerCallback handler,
|
||||||
int nr_states,
|
int nr_states,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
void fpi_ssm_free(fpi_ssm *machine);
|
void fpi_ssm_free (FpiSsm *machine);
|
||||||
void fpi_ssm_start(fpi_ssm *ssm, ssm_completed_fn callback);
|
void fpi_ssm_start (FpiSsm *ssm,
|
||||||
void fpi_ssm_start_subsm(fpi_ssm *parent, fpi_ssm *child);
|
FpiSsmCompletedCallback callback);
|
||||||
|
void fpi_ssm_start_subsm (FpiSsm *parent,
|
||||||
|
FpiSsm *child);
|
||||||
|
|
||||||
/* for drivers */
|
/* for drivers */
|
||||||
void fpi_ssm_next_state(fpi_ssm *machine);
|
void fpi_ssm_next_state (FpiSsm *machine);
|
||||||
void fpi_ssm_next_state_timeout_cb(struct fp_dev *dev, void *data);
|
void fpi_ssm_jump_to_state (FpiSsm *machine,
|
||||||
void fpi_ssm_jump_to_state(fpi_ssm *machine, int state);
|
int state);
|
||||||
void fpi_ssm_mark_completed(fpi_ssm *machine);
|
void fpi_ssm_mark_completed (FpiSsm *machine);
|
||||||
void fpi_ssm_mark_failed(fpi_ssm *machine, int error);
|
void fpi_ssm_mark_failed (FpiSsm *machine,
|
||||||
void *fpi_ssm_get_user_data(fpi_ssm *machine);
|
GError *error);
|
||||||
int fpi_ssm_get_error(fpi_ssm *machine);
|
void *fpi_ssm_get_user_data (FpiSsm *machine);
|
||||||
int fpi_ssm_get_cur_state(fpi_ssm *machine);
|
GError * fpi_ssm_get_error (FpiSsm *machine);
|
||||||
|
GError * fpi_ssm_dup_error (FpiSsm *machine);
|
||||||
|
int fpi_ssm_get_cur_state (FpiSsm *machine);
|
||||||
|
|
||||||
#endif
|
/* Callbacks to be used by the driver instead of implementing their own
|
||||||
|
* logic.
|
||||||
|
*/
|
||||||
|
void fpi_ssm_next_state_timeout_cb (FpDevice *dev,
|
||||||
|
void *data);
|
||||||
|
void fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer,
|
||||||
|
FpDevice *device,
|
||||||
|
gpointer user_data,
|
||||||
|
GError *error);
|
||||||
|
|
|
@ -1,690 +0,0 @@
|
||||||
/*
|
|
||||||
* Synchronous I/O functionality
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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 "sync"
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
#include "fpi-dev.h"
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
struct sync_open_data {
|
|
||||||
struct fp_dev *dev;
|
|
||||||
int status;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void sync_open_cb(struct fp_dev *dev, int status, void *user_data)
|
|
||||||
{
|
|
||||||
struct sync_open_data *odata = user_data;
|
|
||||||
fp_dbg("status %d", status);
|
|
||||||
odata->dev = dev;
|
|
||||||
odata->status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_open:
|
|
||||||
* @ddev: the struct #fp_dscv_dev discovered device to open
|
|
||||||
*
|
|
||||||
* Opens and initialises a device. This is the function you call in order
|
|
||||||
* to convert a #fp_dscv_dev discovered device into an actual device handle
|
|
||||||
* that you can perform operations with.
|
|
||||||
*
|
|
||||||
* Returns: the opened device handle, or %NULL on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev)
|
|
||||||
{
|
|
||||||
struct fp_dev *dev = NULL;
|
|
||||||
struct sync_open_data *odata = g_malloc0(sizeof(*odata));
|
|
||||||
int r;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
r = fp_async_dev_open(ddev, sync_open_cb, odata);
|
|
||||||
if (r)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
while (!odata->dev)
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (odata->status == 0)
|
|
||||||
dev = odata->dev;
|
|
||||||
else
|
|
||||||
fp_dev_close(odata->dev);
|
|
||||||
|
|
||||||
out:
|
|
||||||
g_free(odata);
|
|
||||||
return dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sync_close_cb(struct fp_dev *dev, void *user_data)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
gboolean *closed = user_data;
|
|
||||||
*closed = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_close:
|
|
||||||
* @dev: the struct #fp_dev device to close. If %NULL, function simply returns
|
|
||||||
*
|
|
||||||
* Closes a device. You must call this function when you have finished using
|
|
||||||
* a fingerprint device.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_dev_close(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
gboolean closed = FALSE;
|
|
||||||
|
|
||||||
if (!dev)
|
|
||||||
return;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
fp_async_dev_close(dev, sync_close_cb, &closed);
|
|
||||||
while (!closed)
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sync_enroll_data {
|
|
||||||
gboolean populated;
|
|
||||||
int result;
|
|
||||||
struct fp_print_data *data;
|
|
||||||
struct fp_img *img;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void sync_enroll_cb(struct fp_dev *dev, int result,
|
|
||||||
struct fp_print_data *data, struct fp_img *img, void *user_data)
|
|
||||||
{
|
|
||||||
struct sync_enroll_data *edata = user_data;
|
|
||||||
fp_dbg("result %d", result);
|
|
||||||
edata->result = result;
|
|
||||||
edata->data = data;
|
|
||||||
edata->img = img;
|
|
||||||
edata->populated = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void enroll_stop_cb(struct fp_dev *dev, void *user_data)
|
|
||||||
{
|
|
||||||
gboolean *stopped = user_data;
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
*stopped = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_enroll_finger_img:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @print_data: a location to return the resultant enrollment data from
|
|
||||||
* the final stage. Must be freed with fp_print_data_free() after use
|
|
||||||
* @img: location to store the scan image. accepts %NULL for no image
|
|
||||||
* storage. If an image is returned, it must be freed with fp_img_free() after
|
|
||||||
* use
|
|
||||||
*
|
|
||||||
* Performs an enroll stage. See [Enrolling](libfprint-Devices-operations.html#enrolling)
|
|
||||||
* for an explanation of enroll stages.
|
|
||||||
*
|
|
||||||
* If no enrollment is in process, this kicks of the process and runs the
|
|
||||||
* first stage. If an enrollment is already in progress, calling this
|
|
||||||
* function runs the next stage, which may well be the last.
|
|
||||||
*
|
|
||||||
* A negative error code may be returned from any stage. When this occurs,
|
|
||||||
* further calls to the enroll function will start a new enrollment process,
|
|
||||||
* i.e. a negative error code indicates that the enrollment process has been
|
|
||||||
* aborted. These error codes only ever indicate unexpected internal errors
|
|
||||||
* or I/O problems.
|
|
||||||
*
|
|
||||||
* The RETRY codes from #fp_enroll_result may be returned from any enroll
|
|
||||||
* stage. These codes indicate that the scan was not successful in that the
|
|
||||||
* user did not position their finger correctly or similar. When a RETRY code
|
|
||||||
* is returned, the enrollment stage is <emphasis role="strong">not</emphasis> advanced, so the next call
|
|
||||||
* into this function will retry the current stage again. The current stage may
|
|
||||||
* need to be retried several times.
|
|
||||||
*
|
|
||||||
* The %FP_ENROLL_FAIL code may be returned from any enroll
|
|
||||||
* stage. This code indicates that even though the scans themselves have been
|
|
||||||
* acceptable, data processing applied to these scans produces incomprehensible
|
|
||||||
* results. In other words, the user may have been scanning a different finger
|
|
||||||
* for each stage or something like that. Like negative error codes, this
|
|
||||||
* return code indicates that the enrollment process has been aborted.
|
|
||||||
*
|
|
||||||
* The %FP_ENROLL_PASS code will only ever be returned for
|
|
||||||
* non-final stages. This return code indicates that the scan was acceptable
|
|
||||||
* and the next call into this function will advance onto the next enroll
|
|
||||||
* stage.
|
|
||||||
*
|
|
||||||
* The %FP_ENROLL_COMPLETE code will only ever be returned
|
|
||||||
* from the final enroll stage. It indicates that enrollment completed
|
|
||||||
* successfully, and that print_data has been assigned to point to the
|
|
||||||
* resultant enrollment data. The print_data parameter will not be modified
|
|
||||||
* during any other enrollment stages, hence it is actually legal to pass NULL
|
|
||||||
* as this argument for all but the final stage.
|
|
||||||
*
|
|
||||||
* If the device is an imaging device, it can also return the image from
|
|
||||||
* the scan, even when the enroll fails with a RETRY or FAIL code. It is legal
|
|
||||||
* to call this function even on non-imaging devices, just don't expect them to
|
|
||||||
* provide images.
|
|
||||||
*
|
|
||||||
* Returns: negative code on error, otherwise a code from #fp_enroll_result
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_enroll_finger_img(struct fp_dev *dev,
|
|
||||||
struct fp_print_data **print_data, struct fp_img **img)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
int stage = dev->__enroll_stage;
|
|
||||||
gboolean final = FALSE;
|
|
||||||
gboolean stopped = FALSE;
|
|
||||||
struct sync_enroll_data *edata = NULL;
|
|
||||||
int r;
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
|
|
||||||
/* FIXME __enroll_stage is ugly, can we replace it by some function that
|
|
||||||
* says whether we're enrolling or not, and then put __enroll_stage into
|
|
||||||
* edata? */
|
|
||||||
|
|
||||||
if (stage == -1) {
|
|
||||||
edata = g_malloc0(sizeof(struct sync_enroll_data));
|
|
||||||
r = fp_async_enroll_start(dev, sync_enroll_cb, edata);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(edata);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->__enroll_stage = ++stage;
|
|
||||||
} else if (stage >= dev->nr_enroll_stages) {
|
|
||||||
fp_err("exceeding number of enroll stages for device claimed by "
|
|
||||||
"driver %s (%d stages)", drv->name, dev->nr_enroll_stages);
|
|
||||||
dev->__enroll_stage = -1;
|
|
||||||
r = -EINVAL;
|
|
||||||
final = TRUE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
fp_dbg("%s will handle enroll stage %d/%d", drv->name, stage,
|
|
||||||
dev->nr_enroll_stages - 1);
|
|
||||||
|
|
||||||
/* FIXME this isn't very clean */
|
|
||||||
edata = dev->enroll_stage_cb_data;
|
|
||||||
|
|
||||||
while (!edata->populated) {
|
|
||||||
r = fp_handle_events();
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(edata);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
edata->populated = FALSE;
|
|
||||||
|
|
||||||
if (img)
|
|
||||||
*img = edata->img;
|
|
||||||
else
|
|
||||||
fp_img_free(edata->img);
|
|
||||||
|
|
||||||
r = edata->result;
|
|
||||||
switch (r) {
|
|
||||||
case FP_ENROLL_PASS:
|
|
||||||
fp_dbg("enroll stage passed");
|
|
||||||
dev->__enroll_stage = stage + 1;
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_COMPLETE:
|
|
||||||
fp_dbg("enroll complete");
|
|
||||||
dev->__enroll_stage = -1;
|
|
||||||
*print_data = edata->data;
|
|
||||||
final = TRUE;
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY:
|
|
||||||
fp_dbg("enroll should retry");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY_TOO_SHORT:
|
|
||||||
fp_dbg("swipe was too short, enroll should retry");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY_CENTER_FINGER:
|
|
||||||
fp_dbg("finger was not centered, enroll should retry");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY_REMOVE_FINGER:
|
|
||||||
fp_dbg("scan failed, remove finger and retry");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_FAIL:
|
|
||||||
fp_err("enroll failed");
|
|
||||||
dev->__enroll_stage = -1;
|
|
||||||
final = TRUE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fp_err("unrecognised return code %d", r);
|
|
||||||
dev->__enroll_stage = -1;
|
|
||||||
r = -EINVAL;
|
|
||||||
final = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!final)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (final) {
|
|
||||||
fp_dbg("ending enrollment");
|
|
||||||
g_free(edata);
|
|
||||||
}
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (fp_async_enroll_stop(dev, enroll_stop_cb, &stopped) == 0)
|
|
||||||
while (!stopped)
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
break;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_enroll_finger:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @print_data: a location to return the resultant enrollment data from
|
|
||||||
* the final stage. Must be freed with fp_print_data_free() after use
|
|
||||||
*
|
|
||||||
* Performs an enroll stage. See [Enrolling](libfprint-Devices-operations.html#enrolling)
|
|
||||||
* for an explanation of enroll stages. This function is just a shortcut to
|
|
||||||
* calling fp_enroll_finger_img() with a %NULL image parameter. Be sure to read
|
|
||||||
* the description of fp_enroll_finger_img() in order to understand its behaviour.
|
|
||||||
*
|
|
||||||
* Returns: negative code on error, otherwise a code from #fp_enroll_result
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_enroll_finger(struct fp_dev *dev,
|
|
||||||
struct fp_print_data **print_data)
|
|
||||||
{
|
|
||||||
return fp_enroll_finger_img(dev, print_data, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sync_verify_data {
|
|
||||||
gboolean populated;
|
|
||||||
int result;
|
|
||||||
struct fp_img *img;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void sync_verify_cb(struct fp_dev *dev, int result, struct fp_img *img,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
struct sync_verify_data *vdata = user_data;
|
|
||||||
vdata->result = result;
|
|
||||||
vdata->img = img;
|
|
||||||
vdata->populated = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void verify_stop_cb(struct fp_dev *dev, void *user_data)
|
|
||||||
{
|
|
||||||
gboolean *stopped = user_data;
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
*stopped = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_verify_finger_img:
|
|
||||||
* @dev: the struct #fp_dev device to perform the scan on
|
|
||||||
* @enrolled_print: the print to verify against. Must have been previously
|
|
||||||
* enrolled with a device compatible to the device selected to perform the scan
|
|
||||||
* @img: location to store the scan image. accepts %NULL for no image
|
|
||||||
* storage. If an image is returned, it must be freed with fp_img_free() after
|
|
||||||
* use
|
|
||||||
|
|
||||||
* Performs a new scan and verifies it against a previously enrolled print.
|
|
||||||
* If the device is an imaging device, it can also return the image from
|
|
||||||
* the scan, even when the verify fails with a RETRY code. It is legal to
|
|
||||||
* call this function even on non-imaging devices, just don't expect them to
|
|
||||||
* provide images.
|
|
||||||
*
|
|
||||||
* Returns: negative code on error, otherwise a code from #fp_verify_result
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_verify_finger_img(struct fp_dev *dev,
|
|
||||||
struct fp_print_data *enrolled_print, struct fp_img **img)
|
|
||||||
{
|
|
||||||
struct sync_verify_data *vdata;
|
|
||||||
gboolean stopped = FALSE;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!enrolled_print) {
|
|
||||||
fp_err("no print given");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fp_dev_supports_print_data(dev, enrolled_print)) {
|
|
||||||
fp_err("print is not compatible with device");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_dbg("to be handled by %s", dev->drv->name);
|
|
||||||
vdata = g_malloc0(sizeof(struct sync_verify_data));
|
|
||||||
r = fp_async_verify_start(dev, enrolled_print, sync_verify_cb, vdata);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_dbg("verify_start error %d", r);
|
|
||||||
g_free(vdata);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!vdata->populated) {
|
|
||||||
r = fp_handle_events();
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(vdata);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (img)
|
|
||||||
*img = vdata->img;
|
|
||||||
else
|
|
||||||
fp_img_free(vdata->img);
|
|
||||||
|
|
||||||
r = vdata->result;
|
|
||||||
g_free(vdata);
|
|
||||||
switch (r) {
|
|
||||||
case FP_VERIFY_NO_MATCH:
|
|
||||||
fp_dbg("result: no match");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_MATCH:
|
|
||||||
fp_dbg("result: match");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY:
|
|
||||||
fp_dbg("verify should retry");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_TOO_SHORT:
|
|
||||||
fp_dbg("swipe was too short, verify should retry");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_CENTER_FINGER:
|
|
||||||
fp_dbg("finger was not centered, verify should retry");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_REMOVE_FINGER:
|
|
||||||
fp_dbg("scan failed, remove finger and retry");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fp_err("unrecognised return code %d", r);
|
|
||||||
r = -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err:
|
|
||||||
fp_dbg("ending verification");
|
|
||||||
if (fp_async_verify_stop(dev, verify_stop_cb, &stopped) == 0)
|
|
||||||
while (!stopped)
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_verify_finger:
|
|
||||||
* @dev: the struct #fp_dev device to perform the scan on
|
|
||||||
* @enrolled_print: the print to verify against. Must have been previously
|
|
||||||
* enrolled with a device compatible to the device selected to perform the scan
|
|
||||||
*
|
|
||||||
* Performs a new scan and verify it against a previously enrolled print. This
|
|
||||||
* function is just a shortcut to calling fp_verify_finger_img() with a NULL
|
|
||||||
* image output parameter.
|
|
||||||
*
|
|
||||||
* See also fp_verify_finger_img().
|
|
||||||
*
|
|
||||||
* Returns: negative code on error, otherwise a code from #fp_verify_result
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_verify_finger(struct fp_dev *dev,
|
|
||||||
struct fp_print_data *enrolled_print)
|
|
||||||
{
|
|
||||||
return fp_verify_finger_img(dev, enrolled_print, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sync_identify_data {
|
|
||||||
gboolean populated;
|
|
||||||
int result;
|
|
||||||
size_t match_offset;
|
|
||||||
struct fp_img *img;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void sync_identify_cb(struct fp_dev *dev, int result,
|
|
||||||
size_t match_offset, struct fp_img *img, void *user_data)
|
|
||||||
{
|
|
||||||
struct sync_identify_data *idata = user_data;
|
|
||||||
idata->result = result;
|
|
||||||
idata->match_offset = match_offset;
|
|
||||||
idata->img = img;
|
|
||||||
idata->populated = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void identify_stop_cb(struct fp_dev *dev, void *user_data)
|
|
||||||
{
|
|
||||||
gboolean *stopped = user_data;
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
*stopped = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_identify_finger_img:
|
|
||||||
* @dev: the struct #fp_dev device to perform the scan on
|
|
||||||
* @print_gallery: NULL-terminated array of pointers to the prints to
|
|
||||||
* identify against. Each one must have been previously enrolled with a device
|
|
||||||
* compatible to the device selected to perform the scan
|
|
||||||
* @match_offset: output location to store the array index of the matched
|
|
||||||
* gallery print (if any was found). Only valid if %FP_VERIFY_MATCH was
|
|
||||||
* returned
|
|
||||||
* @img: location to store the scan image. accepts %NULL for no image
|
|
||||||
* storage. If an image is returned, it must be freed with fp_img_free() after
|
|
||||||
* use
|
|
||||||
|
|
||||||
* Performs a new scan and attempts to identify the scanned finger against
|
|
||||||
* a collection of previously enrolled fingerprints.
|
|
||||||
* If the device is an imaging device, it can also return the image from
|
|
||||||
* the scan, even when identification fails with a RETRY code. It is legal to
|
|
||||||
* call this function even on non-imaging devices, just don't expect them to
|
|
||||||
* provide images.
|
|
||||||
*
|
|
||||||
* This function returns codes from #fp_verify_result. The return code
|
|
||||||
* %FP_VERIFY_MATCH indicates that the scanned fingerprint
|
|
||||||
* does appear in the print gallery, and the match_offset output parameter
|
|
||||||
* will indicate the index into the print gallery array of the matched print.
|
|
||||||
*
|
|
||||||
* This function will not necessarily examine the whole print gallery, it
|
|
||||||
* will return as soon as it finds a matching print.
|
|
||||||
*
|
|
||||||
* Not all devices support identification. -ENOTSUP will be returned when
|
|
||||||
* this is the case.
|
|
||||||
*
|
|
||||||
* Returns: negative code on error, otherwise a code from #fp_verify_result
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_identify_finger_img(struct fp_dev *dev,
|
|
||||||
struct fp_print_data **print_gallery, size_t *match_offset,
|
|
||||||
struct fp_img **img)
|
|
||||||
{
|
|
||||||
gboolean stopped = FALSE;
|
|
||||||
struct sync_identify_data *idata
|
|
||||||
= g_malloc0(sizeof(struct sync_identify_data));
|
|
||||||
int r;
|
|
||||||
|
|
||||||
fp_dbg("to be handled by %s", dev->drv->name);
|
|
||||||
|
|
||||||
r = fp_async_identify_start(dev, print_gallery, sync_identify_cb, idata);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("identify_start error %d", r);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!idata->populated) {
|
|
||||||
r = fp_handle_events();
|
|
||||||
if (r < 0)
|
|
||||||
goto err_stop;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (img)
|
|
||||||
*img = idata->img;
|
|
||||||
else
|
|
||||||
fp_img_free(idata->img);
|
|
||||||
|
|
||||||
r = idata->result;
|
|
||||||
switch (idata->result) {
|
|
||||||
case FP_VERIFY_NO_MATCH:
|
|
||||||
fp_dbg("result: no match");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_MATCH:
|
|
||||||
fp_dbg("result: match at offset %zd", idata->match_offset);
|
|
||||||
*match_offset = idata->match_offset;
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY:
|
|
||||||
fp_dbg("verify should retry");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_TOO_SHORT:
|
|
||||||
fp_dbg("swipe was too short, verify should retry");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_CENTER_FINGER:
|
|
||||||
fp_dbg("finger was not centered, verify should retry");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_REMOVE_FINGER:
|
|
||||||
fp_dbg("scan failed, remove finger and retry");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fp_err("unrecognised return code %d", r);
|
|
||||||
r = -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err_stop:
|
|
||||||
if (fp_async_identify_stop(dev, identify_stop_cb, &stopped) == 0)
|
|
||||||
while (!stopped)
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
err:
|
|
||||||
g_free(idata);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_identify_finger:
|
|
||||||
* @dev: the struct #fp_dev device to perform the scan on
|
|
||||||
* @print_gallery: %NULL-terminated array of pointers to the prints to
|
|
||||||
* identify against. Each one must have been previously enrolled with a device
|
|
||||||
* compatible to the device selected to perform the scan
|
|
||||||
* @match_offset: output location to store the array index of the matched
|
|
||||||
* gallery print (if any was found). Only valid if %FP_VERIFY_MATCH was
|
|
||||||
* returned
|
|
||||||
|
|
||||||
* Performs a new scan and attempts to identify the scanned finger against a
|
|
||||||
* collection of previously enrolled fingerprints. This function is just a
|
|
||||||
* shortcut to calling fp_identify_finger_img() with a %NULL image output
|
|
||||||
* parameter.
|
|
||||||
*
|
|
||||||
* See also fp_identify_finger_img().
|
|
||||||
*
|
|
||||||
* Returns: negative code on error, otherwise a code from #fp_verify_result
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_identify_finger(struct fp_dev *dev,
|
|
||||||
struct fp_print_data **print_gallery, size_t *match_offset)
|
|
||||||
{
|
|
||||||
return fp_identify_finger_img(dev, print_gallery, match_offset, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sync_capture_data {
|
|
||||||
gboolean populated;
|
|
||||||
int result;
|
|
||||||
struct fp_img *img;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void sync_capture_cb(struct fp_dev *dev, int result, struct fp_img *img,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
struct sync_capture_data *vdata = user_data;
|
|
||||||
vdata->result = result;
|
|
||||||
vdata->img = img;
|
|
||||||
vdata->populated = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void capture_stop_cb(struct fp_dev *dev, void *user_data)
|
|
||||||
{
|
|
||||||
gboolean *stopped = user_data;
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
*stopped = TRUE;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* fp_dev_img_capture:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @unconditional: whether to unconditionally capture an image, or to only capture when a finger is detected
|
|
||||||
* @img: a location to return the captured image. Must be freed with
|
|
||||||
* fp_img_free() after use
|
|
||||||
*
|
|
||||||
* Captures a #fp_img from a device. The returned image is the raw
|
|
||||||
* image provided by the device, you may wish to [standardize](libfprint-Image-operations.html#img_std) it.
|
|
||||||
*
|
|
||||||
* If set, the @unconditional flag indicates that the device should
|
|
||||||
* capture an image unconditionally, regardless of whether a finger is there
|
|
||||||
* or not. If unset, this function will block until a finger is detected on
|
|
||||||
* the sensor.
|
|
||||||
*
|
|
||||||
* See fp_dev_supports_imaging().
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error. -ENOTSUP indicates that either the
|
|
||||||
* @unconditional flag was set but the device does not support this, or that the
|
|
||||||
* device does not support imaging
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_img_capture(struct fp_dev *dev, int unconditional,
|
|
||||||
struct fp_img **img)
|
|
||||||
{
|
|
||||||
struct sync_capture_data *vdata;
|
|
||||||
gboolean stopped = FALSE;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!dev->drv->capture_start) {
|
|
||||||
fp_dbg("image capture is not supported on %s device", dev->drv->name);
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_dbg("to be handled by %s", dev->drv->name);
|
|
||||||
vdata = g_malloc0(sizeof(struct sync_capture_data));
|
|
||||||
r = fp_async_capture_start(dev, unconditional, sync_capture_cb, vdata);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_dbg("capture_start error %d", r);
|
|
||||||
g_free(vdata);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!vdata->populated) {
|
|
||||||
r = fp_handle_events();
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(vdata);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (img)
|
|
||||||
*img = vdata->img;
|
|
||||||
else
|
|
||||||
fp_img_free(vdata->img);
|
|
||||||
|
|
||||||
r = vdata->result;
|
|
||||||
g_free(vdata);
|
|
||||||
switch (r) {
|
|
||||||
case FP_CAPTURE_COMPLETE:
|
|
||||||
fp_dbg("result: complete");
|
|
||||||
break;
|
|
||||||
case FP_CAPTURE_FAIL:
|
|
||||||
fp_dbg("result: fail");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fp_err("unrecognised return code %d", r);
|
|
||||||
r = -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err:
|
|
||||||
fp_dbg("ending capture");
|
|
||||||
if (fp_async_capture_stop(dev, capture_stop_cb, &stopped) == 0)
|
|
||||||
while (!stopped)
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
522
libfprint/fpi-usb-transfer.c
Normal file
522
libfprint/fpi-usb-transfer.c
Normal file
|
@ -0,0 +1,522 @@
|
||||||
|
/*
|
||||||
|
* FPrint USB transfer handling
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fpi-usb-transfer.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:fpi-usb-transfer
|
||||||
|
* @title: USB transfer helpers
|
||||||
|
* @short_description: Helpers for libgusb to ease transfer handling
|
||||||
|
*
|
||||||
|
* #FpiUsbTransfer is a structure to simplify the USB transfer handling.
|
||||||
|
* The main goal is to ease memory management and provide more parameters
|
||||||
|
* to callbacks that are useful for libfprint drivers.
|
||||||
|
*
|
||||||
|
* Drivers should use this API only rather than accessing the GUsbDevice
|
||||||
|
* directly in most cases.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
G_DEFINE_BOXED_TYPE (FpiUsbTransfer, fpi_usb_transfer, fpi_usb_transfer_ref, fpi_usb_transfer_unref)
|
||||||
|
|
||||||
|
static void
|
||||||
|
log_transfer (FpiUsbTransfer *transfer, gboolean submit, GError *error)
|
||||||
|
{
|
||||||
|
if (g_getenv ("FP_DEBUG_TRANSFER"))
|
||||||
|
{
|
||||||
|
if (!submit)
|
||||||
|
{
|
||||||
|
g_autofree gchar *error_str = NULL;
|
||||||
|
if (error)
|
||||||
|
error_str = g_strdup_printf ("with error (%s)", error->message);
|
||||||
|
else
|
||||||
|
error_str = g_strdup ("successfully");
|
||||||
|
|
||||||
|
g_debug ("Transfer %p completed %s, requested length %zd, actual length %zd, endpoint 0x%x",
|
||||||
|
transfer,
|
||||||
|
error_str,
|
||||||
|
transfer->length,
|
||||||
|
transfer->actual_length,
|
||||||
|
transfer->endpoint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_debug ("Transfer %p submitted, requested length %zd, endpoint 0x%x",
|
||||||
|
transfer,
|
||||||
|
transfer->length,
|
||||||
|
transfer->endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!submit == !!(transfer->endpoint & FPI_USB_ENDPOINT_IN))
|
||||||
|
{
|
||||||
|
g_autoptr(GString) line = NULL;
|
||||||
|
gssize dump_len;
|
||||||
|
|
||||||
|
dump_len = (transfer->endpoint & FPI_USB_ENDPOINT_IN) ? transfer->actual_length : transfer->length;
|
||||||
|
|
||||||
|
line = g_string_new ("");
|
||||||
|
/* Dump the buffer. */
|
||||||
|
for (gint i = 0; i < dump_len; i++)
|
||||||
|
{
|
||||||
|
g_string_append_printf (line, "%02x ", transfer->buffer[i]);
|
||||||
|
if ((i + 1) % 16 == 0)
|
||||||
|
{
|
||||||
|
g_debug ("%s", line->str);
|
||||||
|
g_string_set_size (line, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line->len)
|
||||||
|
g_debug ("%s", line->str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_usb_transfer_new:
|
||||||
|
* @device: The #FpDevice the transfer is for
|
||||||
|
*
|
||||||
|
* Creates a new #FpiUsbTransfer.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): A newly created #FpiUsbTransfer
|
||||||
|
*/
|
||||||
|
FpiUsbTransfer *
|
||||||
|
fpi_usb_transfer_new (FpDevice * device)
|
||||||
|
{
|
||||||
|
FpiUsbTransfer *self;
|
||||||
|
|
||||||
|
g_assert (device != NULL);
|
||||||
|
|
||||||
|
self = g_slice_new0 (FpiUsbTransfer);
|
||||||
|
self->ref_count = 1;
|
||||||
|
|
||||||
|
self->device = device;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_usb_transfer_free (FpiUsbTransfer *self)
|
||||||
|
{
|
||||||
|
g_assert (self);
|
||||||
|
g_assert_cmpint (self->ref_count, ==, 0);
|
||||||
|
|
||||||
|
if (self->free_buffer && self->buffer)
|
||||||
|
self->free_buffer (self->buffer);
|
||||||
|
self->buffer = NULL;
|
||||||
|
|
||||||
|
g_slice_free (FpiUsbTransfer, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_usb_transfer_ref:
|
||||||
|
* @self: A #FpiUsbTransfer
|
||||||
|
*
|
||||||
|
* Increments the reference count of @self by one.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): @self
|
||||||
|
*/
|
||||||
|
FpiUsbTransfer *
|
||||||
|
fpi_usb_transfer_ref (FpiUsbTransfer *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (self, NULL);
|
||||||
|
g_return_val_if_fail (self->ref_count, NULL);
|
||||||
|
|
||||||
|
g_atomic_int_inc (&self->ref_count);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_usb_transfer_unref:
|
||||||
|
* @self: A #FpiUsbTransfer
|
||||||
|
*
|
||||||
|
* Decrements the reference count of @self by one, freeing the structure when
|
||||||
|
* the reference count reaches zero.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_usb_transfer_unref (FpiUsbTransfer *self)
|
||||||
|
{
|
||||||
|
g_return_if_fail (self);
|
||||||
|
g_return_if_fail (self->ref_count);
|
||||||
|
|
||||||
|
if (g_atomic_int_dec_and_test (&self->ref_count))
|
||||||
|
fpi_usb_transfer_free (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_usb_transfer_fill_bulk:
|
||||||
|
* @transfer: The #FpiUsbTransfer
|
||||||
|
* @endpoint: The endpoint to send the transfer to
|
||||||
|
* @length: The buffer size to allocate
|
||||||
|
*
|
||||||
|
* Prepare a bulk transfer. A buffer will be created for you, use
|
||||||
|
* fpi_usb_transfer_fill_bulk_full() if you want to send a static buffer
|
||||||
|
* or receive a pre-defined buffer.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_usb_transfer_fill_bulk (FpiUsbTransfer *transfer,
|
||||||
|
guint8 endpoint,
|
||||||
|
gsize length)
|
||||||
|
{
|
||||||
|
fpi_usb_transfer_fill_bulk_full (transfer,
|
||||||
|
endpoint,
|
||||||
|
g_malloc0 (length),
|
||||||
|
length,
|
||||||
|
g_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @length: The size of @buffer
|
||||||
|
* @free_func: (destroy buffer): Destroy notify for @buffer
|
||||||
|
*
|
||||||
|
* Prepare a bulk transfer.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_usb_transfer_fill_bulk_full (FpiUsbTransfer *transfer,
|
||||||
|
guint8 endpoint,
|
||||||
|
guint8 *buffer,
|
||||||
|
gsize length,
|
||||||
|
GDestroyNotify free_func)
|
||||||
|
{
|
||||||
|
g_assert (transfer->type == FP_TRANSFER_NONE);
|
||||||
|
g_assert (buffer != NULL);
|
||||||
|
|
||||||
|
transfer->type = FP_TRANSFER_BULK;
|
||||||
|
transfer->endpoint = endpoint;
|
||||||
|
|
||||||
|
transfer->buffer = buffer;
|
||||||
|
transfer->length = length;
|
||||||
|
transfer->free_buffer = free_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_usb_transfer_fill_control:
|
||||||
|
* @transfer: The #FpiUsbTransfer
|
||||||
|
* @direction: The direction of the control transfer
|
||||||
|
* @request_type: The request type
|
||||||
|
* @recipient: The recipient
|
||||||
|
* @request: The control transfer request
|
||||||
|
* @value: The control transfer value
|
||||||
|
* @idx: The control transfer index
|
||||||
|
* @length: The size of the transfer
|
||||||
|
*
|
||||||
|
* Prepare a control transfer. The function will create a new buffer,
|
||||||
|
* you can initialize the buffer after calling this function.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_usb_transfer_fill_control (FpiUsbTransfer *transfer,
|
||||||
|
GUsbDeviceDirection direction,
|
||||||
|
GUsbDeviceRequestType request_type,
|
||||||
|
GUsbDeviceRecipient recipient,
|
||||||
|
guint8 request,
|
||||||
|
guint16 value,
|
||||||
|
guint16 idx,
|
||||||
|
gsize length)
|
||||||
|
{
|
||||||
|
g_assert (transfer->type == FP_TRANSFER_NONE);
|
||||||
|
|
||||||
|
transfer->type = FP_TRANSFER_CONTROL;
|
||||||
|
transfer->direction = direction;
|
||||||
|
transfer->request_type = request_type;
|
||||||
|
transfer->recipient = recipient;
|
||||||
|
transfer->request = request;
|
||||||
|
transfer->value = value;
|
||||||
|
transfer->idx = idx;
|
||||||
|
|
||||||
|
transfer->length = length;
|
||||||
|
transfer->buffer = g_malloc0 (length);
|
||||||
|
transfer->free_buffer = g_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_usb_transfer_fill_interrupt:
|
||||||
|
* @transfer: The #FpiUsbTransfer
|
||||||
|
* @endpoint: The endpoint to send the transfer to
|
||||||
|
* @length: The size of the transfer
|
||||||
|
*
|
||||||
|
* Prepare an interrupt transfer. The function will create a new buffer,
|
||||||
|
* you can initialize the buffer after calling this function.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_usb_transfer_fill_interrupt (FpiUsbTransfer *transfer,
|
||||||
|
guint8 endpoint,
|
||||||
|
gsize length)
|
||||||
|
{
|
||||||
|
fpi_usb_transfer_fill_interrupt_full (transfer,
|
||||||
|
endpoint,
|
||||||
|
g_malloc0 (length),
|
||||||
|
length,
|
||||||
|
g_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @length: The size of @buffer
|
||||||
|
* @free_func: (destroy buffer): Destroy notify for @buffer
|
||||||
|
*
|
||||||
|
* Prepare an interrupt transfer.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_usb_transfer_fill_interrupt_full (FpiUsbTransfer *transfer,
|
||||||
|
guint8 endpoint,
|
||||||
|
guint8 *buffer,
|
||||||
|
gsize length,
|
||||||
|
GDestroyNotify free_func)
|
||||||
|
{
|
||||||
|
g_assert (transfer->type == FP_TRANSFER_NONE);
|
||||||
|
g_assert (buffer != NULL);
|
||||||
|
|
||||||
|
transfer->type = FP_TRANSFER_INTERRUPT;
|
||||||
|
transfer->endpoint = endpoint;
|
||||||
|
|
||||||
|
transfer->buffer = buffer;
|
||||||
|
transfer->length = length;
|
||||||
|
transfer->free_buffer = free_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
FpiUsbTransfer *transfer = user_data;
|
||||||
|
FpiUsbTransferCallback callback;
|
||||||
|
|
||||||
|
switch (transfer->type)
|
||||||
|
{
|
||||||
|
case FP_TRANSFER_BULK:
|
||||||
|
transfer->actual_length =
|
||||||
|
g_usb_device_bulk_transfer_finish (G_USB_DEVICE (source_object),
|
||||||
|
res,
|
||||||
|
&error);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_TRANSFER_CONTROL:
|
||||||
|
transfer->actual_length =
|
||||||
|
g_usb_device_control_transfer_finish (G_USB_DEVICE (source_object),
|
||||||
|
res,
|
||||||
|
&error);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_TRANSFER_INTERRUPT:
|
||||||
|
transfer->actual_length =
|
||||||
|
g_usb_device_interrupt_transfer_finish (G_USB_DEVICE (source_object),
|
||||||
|
res,
|
||||||
|
&error);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_TRANSFER_NONE:
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
log_transfer (transfer, FALSE, error);
|
||||||
|
|
||||||
|
/* Check for short error, and set an error if requested */
|
||||||
|
if (error == NULL &&
|
||||||
|
transfer->short_is_error &&
|
||||||
|
transfer->actual_length > 0 &&
|
||||||
|
transfer->actual_length != transfer->length)
|
||||||
|
{
|
||||||
|
error = g_error_new (G_USB_DEVICE_ERROR,
|
||||||
|
G_USB_DEVICE_ERROR_IO,
|
||||||
|
"Unexpected short error of %zd size (expected %zd)", transfer->actual_length, transfer->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback = transfer->callback;
|
||||||
|
transfer->callback = NULL;
|
||||||
|
callback (transfer, transfer->device, transfer->user_data, error);
|
||||||
|
|
||||||
|
fpi_usb_transfer_unref (transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_usb_transfer_submit:
|
||||||
|
* @transfer: The transfer to submit, must have been filled.
|
||||||
|
* @timeout_ms: Timeout for the transfer in ms
|
||||||
|
* @cancellable: Cancellable to use, e.g. fpi_device_get_cancellable()
|
||||||
|
* @callback: Callback on completion or error
|
||||||
|
* @user_data: Data to pass to callback
|
||||||
|
*
|
||||||
|
* Submit a USB transfer with a specific timeout and callback functions.
|
||||||
|
*
|
||||||
|
* Note that #FpiUsbTransfer is owned by the user. In most cases, you
|
||||||
|
* should call fpi_usb_transfer_unref() just after calling this function.
|
||||||
|
* Doing so means that all associated data will be free'ed automatically
|
||||||
|
* after the callback ran.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_usb_transfer_submit (FpiUsbTransfer *transfer,
|
||||||
|
guint timeout_ms,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
FpiUsbTransferCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_return_if_fail (transfer);
|
||||||
|
g_return_if_fail (callback);
|
||||||
|
|
||||||
|
/* Recycling is allowed, but not two at the same time. */
|
||||||
|
g_return_if_fail (transfer->callback == NULL);
|
||||||
|
|
||||||
|
transfer->callback = callback;
|
||||||
|
transfer->user_data = user_data;
|
||||||
|
|
||||||
|
/* Grab a reference, this means that one can simply unref after submit and
|
||||||
|
* trust for the data to disappear without explicit management by the callback
|
||||||
|
* function. */
|
||||||
|
fpi_usb_transfer_ref (transfer);
|
||||||
|
|
||||||
|
log_transfer (transfer, TRUE, NULL);
|
||||||
|
|
||||||
|
switch (transfer->type)
|
||||||
|
{
|
||||||
|
case FP_TRANSFER_BULK:
|
||||||
|
g_usb_device_bulk_transfer_async (fpi_device_get_usb_device (transfer->device),
|
||||||
|
transfer->endpoint,
|
||||||
|
transfer->buffer,
|
||||||
|
transfer->length,
|
||||||
|
timeout_ms,
|
||||||
|
cancellable,
|
||||||
|
transfer_finish_cb,
|
||||||
|
transfer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_TRANSFER_CONTROL:
|
||||||
|
g_usb_device_control_transfer_async (fpi_device_get_usb_device (transfer->device),
|
||||||
|
transfer->direction,
|
||||||
|
transfer->request_type,
|
||||||
|
transfer->recipient,
|
||||||
|
transfer->request,
|
||||||
|
transfer->value,
|
||||||
|
transfer->idx,
|
||||||
|
transfer->buffer,
|
||||||
|
transfer->length,
|
||||||
|
timeout_ms,
|
||||||
|
cancellable,
|
||||||
|
transfer_finish_cb,
|
||||||
|
transfer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_TRANSFER_INTERRUPT:
|
||||||
|
g_usb_device_interrupt_transfer_async (fpi_device_get_usb_device (transfer->device),
|
||||||
|
transfer->endpoint,
|
||||||
|
transfer->buffer,
|
||||||
|
transfer->length,
|
||||||
|
timeout_ms,
|
||||||
|
cancellable,
|
||||||
|
transfer_finish_cb,
|
||||||
|
transfer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_TRANSFER_NONE:
|
||||||
|
default:
|
||||||
|
fpi_usb_transfer_unref (transfer);
|
||||||
|
g_return_if_reached ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_usb_transfer_submit_sync:
|
||||||
|
* @transfer: The transfer to submit, must have been filled.
|
||||||
|
* @timeout_ms: Timeout for the transfer in millisecnods
|
||||||
|
* @error: Location to store #GError to
|
||||||
|
*
|
||||||
|
* Synchronously submit a USB transfer with a specific timeout.
|
||||||
|
* Only use this function with short timeouts as the application will
|
||||||
|
* be blocked otherwise.
|
||||||
|
*
|
||||||
|
* Note that you still need to fpi_usb_transfer_unref() the
|
||||||
|
* #FpiUsbTransfer afterwards.
|
||||||
|
*
|
||||||
|
* Returns: #TRUE on success, otherwise #FALSE and @error will be set
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
|
||||||
|
guint timeout_ms,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean res;
|
||||||
|
|
||||||
|
g_return_val_if_fail (transfer, FALSE);
|
||||||
|
|
||||||
|
/* Recycling is allowed, but not two at the same time. */
|
||||||
|
g_return_val_if_fail (transfer->callback == NULL, FALSE);
|
||||||
|
|
||||||
|
log_transfer (transfer, TRUE, NULL);
|
||||||
|
|
||||||
|
switch (transfer->type)
|
||||||
|
{
|
||||||
|
case FP_TRANSFER_BULK:
|
||||||
|
res = g_usb_device_bulk_transfer (fpi_device_get_usb_device (transfer->device),
|
||||||
|
transfer->endpoint,
|
||||||
|
transfer->buffer,
|
||||||
|
transfer->length,
|
||||||
|
&transfer->actual_length,
|
||||||
|
timeout_ms,
|
||||||
|
NULL,
|
||||||
|
error);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_TRANSFER_CONTROL:
|
||||||
|
res = g_usb_device_control_transfer (fpi_device_get_usb_device (transfer->device),
|
||||||
|
transfer->direction,
|
||||||
|
transfer->request_type,
|
||||||
|
transfer->recipient,
|
||||||
|
transfer->request,
|
||||||
|
transfer->value,
|
||||||
|
transfer->idx,
|
||||||
|
transfer->buffer,
|
||||||
|
transfer->length,
|
||||||
|
&transfer->actual_length,
|
||||||
|
timeout_ms,
|
||||||
|
NULL,
|
||||||
|
error);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_TRANSFER_INTERRUPT:
|
||||||
|
res = g_usb_device_interrupt_transfer (fpi_device_get_usb_device (transfer->device),
|
||||||
|
transfer->endpoint,
|
||||||
|
transfer->buffer,
|
||||||
|
transfer->length,
|
||||||
|
&transfer->actual_length,
|
||||||
|
timeout_ms,
|
||||||
|
NULL,
|
||||||
|
error);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_TRANSFER_NONE:
|
||||||
|
default:
|
||||||
|
g_return_val_if_reached (FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_transfer (transfer, FALSE, *error);
|
||||||
|
|
||||||
|
if (!res)
|
||||||
|
transfer->actual_length = -1;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
157
libfprint/fpi-usb-transfer.h
Normal file
157
libfprint/fpi-usb-transfer.h
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
* FPrint USB transfer handling
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gusb.h>
|
||||||
|
#include "fpi-device.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define FPI_TYPE_USB_TRANSFER (fpi_usb_transfer_get_type ())
|
||||||
|
|
||||||
|
#define FPI_USB_ENDPOINT_IN 0x80
|
||||||
|
#define FPI_USB_ENDPOINT_OUT 0x00
|
||||||
|
|
||||||
|
typedef struct _FpiUsbTransfer FpiUsbTransfer;
|
||||||
|
|
||||||
|
#include "fpi-ssm.h"
|
||||||
|
|
||||||
|
typedef void (*FpiUsbTransferCallback)(FpiUsbTransfer *transfer,
|
||||||
|
FpDevice *dev,
|
||||||
|
gpointer user_data,
|
||||||
|
GError *error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpiTransferType:
|
||||||
|
* @FP_TRANSFER_NONE: Type not set
|
||||||
|
* @FP_TRANSFER_BULK: Bulk transfer
|
||||||
|
* @FP_TRANSFER_CONTROL: Control transfer
|
||||||
|
* @FP_TRANSFER_INTERRUPT: Interrupt transfer
|
||||||
|
*
|
||||||
|
* Type of the transfer.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FP_TRANSFER_NONE = 0,
|
||||||
|
FP_TRANSFER_BULK,
|
||||||
|
FP_TRANSFER_CONTROL,
|
||||||
|
FP_TRANSFER_INTERRUPT,
|
||||||
|
} FpiTransferType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpiUsbTransfer:
|
||||||
|
* @device: The #FpDevice that the transfer belongs to.
|
||||||
|
* @ssm: Storage slot to associate the transfer with a state machine.
|
||||||
|
* Used by fpi_ssm_usb_transfer_cb() to modify the given state machine.
|
||||||
|
* @length: The requested length of the transfer in bytes.
|
||||||
|
* @actual_length: The actual length of the transfer
|
||||||
|
* (see also fpi_usb_transfer_set_short_error())
|
||||||
|
* @buffer: The transfered data.
|
||||||
|
*
|
||||||
|
* Helper for handling USB transfers.
|
||||||
|
*/
|
||||||
|
struct _FpiUsbTransfer
|
||||||
|
{
|
||||||
|
/*< public >*/
|
||||||
|
FpDevice *device;
|
||||||
|
|
||||||
|
FpiSsm *ssm;
|
||||||
|
|
||||||
|
gssize length;
|
||||||
|
gssize actual_length;
|
||||||
|
|
||||||
|
guchar *buffer;
|
||||||
|
|
||||||
|
/*< private >*/
|
||||||
|
guint ref_count;
|
||||||
|
|
||||||
|
/* USB Transfer information */
|
||||||
|
FpiTransferType type;
|
||||||
|
guint8 endpoint;
|
||||||
|
|
||||||
|
/* Control Transfer options */
|
||||||
|
GUsbDeviceDirection direction;
|
||||||
|
GUsbDeviceRequestType request_type;
|
||||||
|
GUsbDeviceRecipient recipient;
|
||||||
|
guint8 request;
|
||||||
|
guint16 value;
|
||||||
|
guint16 idx;
|
||||||
|
|
||||||
|
/* Flags */
|
||||||
|
gboolean short_is_error;
|
||||||
|
|
||||||
|
/* Callbacks */
|
||||||
|
gpointer user_data;
|
||||||
|
FpiUsbTransferCallback callback;
|
||||||
|
|
||||||
|
/* Data free function */
|
||||||
|
GDestroyNotify free_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType fpi_usb_transfer_get_type (void) G_GNUC_CONST;
|
||||||
|
FpiUsbTransfer *fpi_usb_transfer_new (FpDevice *device);
|
||||||
|
FpiUsbTransfer *fpi_usb_transfer_ref (FpiUsbTransfer *self);
|
||||||
|
void fpi_usb_transfer_unref (FpiUsbTransfer *self);
|
||||||
|
|
||||||
|
void fpi_usb_transfer_set_short_error (FpiUsbTransfer *transfer,
|
||||||
|
gboolean short_is_error);
|
||||||
|
|
||||||
|
void fpi_usb_transfer_fill_bulk (FpiUsbTransfer *transfer,
|
||||||
|
guint8 endpoint,
|
||||||
|
gsize length);
|
||||||
|
|
||||||
|
void fpi_usb_transfer_fill_bulk_full (FpiUsbTransfer *transfer,
|
||||||
|
guint8 endpoint,
|
||||||
|
guint8 *buffer,
|
||||||
|
gsize length,
|
||||||
|
GDestroyNotify free_func);
|
||||||
|
|
||||||
|
void fpi_usb_transfer_fill_control (FpiUsbTransfer *transfer,
|
||||||
|
GUsbDeviceDirection direction,
|
||||||
|
GUsbDeviceRequestType request_type,
|
||||||
|
GUsbDeviceRecipient recipient,
|
||||||
|
guint8 request,
|
||||||
|
guint16 value,
|
||||||
|
guint16 idx,
|
||||||
|
gsize length);
|
||||||
|
|
||||||
|
void fpi_usb_transfer_fill_interrupt (FpiUsbTransfer *transfer,
|
||||||
|
guint8 endpoint,
|
||||||
|
gsize length);
|
||||||
|
|
||||||
|
void fpi_usb_transfer_fill_interrupt_full (FpiUsbTransfer *transfer,
|
||||||
|
guint8 endpoint,
|
||||||
|
guint8 *buffer,
|
||||||
|
gsize length,
|
||||||
|
GDestroyNotify free_func);
|
||||||
|
|
||||||
|
void fpi_usb_transfer_submit (FpiUsbTransfer *transfer,
|
||||||
|
guint timeout_ms,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
FpiUsbTransferCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
gboolean fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
|
||||||
|
guint timeout_ms,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiUsbTransfer, fpi_usb_transfer_unref)
|
||||||
|
|
||||||
|
G_END_DECLS
|
|
@ -1,236 +0,0 @@
|
||||||
/*
|
|
||||||
* Driver API definitions
|
|
||||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fpi-usb.h"
|
|
||||||
#include "drivers_api.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:fpi-usb
|
|
||||||
* @title: Helpers for libusb
|
|
||||||
* @short_description: libusb-related helpers
|
|
||||||
*
|
|
||||||
* A collection of [libusb helpers](http://libusb.sourceforge.net/api-1.0/group__poll.html#details)
|
|
||||||
* to make driver development easier. Please refer to the libusb API documentation for more
|
|
||||||
* information about the original API.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Helpers from glib */
|
|
||||||
#include <glib.h>
|
|
||||||
#include <glib/gprintf.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
/* special helpers to avoid gmessage.c dependency */
|
|
||||||
static void mem_error (const char *format, ...) G_GNUC_PRINTF (1,2);
|
|
||||||
#define mem_assert(cond) do { if (G_LIKELY (cond)) ; else mem_error ("assertion failed: %s", #cond); } while (0)
|
|
||||||
|
|
||||||
static void
|
|
||||||
mem_error (const char *format,
|
|
||||||
...)
|
|
||||||
{
|
|
||||||
const char *pname;
|
|
||||||
va_list args;
|
|
||||||
/* at least, put out "MEMORY-ERROR", in case we segfault during the rest of the function */
|
|
||||||
fputs ("\n***MEMORY-ERROR***: ", stderr);
|
|
||||||
pname = g_get_prgname();
|
|
||||||
g_fprintf (stderr, "%s[%ld]: ", pname ? pname : "", (long)getpid());
|
|
||||||
va_start (args, format);
|
|
||||||
g_vfprintf (stderr, format, args);
|
|
||||||
va_end (args);
|
|
||||||
fputs ("\n", stderr);
|
|
||||||
abort();
|
|
||||||
_exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fpi_usb_transfer {
|
|
||||||
struct libusb_transfer *transfer;
|
|
||||||
fpi_ssm *ssm;
|
|
||||||
struct fp_dev *dev;
|
|
||||||
fpi_usb_transfer_cb_fn callback;
|
|
||||||
void *user_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_usb_alloc:
|
|
||||||
*
|
|
||||||
* Returns a struct libusb_transfer, similar to calling
|
|
||||||
* `libusb_alloc_transfer(0)`[[1](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga13cc69ea40c702181c430c950121c000)]. As libfprint uses GLib internally,
|
|
||||||
* and [memory allocation failures will make applications fail](https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html#glib-Memory-Allocation.description),
|
|
||||||
* this helper will assert when the libusb call fails.
|
|
||||||
*/
|
|
||||||
struct libusb_transfer *
|
|
||||||
fpi_usb_alloc(void)
|
|
||||||
{
|
|
||||||
struct libusb_transfer *transfer;
|
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
|
||||||
mem_assert(transfer);
|
|
||||||
|
|
||||||
return transfer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static fpi_usb_transfer *
|
|
||||||
fpi_usb_transfer_new(struct fp_dev *dev,
|
|
||||||
fpi_ssm *ssm,
|
|
||||||
fpi_usb_transfer_cb_fn callback,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
fpi_usb_transfer *transfer;
|
|
||||||
|
|
||||||
transfer = g_new0(fpi_usb_transfer, 1);
|
|
||||||
transfer->transfer = fpi_usb_alloc();
|
|
||||||
transfer->dev = dev;
|
|
||||||
transfer->ssm = ssm;
|
|
||||||
transfer->callback = callback;
|
|
||||||
transfer->user_data = user_data;
|
|
||||||
|
|
||||||
return transfer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpi_usb_transfer_free(fpi_usb_transfer *transfer)
|
|
||||||
{
|
|
||||||
if (transfer == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
g_free(transfer->transfer->buffer);
|
|
||||||
libusb_free_transfer(transfer->transfer);
|
|
||||||
g_free(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_usb_transfer_cb (struct libusb_transfer *transfer)
|
|
||||||
{
|
|
||||||
fpi_usb_transfer *t;
|
|
||||||
|
|
||||||
g_assert(transfer);
|
|
||||||
g_assert(transfer->user_data);
|
|
||||||
|
|
||||||
t = transfer->user_data;
|
|
||||||
BUG_ON(transfer->callback == NULL);
|
|
||||||
(t->callback) (transfer, t->dev, t->ssm, t->user_data);
|
|
||||||
fpi_usb_transfer_free(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_usb_fill_bulk_transfer:
|
|
||||||
* @dev: a struct #fp_dev fingerprint device
|
|
||||||
* @ssm: the current #fpi_ssm state machine
|
|
||||||
* @endpoint: the USB end point
|
|
||||||
* @buffer: a buffer allocated with g_malloc() or another GLib function.
|
|
||||||
* Note that the returned #fpi_usb_transfer will own this buffer, so it
|
|
||||||
* should not be freed manually.
|
|
||||||
* @length: the size of @buffer
|
|
||||||
* @callback: the callback function that will be called once the fpi_usb_submit_transfer()
|
|
||||||
* call finishes.
|
|
||||||
* @user_data: a user data pointer to pass to the callback
|
|
||||||
* @timeout: timeout for the transfer in milliseconds, or 0 for no timeout
|
|
||||||
*
|
|
||||||
* This function is similar to calling [`libusb_alloc_transfer(0)`](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga13cc69ea40c702181c430c950121c000)]
|
|
||||||
* followed by calling [`libusb_fill_bulk_transfer()`](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gad4ddb1a5c6c7fefc979a44d7300b95d7).
|
|
||||||
* The #fpi_usb_transfer_cb_fn callback will however provide more arguments
|
|
||||||
* relevant to libfprint drivers, making it a good replacement for the raw libusb
|
|
||||||
* calls.
|
|
||||||
*
|
|
||||||
* Returns: a #fpi_usb_transfer transfer struct, to be passed to
|
|
||||||
* fpi_usb_submit_transfer().
|
|
||||||
*/
|
|
||||||
fpi_usb_transfer *
|
|
||||||
fpi_usb_fill_bulk_transfer (struct fp_dev *dev,
|
|
||||||
fpi_ssm *ssm,
|
|
||||||
unsigned char endpoint,
|
|
||||||
unsigned char *buffer,
|
|
||||||
int length,
|
|
||||||
fpi_usb_transfer_cb_fn callback,
|
|
||||||
void *user_data,
|
|
||||||
unsigned int timeout)
|
|
||||||
{
|
|
||||||
fpi_usb_transfer *transfer;
|
|
||||||
|
|
||||||
g_return_val_if_fail (dev != NULL, NULL);
|
|
||||||
g_return_val_if_fail (callback != NULL, NULL);
|
|
||||||
|
|
||||||
transfer = fpi_usb_transfer_new(dev,
|
|
||||||
ssm,
|
|
||||||
callback,
|
|
||||||
user_data);
|
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(transfer->transfer,
|
|
||||||
fpi_dev_get_usb_dev(dev),
|
|
||||||
endpoint,
|
|
||||||
buffer,
|
|
||||||
length,
|
|
||||||
fpi_usb_transfer_cb,
|
|
||||||
transfer,
|
|
||||||
timeout);
|
|
||||||
|
|
||||||
return transfer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_usb_submit_transfer:
|
|
||||||
* @transfer: a #fpi_usb_transfer struct
|
|
||||||
*
|
|
||||||
* Start a transfer to the device with the provided #fpi_usb_transfer.
|
|
||||||
* On error, the #fpi_usb_transfer struct will be freed, otherwise it will
|
|
||||||
* be freed once the callback provided to fpi_usb_fill_bulk_transfer() has
|
|
||||||
* been called.
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, or the same errors as [libusb_submit_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gabb0932601f2c7dad2fee4b27962848ce)
|
|
||||||
* on failure.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
fpi_usb_submit_transfer(fpi_usb_transfer *transfer)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail (transfer != NULL, LIBUSB_ERROR_INVALID_PARAM);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer->transfer);
|
|
||||||
if (r < 0)
|
|
||||||
fpi_usb_transfer_free(transfer);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_usb_cancel_transfer:
|
|
||||||
* @transfer: a #fpi_usb_transfer struct
|
|
||||||
*
|
|
||||||
* Cancel a transfer to the device with the provided #fpi_usb_transfer.
|
|
||||||
* Note that this will not complete the cancellation, as your transfer
|
|
||||||
* callback will be called with the `LIBUSB_TRANSFER_CANCELLED` status,
|
|
||||||
* as [libusb_cancel_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga685eb7731f9a0593f75beb99727bbe54)
|
|
||||||
* would.
|
|
||||||
*
|
|
||||||
* You should not access anything but the given struct #libusb_transfer
|
|
||||||
* in the callback before checking whether `LIBUSB_TRANSFER_CANCELLED` has
|
|
||||||
* been called, as that might cause memory access violations.
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, or the same errors as [libusb_cancel_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga685eb7731f9a0593f75beb99727bbe54)
|
|
||||||
* on failure.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
fpi_usb_cancel_transfer(fpi_usb_transfer *transfer)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (transfer != NULL, LIBUSB_ERROR_NOT_FOUND);
|
|
||||||
|
|
||||||
return libusb_cancel_transfer(transfer->transfer);
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __FPI_USB_H__
|
|
||||||
#define __FPI_USB_H__
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
#include "fpi-dev.h"
|
|
||||||
#include "fpi-ssm.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_usb_transfer:
|
|
||||||
*
|
|
||||||
* A structure containing the arguments passed to fpi_usb_fill_bulk_transfer()
|
|
||||||
* to be used with fpi_usb_submit_transfer().
|
|
||||||
*/
|
|
||||||
typedef struct fpi_usb_transfer fpi_usb_transfer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_usb_transfer_cb_fn:
|
|
||||||
* @transfer: a struct #libusb_transfer
|
|
||||||
* @dev: the struct #fp_dev on which the operation was performed
|
|
||||||
* @ssm: the #fpi_ssm state machine
|
|
||||||
* @user_data: the user data passed to fpi_usb_fill_bulk_transfer()
|
|
||||||
*
|
|
||||||
* This callback will be called in response to a libusb bulk transfer
|
|
||||||
* triggered via fpi_usb_fill_bulk_transfer() finishing. Note that the
|
|
||||||
* struct #libusb_transfer does not need to be freed, as it will be
|
|
||||||
* freed after the callback returns, similarly to
|
|
||||||
* the [LIBUSB_TRANSFER_FREE_TRANSFER flag](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gga1fb47dd0f7c209b60a3609ff0c03d56dacf3f064997b283a14097c9f4d6f8ccc1).
|
|
||||||
*
|
|
||||||
* Note that the cancelled status of the transfer should be checked
|
|
||||||
* first thing, as the @dev, @ssm and @user_data pointers might not
|
|
||||||
* be pointing to valid values anymore. See fpi_usb_cancel_transfer()
|
|
||||||
* for more information.
|
|
||||||
*/
|
|
||||||
typedef void(*fpi_usb_transfer_cb_fn) (struct libusb_transfer *transfer,
|
|
||||||
struct fp_dev *dev,
|
|
||||||
fpi_ssm *ssm,
|
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
struct libusb_transfer *fpi_usb_alloc(void) __attribute__((returns_nonnull));
|
|
||||||
|
|
||||||
fpi_usb_transfer *fpi_usb_fill_bulk_transfer (struct fp_dev *dev,
|
|
||||||
fpi_ssm *ssm,
|
|
||||||
unsigned char endpoint,
|
|
||||||
unsigned char *buffer,
|
|
||||||
int length,
|
|
||||||
fpi_usb_transfer_cb_fn callback,
|
|
||||||
void *user_data,
|
|
||||||
unsigned int timeout);
|
|
||||||
int fpi_usb_submit_transfer (fpi_usb_transfer *transfer);
|
|
||||||
int fpi_usb_cancel_transfer (fpi_usb_transfer *transfer);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -2,6 +2,7 @@
|
||||||
* Copyright (C) 2009 Red Hat <mjg@redhat.com>
|
* Copyright (C) 2009 Red Hat <mjg@redhat.com>
|
||||||
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
|
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
|
||||||
* Copyright (C) 2008 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net>
|
* Copyright (C) 2008 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net>
|
||||||
|
* Coypright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -22,19 +23,35 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
#include "fp_internal.h"
|
#include "fpi-context.h"
|
||||||
|
#include "fpi-device.h"
|
||||||
|
|
||||||
GHashTable *printed = NULL;
|
GHashTable *printed = NULL;
|
||||||
|
|
||||||
static GList *insert_driver (GList *list,
|
static GList *insert_drivers (GList *list)
|
||||||
struct fp_driver *driver)
|
|
||||||
{
|
{
|
||||||
int i;
|
g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof(GType));
|
||||||
|
gint i;
|
||||||
|
|
||||||
for (i = 0; driver->id_table[i].vendor != 0; i++) {
|
fpi_get_driver_types (drivers);
|
||||||
|
|
||||||
|
/* Find the best driver to handle this USB device. */
|
||||||
|
for (i = 0; i < drivers->len; i++)
|
||||||
|
{
|
||||||
|
GType driver = g_array_index (drivers, GType, i);
|
||||||
|
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
|
||||||
|
const FpIdEntry *entry;
|
||||||
|
|
||||||
|
if (cls->type != FP_DEVICE_TYPE_USB) {
|
||||||
|
g_type_class_unref (cls);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (entry = cls->id_table; entry->vid; entry++)
|
||||||
|
{
|
||||||
char *key;
|
char *key;
|
||||||
|
|
||||||
key = g_strdup_printf ("%04x:%04x", driver->id_table[i].vendor, driver->id_table[i].product);
|
key = g_strdup_printf ("%04x:%04x", entry->vid, entry->pid);
|
||||||
|
|
||||||
if (g_hash_table_lookup (printed, key) != NULL) {
|
if (g_hash_table_lookup (printed, key) != NULL) {
|
||||||
g_free (key);
|
g_free (key);
|
||||||
|
@ -43,7 +60,10 @@ static GList *insert_driver (GList *list,
|
||||||
|
|
||||||
g_hash_table_insert (printed, key, GINT_TO_POINTER (1));
|
g_hash_table_insert (printed, key, GINT_TO_POINTER (1));
|
||||||
|
|
||||||
list = g_list_prepend (list, g_strdup_printf ("%s | %s\n", key, driver->full_name));
|
list = g_list_prepend (list, g_strdup_printf ("%s | %s\n", key, cls->full_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_type_class_unref (cls);
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
|
@ -51,14 +71,10 @@ static GList *insert_driver (GList *list,
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct fp_driver **driver_list;
|
|
||||||
guint i;
|
|
||||||
GList *list, *l;
|
GList *list, *l;
|
||||||
|
|
||||||
setlocale (LC_ALL, "");
|
setlocale (LC_ALL, "");
|
||||||
|
|
||||||
driver_list = fprint_get_drivers ();
|
|
||||||
|
|
||||||
printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||||
|
|
||||||
g_print ("%% lifprint — Supported Devices\n");
|
g_print ("%% lifprint — Supported Devices\n");
|
||||||
|
@ -76,8 +92,7 @@ int main (int argc, char **argv)
|
||||||
g_print ("------------ | ------------\n");
|
g_print ("------------ | ------------\n");
|
||||||
|
|
||||||
list = NULL;
|
list = NULL;
|
||||||
for (i = 0; driver_list[i] != NULL; i++)
|
list = insert_drivers (list);
|
||||||
list = insert_driver (list, driver_list[i]);
|
|
||||||
|
|
||||||
list = g_list_sort (list, (GCompareFunc) g_strcmp0);
|
list = g_list_sort (list, (GCompareFunc) g_strcmp0);
|
||||||
for (l = list; l != NULL; l = l->next)
|
for (l = list; l != NULL; l = l->next)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* Copyright (C) 2009 Red Hat <mjg@redhat.com>
|
* Copyright (C) 2009 Red Hat <mjg@redhat.com>
|
||||||
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
|
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
|
||||||
* Copyright (C) 2008 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net>
|
* Copyright (C) 2008 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net>
|
||||||
|
* Coypright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -19,54 +20,55 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
#include "fpi-context.h"
|
||||||
|
#include "fpi-device.h"
|
||||||
|
|
||||||
static const struct usb_id whitelist_id_table[] = {
|
static const FpIdEntry whitelist_id_table[] = {
|
||||||
/* Unsupported (for now) Validity Sensors finger print readers */
|
/* Unsupported (for now) Validity Sensors finger print readers */
|
||||||
{ .vendor = 0x138a, .product = 0x0090 }, /* Found on e.g. Lenovo T460s */
|
{ .vid = 0x138a, .pid = 0x0090 }, /* Found on e.g. Lenovo T460s */
|
||||||
{ .vendor = 0x138a, .product = 0x0091 },
|
{ .vid = 0x138a, .pid = 0x0091 },
|
||||||
{ .vendor = 0x138a, .product = 0x0094 },
|
{ .vid = 0x138a, .pid = 0x0094 },
|
||||||
{ .vendor = 0x138a, .product = 0x0097 }, /* Found on e.g. Lenovo T470s */
|
{ .vid = 0x138a, .pid = 0x0097 }, /* Found on e.g. Lenovo T470s */
|
||||||
{ 0, 0, 0, },
|
{ .vid = 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct usb_id blacklist_id_table[] = {
|
static const FpIdEntry blacklist_id_table[] = {
|
||||||
{ .vendor = 0x0483, .product = 0x2016 },
|
{ .vid = 0x0483, .pid = 0x2016 },
|
||||||
/* https://bugs.freedesktop.org/show_bug.cgi?id=66659 */
|
/* https://bugs.freedesktop.org/show_bug.cgi?id=66659 */
|
||||||
{ .vendor = 0x045e, .product = 0x00bb },
|
{ .vid = 0x045e, .pid = 0x00bb },
|
||||||
{ 0, 0, 0 },
|
{ .vid = 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_driver whitelist = {
|
static const FpDeviceClass whitelist = {
|
||||||
|
.type = FP_DEVICE_TYPE_USB,
|
||||||
.id_table = whitelist_id_table,
|
.id_table = whitelist_id_table,
|
||||||
.full_name = "Hardcoded whitelist"
|
.full_name = "Hardcoded whitelist"
|
||||||
};
|
};
|
||||||
|
|
||||||
GHashTable *printed = NULL;
|
GHashTable *printed = NULL;
|
||||||
|
|
||||||
static void print_driver (struct fp_driver *driver)
|
static void print_driver (const FpDeviceClass *cls)
|
||||||
{
|
{
|
||||||
int i, j, blacklist, num_printed;
|
const FpIdEntry *entry;
|
||||||
|
gint num_printed = 0;
|
||||||
|
|
||||||
num_printed = 0;
|
if (cls->type != FP_DEVICE_TYPE_USB)
|
||||||
|
return;
|
||||||
|
|
||||||
for (i = 0; driver->id_table[i].vendor != 0; i++) {
|
for (entry = cls->id_table; entry->vid != 0; entry++) {
|
||||||
|
const FpIdEntry *bl_entry;
|
||||||
char *key;
|
char *key;
|
||||||
|
|
||||||
blacklist = 0;
|
for (bl_entry = blacklist_id_table; bl_entry->vid != 0; bl_entry++) {
|
||||||
for (j = 0; blacklist_id_table[j].vendor != 0; j++) {
|
if (entry->vid == bl_entry->vid && entry->pid == bl_entry->pid) {
|
||||||
if (driver->id_table[i].vendor == blacklist_id_table[j].vendor &&
|
|
||||||
driver->id_table[i].product == blacklist_id_table[j].product) {
|
|
||||||
blacklist = 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (blacklist)
|
if (bl_entry->vid != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
key = g_strdup_printf ("%04x:%04x", driver->id_table[i].vendor, driver->id_table[i].product);
|
key = g_strdup_printf ("%04x:%04x", entry->vid, entry->pid);
|
||||||
|
|
||||||
if (g_hash_table_lookup (printed, key) != NULL) {
|
if (g_hash_table_lookup (printed, key) != NULL) {
|
||||||
g_free (key);
|
g_free (key);
|
||||||
|
@ -76,28 +78,42 @@ static void print_driver (struct fp_driver *driver)
|
||||||
g_hash_table_insert (printed, key, GINT_TO_POINTER (1));
|
g_hash_table_insert (printed, key, GINT_TO_POINTER (1));
|
||||||
|
|
||||||
if (num_printed == 0)
|
if (num_printed == 0)
|
||||||
printf ("# %s\n", driver->full_name);
|
g_print ("# %s\n", cls->full_name);
|
||||||
|
|
||||||
printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n", driver->id_table[i].vendor, driver->id_table[i].product);
|
g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n",
|
||||||
printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n", driver->id_table[i].vendor, driver->id_table[i].product, driver->full_name);
|
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++;
|
num_printed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_printed > 0)
|
if (num_printed > 0)
|
||||||
printf ("\n");
|
g_print ("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct fp_driver **list;
|
g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof(GType));
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
list = fprint_get_drivers ();
|
g_print ("%p\n", drivers);
|
||||||
|
g_print ("%p\n", fpi_get_driver_types);
|
||||||
|
fpi_get_driver_types (drivers);
|
||||||
|
|
||||||
printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||||
|
|
||||||
for (i = 0; list[i] != NULL; i++) {
|
for (i = 0; i < drivers->len; i++) {
|
||||||
print_driver (list[i]);
|
GType driver = g_array_index (drivers, GType, i);
|
||||||
|
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
|
||||||
|
|
||||||
|
if (cls->type != FP_DEVICE_TYPE_USB) {
|
||||||
|
g_type_class_unref (cls);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_driver (cls);
|
||||||
|
|
||||||
|
g_type_class_unref (cls);
|
||||||
}
|
}
|
||||||
|
|
||||||
print_driver (&whitelist);
|
print_driver (&whitelist);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Main definitions for libfprint
|
* Main definitions for libfprint
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -17,411 +17,9 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __FPRINT_H__
|
#pragma once
|
||||||
#define __FPRINT_H__
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include "fp-context.h"
|
||||||
extern "C" {
|
#include "fp-device.h"
|
||||||
#endif
|
#include "fp-image.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LIBFPRINT_DEPRECATED:
|
|
||||||
*
|
|
||||||
* Expands to the GNU C deprecated attribute if the compiler is `gcc`. When
|
|
||||||
* called with the `-Wdeprecated-declarations` option, `gcc` will generate warnings
|
|
||||||
* when deprecated interfaces are used.
|
|
||||||
*/
|
|
||||||
#define LIBFPRINT_DEPRECATED __attribute__((__deprecated__))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_dev:
|
|
||||||
*
|
|
||||||
* #fp_dscv_dev is an opaque structure type. You must access it using the
|
|
||||||
* functions in this section.
|
|
||||||
*/
|
|
||||||
struct fp_dscv_dev;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev:
|
|
||||||
*
|
|
||||||
* #fp_dev is an opaque structure type. You must access it using the
|
|
||||||
* functions in this section.
|
|
||||||
*/
|
|
||||||
struct fp_dev;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_driver:
|
|
||||||
*
|
|
||||||
* #fp_driver is an opaque structure type. You must access it using the
|
|
||||||
* functions in this section.
|
|
||||||
*/
|
|
||||||
struct fp_driver;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data:
|
|
||||||
*
|
|
||||||
* #fp_print_data is an opaque structure type. You must access it using the
|
|
||||||
* functions in this section.
|
|
||||||
*/
|
|
||||||
struct fp_print_data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_img:
|
|
||||||
*
|
|
||||||
* #fp_img is an opaque structure type. You must access it using the
|
|
||||||
* functions in this section.
|
|
||||||
*/
|
|
||||||
struct fp_img;
|
|
||||||
|
|
||||||
/* misc/general stuff */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_finger:
|
|
||||||
* @LEFT_THUMB: Left thumb
|
|
||||||
* @LEFT_INDEX: Left index finger
|
|
||||||
* @LEFT_MIDDLE: Left middle finger
|
|
||||||
* @LEFT_RING: Left ring finger
|
|
||||||
* @LEFT_LITTLE: Left little finger
|
|
||||||
* @RIGHT_THUMB: Right thumb
|
|
||||||
* @RIGHT_INDEX: Right index finger
|
|
||||||
* @RIGHT_MIDDLE: Right middle finger
|
|
||||||
* @RIGHT_RING: Right ring finger
|
|
||||||
* @RIGHT_LITTLE: Right little finger
|
|
||||||
*
|
|
||||||
* Numeric codes used to refer to fingers (and thumbs) of a human. These are
|
|
||||||
* purposely not available as strings, to avoid getting the library tangled up
|
|
||||||
* in localization efforts.
|
|
||||||
*/
|
|
||||||
enum fp_finger {
|
|
||||||
LEFT_THUMB = 1,
|
|
||||||
LEFT_INDEX,
|
|
||||||
LEFT_MIDDLE,
|
|
||||||
LEFT_RING,
|
|
||||||
LEFT_LITTLE,
|
|
||||||
RIGHT_THUMB,
|
|
||||||
RIGHT_INDEX,
|
|
||||||
RIGHT_MIDDLE,
|
|
||||||
RIGHT_RING,
|
|
||||||
RIGHT_LITTLE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_scan_type:
|
|
||||||
* @FP_SCAN_TYPE_PRESS: the reader has a surface area that covers the whole finger
|
|
||||||
* @FP_SCAN_TYPE_SWIPE: the reader requires swiping the finger on a smaller area
|
|
||||||
*
|
|
||||||
* Numeric codes used to refer to the scan type of the device. Devices require
|
|
||||||
* either swiping or pressing the finger on the device. This is useful for
|
|
||||||
* front-ends.
|
|
||||||
*/
|
|
||||||
enum fp_scan_type {
|
|
||||||
FP_SCAN_TYPE_PRESS = 0,
|
|
||||||
FP_SCAN_TYPE_SWIPE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Drivers */
|
|
||||||
const char *fp_driver_get_name(struct fp_driver *drv);
|
|
||||||
const char *fp_driver_get_full_name(struct fp_driver *drv);
|
|
||||||
uint16_t fp_driver_get_driver_id(struct fp_driver *drv);
|
|
||||||
enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv);
|
|
||||||
int fp_driver_supports_imaging(struct fp_driver *drv);
|
|
||||||
|
|
||||||
/* Device discovery */
|
|
||||||
struct fp_dscv_dev **fp_discover_devs(void);
|
|
||||||
void fp_dscv_devs_free(struct fp_dscv_dev **devs);
|
|
||||||
struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev);
|
|
||||||
uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev);
|
|
||||||
uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev);
|
|
||||||
int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev,
|
|
||||||
struct fp_print_data *print);
|
|
||||||
|
|
||||||
/* Device handling */
|
|
||||||
struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev);
|
|
||||||
void fp_dev_close(struct fp_dev *dev);
|
|
||||||
struct fp_driver *fp_dev_get_driver(struct fp_dev *dev);
|
|
||||||
int fp_dev_get_nr_enroll_stages(struct fp_dev *dev);
|
|
||||||
uint32_t fp_dev_get_devtype(struct fp_dev *dev);
|
|
||||||
int fp_dev_supports_print_data(struct fp_dev *dev, struct fp_print_data *data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_capture_result:
|
|
||||||
* @FP_CAPTURE_COMPLETE: Capture completed successfully, the capture data has been returned to the caller.
|
|
||||||
* @FP_CAPTURE_FAIL: Capture failed
|
|
||||||
*
|
|
||||||
* Whether a capture failed or completed.
|
|
||||||
*/
|
|
||||||
enum fp_capture_result {
|
|
||||||
FP_CAPTURE_COMPLETE = 0,
|
|
||||||
FP_CAPTURE_FAIL,
|
|
||||||
};
|
|
||||||
|
|
||||||
int fp_dev_supports_imaging(struct fp_dev *dev);
|
|
||||||
int fp_dev_img_capture(struct fp_dev *dev, int unconditional,
|
|
||||||
struct fp_img **img);
|
|
||||||
int fp_dev_get_img_width(struct fp_dev *dev);
|
|
||||||
int fp_dev_get_img_height(struct fp_dev *dev);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_enroll_result:
|
|
||||||
* @FP_ENROLL_COMPLETE: Enrollment completed successfully, the enrollment data has been
|
|
||||||
* returned to the caller.
|
|
||||||
* @FP_ENROLL_FAIL: Enrollment failed due to incomprehensible data; this may occur when
|
|
||||||
* the user scans a different finger on each enroll stage.
|
|
||||||
* @FP_ENROLL_PASS: Enroll stage passed; more stages are need to complete the process.
|
|
||||||
* @FP_ENROLL_RETRY: The enrollment scan did not succeed due to poor scan quality or
|
|
||||||
* other general user scanning problem.
|
|
||||||
* @FP_ENROLL_RETRY_TOO_SHORT: The enrollment scan did not succeed because the finger swipe was
|
|
||||||
* too short.
|
|
||||||
* @FP_ENROLL_RETRY_CENTER_FINGER: The enrollment scan did not succeed because the finger was not
|
|
||||||
* centered on the scanner.
|
|
||||||
* @FP_ENROLL_RETRY_REMOVE_FINGER: The verification scan did not succeed due to quality or pressure
|
|
||||||
* problems; the user should remove their finger from the scanner before
|
|
||||||
* retrying.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Enrollment result codes returned from fp_enroll_finger().
|
|
||||||
* Result codes with RETRY in the name suggest that the scan failed due to
|
|
||||||
* user error. Applications will generally want to inform the user of the
|
|
||||||
* problem and then retry the enrollment stage. For more info on the semantics
|
|
||||||
* of interpreting these result codes and tracking enrollment process, see
|
|
||||||
* [Enrolling](libfprint-Devices-operations.html#enrolling)
|
|
||||||
*/
|
|
||||||
enum fp_enroll_result {
|
|
||||||
FP_ENROLL_COMPLETE = 1,
|
|
||||||
FP_ENROLL_FAIL,
|
|
||||||
FP_ENROLL_PASS,
|
|
||||||
FP_ENROLL_RETRY = 100,
|
|
||||||
FP_ENROLL_RETRY_TOO_SHORT,
|
|
||||||
FP_ENROLL_RETRY_CENTER_FINGER,
|
|
||||||
FP_ENROLL_RETRY_REMOVE_FINGER,
|
|
||||||
};
|
|
||||||
|
|
||||||
int fp_enroll_finger_img(struct fp_dev *dev, struct fp_print_data **print_data,
|
|
||||||
struct fp_img **img);
|
|
||||||
int fp_enroll_finger(struct fp_dev *dev,
|
|
||||||
struct fp_print_data **print_data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_verify_result:
|
|
||||||
* @FP_VERIFY_NO_MATCH: The scan completed successfully, but the newly scanned fingerprint
|
|
||||||
* does not match the fingerprint being verified against.
|
|
||||||
* In the case of identification, this return code indicates that the
|
|
||||||
* scanned finger could not be found in the print gallery.
|
|
||||||
* @FP_VERIFY_MATCH: The scan completed successfully and the newly scanned fingerprint does
|
|
||||||
* match the fingerprint being verified, or in the case of identification,
|
|
||||||
* the scanned fingerprint was found in the print gallery.
|
|
||||||
* @FP_VERIFY_RETRY: The scan did not succeed due to poor scan quality or other general
|
|
||||||
* user scanning problem.
|
|
||||||
* @FP_VERIFY_RETRY_TOO_SHORT: The scan did not succeed because the finger swipe was too short.
|
|
||||||
* @FP_VERIFY_RETRY_CENTER_FINGER: The scan did not succeed because the finger was not centered on the
|
|
||||||
* scanner.
|
|
||||||
* @FP_VERIFY_RETRY_REMOVE_FINGER: The scan did not succeed due to quality or pressure problems; the user
|
|
||||||
* should remove their finger from the scanner before retrying.
|
|
||||||
*
|
|
||||||
* Verification result codes returned from fp_verify_finger(). Return codes
|
|
||||||
* are also shared with fp_identify_finger().
|
|
||||||
* Result codes with RETRY in the name suggest that the scan failed due to
|
|
||||||
* user error. Applications will generally want to inform the user of the
|
|
||||||
* problem and then retry the verify operation.
|
|
||||||
*/
|
|
||||||
enum fp_verify_result {
|
|
||||||
FP_VERIFY_NO_MATCH = 0,
|
|
||||||
FP_VERIFY_MATCH = 1,
|
|
||||||
FP_VERIFY_RETRY = FP_ENROLL_RETRY,
|
|
||||||
FP_VERIFY_RETRY_TOO_SHORT = FP_ENROLL_RETRY_TOO_SHORT,
|
|
||||||
FP_VERIFY_RETRY_CENTER_FINGER = FP_ENROLL_RETRY_CENTER_FINGER,
|
|
||||||
FP_VERIFY_RETRY_REMOVE_FINGER = FP_ENROLL_RETRY_REMOVE_FINGER,
|
|
||||||
};
|
|
||||||
|
|
||||||
int fp_verify_finger_img(struct fp_dev *dev,
|
|
||||||
struct fp_print_data *enrolled_print, struct fp_img **img);
|
|
||||||
int fp_verify_finger(struct fp_dev *dev,
|
|
||||||
struct fp_print_data *enrolled_print);
|
|
||||||
|
|
||||||
int fp_dev_supports_identification(struct fp_dev *dev);
|
|
||||||
int fp_identify_finger_img(struct fp_dev *dev,
|
|
||||||
struct fp_print_data **print_gallery, size_t *match_offset,
|
|
||||||
struct fp_img **img);
|
|
||||||
int fp_identify_finger(struct fp_dev *dev,
|
|
||||||
struct fp_print_data **print_gallery, size_t *match_offset);
|
|
||||||
|
|
||||||
/* Data handling */
|
|
||||||
void fp_print_data_free(struct fp_print_data *data);
|
|
||||||
size_t fp_print_data_get_data(struct fp_print_data *data, unsigned char **ret);
|
|
||||||
struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
|
|
||||||
size_t buflen);
|
|
||||||
uint16_t fp_print_data_get_driver_id(struct fp_print_data *data);
|
|
||||||
uint32_t fp_print_data_get_devtype(struct fp_print_data *data);
|
|
||||||
|
|
||||||
/* Image handling */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_minutia:
|
|
||||||
*
|
|
||||||
* #fp_minutia is an opaque structure type. You must access it using the
|
|
||||||
* functions in this section.
|
|
||||||
*/
|
|
||||||
struct fp_minutia;
|
|
||||||
|
|
||||||
int fp_img_get_height(struct fp_img *img);
|
|
||||||
int fp_img_get_width(struct fp_img *img);
|
|
||||||
unsigned char *fp_img_get_data(struct fp_img *img);
|
|
||||||
int fp_img_save_to_file(struct fp_img *img, char *path);
|
|
||||||
void fp_img_standardize(struct fp_img *img);
|
|
||||||
struct fp_img *fp_img_binarize(struct fp_img *img);
|
|
||||||
struct fp_minutia **fp_img_get_minutiae(struct fp_img *img, int *nr_minutiae);
|
|
||||||
int fp_minutia_get_coords(struct fp_minutia *minutia, int *coord_x, int *coord_y);
|
|
||||||
void fp_img_free(struct fp_img *img);
|
|
||||||
|
|
||||||
/* Polling and timing */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_pollfd:
|
|
||||||
* @fd: a file descriptor
|
|
||||||
* @events: Event flags to poll for from `<poll.h>`
|
|
||||||
*
|
|
||||||
* A structure representing a file descriptor and the @events to poll
|
|
||||||
* for, as returned by fp_get_pollfds().
|
|
||||||
*/
|
|
||||||
struct fp_pollfd {
|
|
||||||
int fd;
|
|
||||||
short int events;
|
|
||||||
};
|
|
||||||
|
|
||||||
int fp_handle_events_timeout(struct timeval *timeout);
|
|
||||||
int fp_handle_events(void);
|
|
||||||
ssize_t fp_get_pollfds(struct fp_pollfd **pollfds);
|
|
||||||
int fp_get_next_timeout(struct timeval *tv);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_pollfd_added_cb:
|
|
||||||
* @fd: the new file descriptor
|
|
||||||
* @events: events to monitor for, see `<poll.h>` for the possible values
|
|
||||||
*
|
|
||||||
* Type definition for a function that will be called when a new
|
|
||||||
* event source is added. The @events argument is a flag as defined in
|
|
||||||
* `<poll.h>` such as `POLLIN`, or `POLLOUT`. See fp_set_pollfd_notifiers().
|
|
||||||
*/
|
|
||||||
typedef void (*fp_pollfd_added_cb)(int fd, short int events);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_pollfd_removed_cb:
|
|
||||||
* @fd: the file descriptor to stop monitoring
|
|
||||||
*
|
|
||||||
* Type definition for a function that will be called when an
|
|
||||||
* event source is removed. See fp_set_pollfd_notifiers().
|
|
||||||
*/
|
|
||||||
typedef void (*fp_pollfd_removed_cb)(int fd);
|
|
||||||
void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb,
|
|
||||||
fp_pollfd_removed_cb removed_cb);
|
|
||||||
|
|
||||||
/* Library */
|
|
||||||
int fp_init(void);
|
|
||||||
void fp_exit(void);
|
|
||||||
|
|
||||||
/* Asynchronous I/O */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_operation_stop_cb:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @user_data: user data passed to the callback
|
|
||||||
*
|
|
||||||
* Type definition for a function that will be called when fp_async_dev_close(),
|
|
||||||
* fp_async_verify_stop(), fp_async_identify_stop() or fp_async_capture_stop()
|
|
||||||
* finishes.
|
|
||||||
*/
|
|
||||||
typedef void (*fp_operation_stop_cb)(struct fp_dev *dev, void *user_data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_img_operation_cb:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @result: an #fp_verify_result for fp_async_verify_start(), or an #fp_capture_result
|
|
||||||
* for fp_async_capture_start(), or a negative value on error
|
|
||||||
* @img: the captured #fp_img if capture or verification was successful
|
|
||||||
* @user_data: user data passed to the callback
|
|
||||||
*
|
|
||||||
* Type definition for a function that will be called when fp_async_verify_start()
|
|
||||||
* or fp_async_capture_start() finished.
|
|
||||||
*/
|
|
||||||
typedef void (*fp_img_operation_cb)(struct fp_dev *dev, int result,
|
|
||||||
struct fp_img *img, void *user_data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_open_cb:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @status: 0 on success, or a negative value on error
|
|
||||||
* @user_data: user data passed to the callback
|
|
||||||
*
|
|
||||||
* Type definition for a function that will be called when fp_async_dev_open
|
|
||||||
* finishes.
|
|
||||||
*/
|
|
||||||
typedef void (*fp_dev_open_cb)(struct fp_dev *dev, int status, void *user_data);
|
|
||||||
|
|
||||||
int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb callback,
|
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
void fp_async_dev_close(struct fp_dev *dev, fp_operation_stop_cb callback,
|
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_enroll_stage_cb:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @result: a #fp_enroll_result on success, or a negative value on failure
|
|
||||||
* @print: the enrollment data from the final stage
|
|
||||||
* @img: an #fp_img to free with fp_img_free()
|
|
||||||
* @user_data: user data passed to the callback
|
|
||||||
*
|
|
||||||
* Type definition for a function that will be called when
|
|
||||||
* fp_async_enroll_start() finishes. See fp_enroll_finger_img() for
|
|
||||||
* the expected behaviour of your program based on the @result.
|
|
||||||
*/
|
|
||||||
typedef void (*fp_enroll_stage_cb)(struct fp_dev *dev, int result,
|
|
||||||
struct fp_print_data *print, struct fp_img *img, void *user_data);
|
|
||||||
|
|
||||||
int fp_async_enroll_start(struct fp_dev *dev, fp_enroll_stage_cb callback,
|
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
int fp_async_enroll_stop(struct fp_dev *dev, fp_operation_stop_cb callback,
|
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
int fp_async_verify_start(struct fp_dev *dev, struct fp_print_data *data,
|
|
||||||
fp_img_operation_cb callback, void *user_data);
|
|
||||||
|
|
||||||
int fp_async_verify_stop(struct fp_dev *dev, fp_operation_stop_cb callback,
|
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_identify_cb:
|
|
||||||
* @dev: the struct #fp_dev device
|
|
||||||
* @result: a #fp_verify_result on success, or a negative value on error.
|
|
||||||
* @match_offset: the array index of the matched gallery print (if any was found).
|
|
||||||
* Only valid if %FP_VERIFY_MATCH was returned.
|
|
||||||
* @img: the scan image, it must be freed with fp_img_free() after use.
|
|
||||||
* @user_data: user data passed to the callback
|
|
||||||
*
|
|
||||||
* Type definition for a function that will be called when fp_async_identify_start()
|
|
||||||
* finishes.
|
|
||||||
*/
|
|
||||||
typedef void (*fp_identify_cb)(struct fp_dev *dev, int result,
|
|
||||||
size_t match_offset, struct fp_img *img, void *user_data);
|
|
||||||
int fp_async_identify_start(struct fp_dev *dev, struct fp_print_data **gallery,
|
|
||||||
fp_identify_cb callback, void *user_data);
|
|
||||||
|
|
||||||
int fp_async_identify_stop(struct fp_dev *dev, fp_operation_stop_cb callback,
|
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
int fp_async_capture_start(struct fp_dev *dev, int unconditional, fp_img_operation_cb callback, void *user_data);
|
|
||||||
|
|
||||||
int fp_async_capture_stop(struct fp_dev *dev, fp_operation_stop_cb callback, void *user_data);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
LIBFPRINT_2.0.0 {
|
LIBFPRINT_2.0.0 {
|
||||||
global:
|
global:
|
||||||
fp_*;
|
fp_*;
|
||||||
|
|
||||||
|
/* Needs to be public for the listing commands. */
|
||||||
|
fpi_get_driver_types;
|
||||||
local:
|
local:
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,15 +1,27 @@
|
||||||
libfprint_sources = [
|
libfprint_sources = [
|
||||||
'fpi-async.c',
|
'fp-context.c',
|
||||||
|
'fp-device.c',
|
||||||
|
'fp-image.c',
|
||||||
|
'fp-print.c',
|
||||||
|
'fp-image-device.c',
|
||||||
'fpi-assembling.c',
|
'fpi-assembling.c',
|
||||||
'fpi-core.c',
|
|
||||||
'fpi-data.c',
|
|
||||||
'fpi-dev.c',
|
|
||||||
'fpi-dev-img.c',
|
|
||||||
'fpi-img.c',
|
|
||||||
'fpi-ssm.c',
|
'fpi-ssm.c',
|
||||||
'fpi-sync.c',
|
'fpi-usb-transfer.c',
|
||||||
'fpi-poll.c',
|
]
|
||||||
'fpi-usb.c',
|
|
||||||
|
libfprint_public_headers = [
|
||||||
|
'fp-context.h',
|
||||||
|
'fp-device.h',
|
||||||
|
'fp-image.h',
|
||||||
|
'fp-print.h',
|
||||||
|
]
|
||||||
|
|
||||||
|
libfprint_private_headers = [
|
||||||
|
'fpi-assembling.h',
|
||||||
|
'fpi-device.h',
|
||||||
|
'fpi-image.h',
|
||||||
|
'fpi-image-device.h',
|
||||||
|
'fpi-print.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
nbis_sources = [
|
nbis_sources = [
|
||||||
|
@ -134,29 +146,32 @@ if aes3k
|
||||||
endif
|
endif
|
||||||
|
|
||||||
other_sources = []
|
other_sources = []
|
||||||
if imaging_dep.found()
|
|
||||||
other_sources += [ 'fpi-img-pixman.c' ]
|
|
||||||
endif
|
|
||||||
|
|
||||||
libfprint_sources += configure_file(input: 'empty_file',
|
fp_enums = gnome.mkenums_simple('fp-enums',
|
||||||
output: 'drivers_definitions.h',
|
sources: libfprint_public_headers,
|
||||||
|
install_header : true)
|
||||||
|
fp_enums_h = fp_enums[1]
|
||||||
|
|
||||||
|
fpi_enums = gnome.mkenums_simple('fpi-enums',
|
||||||
|
sources: libfprint_private_headers,
|
||||||
|
install_header : true)
|
||||||
|
fpi_enums_h = fpi_enums[1]
|
||||||
|
|
||||||
|
drivers_sources += configure_file(input: 'empty_file',
|
||||||
|
output: 'fp-drivers.c',
|
||||||
capture: true,
|
capture: true,
|
||||||
command: [
|
command: [
|
||||||
'echo',
|
'echo',
|
||||||
drivers_struct_list
|
drivers_type_list + '\n\n' + drivers_type_func
|
||||||
])
|
])
|
||||||
|
|
||||||
libfprint_sources += configure_file(input: 'empty_file',
|
mapfile = 'libfprint.ver'
|
||||||
output: 'drivers_arrays.h',
|
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
|
||||||
capture: true,
|
|
||||||
command: [
|
|
||||||
'echo',
|
|
||||||
drivers_primitive_array + '\n\n' + drivers_img_array
|
|
||||||
])
|
|
||||||
|
|
||||||
deps = [ mathlib_dep, glib_dep, gusb_dep, nss_dep, imaging_dep ]
|
deps = [ mathlib_dep, glib_dep, gusb_dep, nss_dep, imaging_dep, gio_dep ]
|
||||||
libfprint = library('fprint',
|
libfprint = library('fprint',
|
||||||
libfprint_sources + drivers_sources + nbis_sources + other_sources,
|
libfprint_sources + fp_enums + fpi_enums +
|
||||||
|
drivers_sources + nbis_sources + other_sources,
|
||||||
soversion: soversion,
|
soversion: soversion,
|
||||||
version: libversion,
|
version: libversion,
|
||||||
c_args: common_cflags + drivers_cflags,
|
c_args: common_cflags + drivers_cflags,
|
||||||
|
@ -164,14 +179,17 @@ libfprint = library('fprint',
|
||||||
root_inc,
|
root_inc,
|
||||||
include_directories('nbis/include'),
|
include_directories('nbis/include'),
|
||||||
],
|
],
|
||||||
|
link_args : vflag,
|
||||||
|
link_depends : mapfile,
|
||||||
dependencies: deps,
|
dependencies: deps,
|
||||||
install: true)
|
install: true)
|
||||||
|
|
||||||
libfprint_dep = declare_dependency(link_with: libfprint,
|
libfprint_dep = declare_dependency(link_with: libfprint,
|
||||||
|
sources: [ fp_enums_h ],
|
||||||
include_directories: root_inc,
|
include_directories: root_inc,
|
||||||
dependencies: glib_dep)
|
dependencies: [glib_dep, gusb_dep, gio_dep])
|
||||||
|
|
||||||
install_headers(['fprint.h'], subdir: 'libfprint')
|
install_headers(['fprint.h'] + libfprint_public_headers, subdir: 'libfprint')
|
||||||
|
|
||||||
udev_rules = executable('fprint-list-udev-rules',
|
udev_rules = executable('fprint-list-udev-rules',
|
||||||
'fprint-list-udev-rules.c',
|
'fprint-list-udev-rules.c',
|
||||||
|
@ -197,3 +215,35 @@ supported_devices = executable('fprint-list-supported-devices',
|
||||||
],
|
],
|
||||||
dependencies: [ deps, libfprint_dep ],
|
dependencies: [ deps, libfprint_dep ],
|
||||||
install: false)
|
install: false)
|
||||||
|
|
||||||
|
|
||||||
|
if get_option('introspection')
|
||||||
|
# We do *not* include the private header here
|
||||||
|
libfprint_girtarget = gnome.generate_gir(libfprint,
|
||||||
|
sources : fp_enums + [
|
||||||
|
libfprint_public_headers,
|
||||||
|
libfprint_sources,
|
||||||
|
],
|
||||||
|
nsversion : '2.0',
|
||||||
|
namespace : 'FPrint',
|
||||||
|
symbol_prefix : 'fp_',
|
||||||
|
identifier_prefix : 'Fp',
|
||||||
|
export_packages : 'fprint',
|
||||||
|
extra_args : [
|
||||||
|
'--c-include=fprint.h',
|
||||||
|
],
|
||||||
|
link_with : libfprint,
|
||||||
|
dependencies : [
|
||||||
|
gio_dep,
|
||||||
|
gusb_dep,
|
||||||
|
],
|
||||||
|
includes : [
|
||||||
|
'Gio-2.0',
|
||||||
|
'GObject-2.0',
|
||||||
|
'GUsb-1.0',
|
||||||
|
],
|
||||||
|
install : true
|
||||||
|
)
|
||||||
|
libfprint_gir = libfprint_girtarget[0]
|
||||||
|
libfprint_typelib = libfprint_girtarget[1]
|
||||||
|
endif
|
||||||
|
|
28
meson.build
28
meson.build
|
@ -8,6 +8,8 @@ project('libfprint', [ 'c', 'cpp' ],
|
||||||
],
|
],
|
||||||
meson_version: '>= 0.45.0')
|
meson_version: '>= 0.45.0')
|
||||||
|
|
||||||
|
gnome = import('gnome')
|
||||||
|
|
||||||
add_project_arguments([ '-D_GNU_SOURCE' ], language: 'c')
|
add_project_arguments([ '-D_GNU_SOURCE' ], language: 'c')
|
||||||
add_project_arguments([ '-DG_LOG_DOMAIN="libfprint"' ], language: 'c')
|
add_project_arguments([ '-DG_LOG_DOMAIN="libfprint"' ], language: 'c')
|
||||||
|
|
||||||
|
@ -19,7 +21,6 @@ host_system = host_machine.system()
|
||||||
|
|
||||||
common_cflags = cc.get_supported_arguments([
|
common_cflags = cc.get_supported_arguments([
|
||||||
'-fgnu89-inline',
|
'-fgnu89-inline',
|
||||||
'-fvisibility=hidden',
|
|
||||||
'-std=gnu99',
|
'-std=gnu99',
|
||||||
'-Wall',
|
'-Wall',
|
||||||
'-Wundef',
|
'-Wundef',
|
||||||
|
@ -42,6 +43,7 @@ libversion = '@0@.@1@.@2@'.format(soversion, current, revision)
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
glib_dep = dependency('glib-2.0', version: '>= 2.50')
|
glib_dep = dependency('glib-2.0', version: '>= 2.50')
|
||||||
|
gio_dep = dependency('gio-unix-2.0', version: '>= 2.44.0')
|
||||||
gusb_dep = dependency('gusb', version: '>= 0.3.0')
|
gusb_dep = dependency('gusb', version: '>= 0.3.0')
|
||||||
mathlib_dep = cc.find_library('m', required: false)
|
mathlib_dep = cc.find_library('m', required: false)
|
||||||
|
|
||||||
|
@ -67,6 +69,7 @@ endif
|
||||||
|
|
||||||
nss_dep = dependency('', required: false)
|
nss_dep = dependency('', required: false)
|
||||||
imaging_dep = dependency('', required: false)
|
imaging_dep = dependency('', required: false)
|
||||||
|
libfprint_conf.set10('HAVE_PIXMAN', false)
|
||||||
foreach driver: drivers
|
foreach driver: drivers
|
||||||
if driver == 'uru4000'
|
if driver == 'uru4000'
|
||||||
nss_dep = dependency('nss', required: false)
|
nss_dep = dependency('nss', required: false)
|
||||||
|
@ -79,27 +82,23 @@ foreach driver: drivers
|
||||||
if not imaging_dep.found()
|
if not imaging_dep.found()
|
||||||
error('pixman is required for imaging support')
|
error('pixman is required for imaging support')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
libfprint_conf.set10('HAVE_PIXMAN', true)
|
||||||
endif
|
endif
|
||||||
if not all_drivers.contains(driver)
|
if not all_drivers.contains(driver)
|
||||||
error('Invalid driver \'' + driver + '\'')
|
error('Invalid driver \'' + driver + '\'')
|
||||||
endif
|
endif
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
# Export the drivers' structures to the core code
|
# Export the drivers' types to the core code
|
||||||
drivers_struct_list = ''
|
drivers_type_list = '#include <glib-object.h>\n'
|
||||||
drivers_img_array = 'static struct fp_img_driver * const img_drivers[] = {\n'
|
drivers_type_func = 'void fpi_get_driver_types(GArray *drivers)\n{\n\tGType t;\n'
|
||||||
drivers_primitive_array = 'static struct fp_driver * const primitive_drivers[] = {\n'
|
|
||||||
foreach driver: drivers
|
foreach driver: drivers
|
||||||
if primitive_drivers.contains(driver)
|
drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);\n'
|
||||||
drivers_struct_list += 'extern struct fp_driver ' + driver + '_driver;\n'
|
drivers_type_func += ' t = fpi_device_' + driver + '_get_type(); g_array_append_val (drivers, t);\n'
|
||||||
drivers_primitive_array += ' &' + driver + '_driver,\n'
|
|
||||||
else
|
|
||||||
drivers_struct_list += 'extern struct fp_img_driver ' + driver + '_driver;\n'
|
|
||||||
drivers_img_array += ' &' + driver + '_driver,\n'
|
|
||||||
endif
|
|
||||||
endforeach
|
endforeach
|
||||||
drivers_img_array += '};'
|
drivers_type_list += ''
|
||||||
drivers_primitive_array += '};'
|
drivers_type_func += '};'
|
||||||
|
|
||||||
root_inc = include_directories('.')
|
root_inc = include_directories('.')
|
||||||
|
|
||||||
|
@ -129,7 +128,6 @@ if get_option('gtk-examples')
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
libfprint_conf.set('API_EXPORTED', '__attribute__((visibility("default")))')
|
|
||||||
configure_file(output: 'config.h', configuration: libfprint_conf)
|
configure_file(output: 'config.h', configuration: libfprint_conf)
|
||||||
|
|
||||||
subdir('libfprint')
|
subdir('libfprint')
|
||||||
|
|
|
@ -2,6 +2,10 @@ option('drivers',
|
||||||
description: 'Drivers to integrate, "default" selects the default set, "all" selects all drivers',
|
description: 'Drivers to integrate, "default" selects the default set, "all" selects all drivers',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
value: 'default')
|
value: 'default')
|
||||||
|
option('introspection',
|
||||||
|
description: 'Build GObject Introspection repository',
|
||||||
|
type: 'boolean',
|
||||||
|
value: true)
|
||||||
option('udev_rules',
|
option('udev_rules',
|
||||||
description: 'Whether to create a udev rules file',
|
description: 'Whether to create a udev rules file',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
|
|
Loading…
Reference in a new issue