From 5eba6067a3963927f0e69551d3c6480f0a447fb6 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 6 Aug 2019 12:39:38 +0200 Subject: [PATCH] elan: Port driver to new API This changes the cancellation logic a bit to ensure we always deactivate the device (equivalent to the AWAIT_OFF state in the driver). All commands except for the deactivation command should be cancelled when an operation is stopped, this is to ensure that the LED is turned off at the end of an operation. --- libfprint/drivers/elan.c | 649 +++++++++++++++++++-------------------- libfprint/drivers/elan.h | 133 ++++---- meson.build | 2 +- 3 files changed, 391 insertions(+), 393 deletions(-) diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c index e9dad43e..2c4e3be4 100644 --- a/libfprint/drivers/elan.c +++ b/libfprint/drivers/elan.c @@ -41,14 +41,6 @@ #include "drivers_api.h" #include "elan.h" -#define dbg_buf(buf, len) \ - if (len == 1) \ - fp_dbg("%02x", buf[0]); \ - else if (len == 2) \ - fp_dbg("%04x", buf[0] << 8 | buf[1]); \ - else if (len > 2) \ - fp_dbg("%04x... (%d bytes)", buf[0] << 8 | buf[1], len) - unsigned char elan_get_pixel(struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, unsigned int x, unsigned int y) @@ -63,7 +55,9 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = { .get_pixel = elan_get_pixel, }; -struct elan_dev { +struct _FpiDeviceElan { + FpImageDevice parent; + /* device config */ unsigned short dev_type; unsigned short fw_ver; @@ -73,12 +67,12 @@ struct elan_dev { /* commands */ const struct elan_cmd *cmd; int cmd_timeout; - fpi_usb_transfer *cur_transfer; /* end commands */ /* state */ - enum fp_imgdev_state dev_state; - enum fp_imgdev_state dev_state_next; + gboolean deactivating; + FpImageDeviceState dev_state; + FpImageDeviceState dev_state_next; unsigned char *last_read; unsigned char calib_atts_left; unsigned char calib_status; @@ -90,18 +84,19 @@ struct elan_dev { GSList *frames; /* end state */ }; +G_DECLARE_FINAL_TYPE(FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN, + FpImageDevice); +G_DEFINE_TYPE(FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE); int cmp_short(const void *a, const void *b) { return (int)(*(short *)a - *(short *)b); } -static void elan_dev_reset(struct elan_dev *elandev) +static void elan_dev_reset_state(FpiDeviceElan *elandev) { G_DEBUG_HERE(); - BUG_ON(elandev->cur_transfer); - elandev->cmd = NULL; elandev->cmd_timeout = ELAN_CMD_TIMEOUT; @@ -115,7 +110,7 @@ static void elan_dev_reset(struct elan_dev *elandev) elandev->num_frames = 0; } -static void elan_save_frame(struct elan_dev *elandev, unsigned short *frame) +static void elan_save_frame(FpiDeviceElan *self, unsigned short *frame) { G_DEBUG_HERE(); @@ -133,25 +128,25 @@ static void elan_save_frame(struct elan_dev *elandev, unsigned short *frame) * we also discard stripes of 'frame_margin' from bottom and top because * assembling works bad for tall frames */ - unsigned char frame_width = elandev->frame_width; - unsigned char frame_height = elandev->frame_height; - unsigned char raw_height = elandev->raw_frame_height; - unsigned char frame_margin = (raw_height - elandev->frame_height) / 2; + unsigned char frame_width = self->frame_width; + unsigned char frame_height = self->frame_height; + unsigned char raw_height = self->raw_frame_height; + unsigned char frame_margin = (raw_height - self->frame_height) / 2; int frame_idx, raw_idx; for (int y = 0; y < frame_height; y++) for (int x = 0; x < frame_width; x++) { - if (elandev->dev_type & ELAN_NOT_ROTATED) + if (self->dev_type & ELAN_NOT_ROTATED) raw_idx = x + (y + frame_margin) * frame_width; else raw_idx = frame_margin + y + x * raw_height; frame_idx = x + y * frame_width; frame[frame_idx] = - ((unsigned short *)elandev->last_read)[raw_idx]; + ((unsigned short *) self->last_read)[raw_idx]; } } -static void elan_save_background(struct elan_dev *elandev) +static void elan_save_background(FpiDeviceElan *elandev) { G_DEBUG_HERE(); @@ -197,7 +192,7 @@ static void elan_save_background(struct elan_dev *elandev) * \ * ======== 0 \___> ======== 0 */ -static int elan_save_img_frame(struct elan_dev *elandev) +static int elan_save_img_frame(FpiDeviceElan *elandev) { G_DEBUG_HERE(); @@ -290,157 +285,145 @@ static void elan_process_frame_thirds(unsigned short *raw_frame, *frames = g_slist_prepend(*frames, frame); } -static void elan_submit_image(struct fp_img_dev *dev) +static void elan_submit_image(FpImageDevice *dev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); int num_frames; GSList *raw_frames; GSList *frames = NULL; - struct fp_img *img; + FpImage *img; G_DEBUG_HERE(); - num_frames = elandev->num_frames - ELAN_SKIP_LAST_FRAMES; - raw_frames = g_slist_nth(elandev->frames, ELAN_SKIP_LAST_FRAMES); + num_frames = self->num_frames - ELAN_SKIP_LAST_FRAMES; + raw_frames = g_slist_nth(self->frames, ELAN_SKIP_LAST_FRAMES); - assembling_ctx.frame_width = elandev->frame_width; - assembling_ctx.frame_height = elandev->frame_height; - assembling_ctx.image_width = elandev->frame_width * 3 / 2; - g_slist_foreach(raw_frames, (GFunc) elandev->process_frame, &frames); + assembling_ctx.frame_width = self->frame_width; + assembling_ctx.frame_height = self->frame_height; + assembling_ctx.image_width = self->frame_width * 3 / 2; + g_slist_foreach(raw_frames, (GFunc) self->process_frame, &frames); fpi_do_movement_estimation(&assembling_ctx, frames, num_frames); img = fpi_assemble_frames(&assembling_ctx, frames, num_frames); - img->flags |= FP_IMG_PARTIAL; - fpi_imgdev_image_captured(dev, img); + fpi_image_device_image_captured(dev, img); } -static void elan_cmd_done(fpi_ssm *ssm) +static void elan_cmd_done(FpiSsm *ssm) { G_DEBUG_HERE(); fpi_ssm_next_state(ssm); } -static void elan_cmd_cb(struct libusb_transfer *transfer, - struct fp_dev *_dev, - fpi_ssm *ssm, - void *user_data) +static void elan_cmd_cb(FpiUsbTransfer *transfer, FpDevice *dev, + gpointer user_data, GError *error) { - struct fp_img_dev *dev; - struct elan_dev *elandev; + FpiSsm *ssm = transfer->ssm; + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); G_DEBUG_HERE(); - if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { - fp_dbg("transfer cancelled"); + if (error) { + /* XXX: In the cancellation case we used to not + * mark the SSM as failed?! */ + fpi_ssm_mark_failed (transfer->ssm, error); return; } - dev = FP_IMG_DEV(_dev); - elandev = FP_INSTANCE_DATA(_dev); - elandev->cur_transfer = NULL; - - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - if (transfer->length != transfer->actual_length) { - fp_dbg("transfer length error: expected %d, got %d", - transfer->length, transfer->actual_length); - elan_dev_reset(elandev); - fpi_ssm_mark_failed(ssm, -EPROTO); - } else if (transfer->endpoint & LIBUSB_ENDPOINT_IN) { - /* just finished receiving */ - elandev->last_read = g_memdup(transfer->buffer, transfer->actual_length); - dbg_buf(transfer->buffer, transfer->actual_length); - elan_cmd_done(ssm); - } else { - /* just finished sending */ - G_DEBUG_HERE(); - elan_cmd_read(ssm, dev); - } - break; - case LIBUSB_TRANSFER_TIMED_OUT: - fp_dbg("transfer timed out"); - fpi_ssm_mark_failed(ssm, -ETIMEDOUT); - break; - default: - fp_dbg("transfer failed: %d", transfer->status); - elan_dev_reset(elandev); - fpi_ssm_mark_failed(ssm, -EIO); + /* XXX: We used to reset the device in error cases! */ + if (transfer->endpoint & FPI_USB_ENDPOINT_IN) { + /* just finished receiving */ + self->last_read = g_memdup(transfer->buffer, transfer->actual_length); + elan_cmd_done(ssm); + } else { + /* just finished sending */ + G_DEBUG_HERE(); + elan_cmd_read(ssm, dev); } } -static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev) +static void elan_cmd_read(FpiSsm *ssm, FpDevice *dev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); - int response_len = elandev->cmd->response_len; - unsigned char *buffer; + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); + FpiUsbTransfer *transfer; + GCancellable *cancellable = NULL; + int response_len = self->cmd->response_len; G_DEBUG_HERE(); - if (elandev->cmd->response_len == ELAN_CMD_SKIP_READ) { + if (self->cmd->response_len == ELAN_CMD_SKIP_READ) { fp_dbg("skipping read, not expecting anything"); elan_cmd_done(ssm); return; } - if (elandev->dev_type == ELAN_0C42) { + if (self->dev_type == ELAN_0C42) { /* ELAN_0C42 sends an extra byte in one byte responses */ - if (elandev->cmd->response_len == 1) + if (self->cmd->response_len == 1) response_len = 2; } - if (elandev->cmd->cmd == get_image_cmd.cmd) + if (self->cmd->cmd == get_image_cmd.cmd) /* raw data has 2-byte "pixels" and the frame is vertical */ response_len = - elandev->raw_frame_height * elandev->frame_width * 2; + self->raw_frame_height * self->frame_width * 2; - g_clear_pointer(&elandev->last_read, g_free); - buffer = g_malloc(response_len); + g_clear_pointer(&self->last_read, g_free); - elandev->cur_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), - ssm, - elandev->cmd->response_in, - buffer, - response_len, - elan_cmd_cb, - NULL, - elandev->cmd_timeout); - int r = fpi_usb_submit_transfer(elandev->cur_transfer); - if (r < 0) - fpi_ssm_mark_failed(ssm, r); + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + + fpi_usb_transfer_fill_bulk (transfer, + self->cmd->response_in, + response_len); + + if (!self->cmd->never_cancel) + cancellable = fpi_device_get_cancellable (dev); + + fpi_usb_transfer_submit (transfer, self->cmd_timeout, cancellable, elan_cmd_cb, NULL); + fpi_usb_transfer_unref (transfer); } static void -elan_run_cmd(fpi_ssm *ssm, - struct fp_img_dev *dev, +elan_run_cmd(FpiSsm *ssm, + FpDevice *dev, const struct elan_cmd *cmd, int cmd_timeout) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); + FpiUsbTransfer *transfer; + GCancellable *cancellable = NULL; - dbg_buf(cmd->cmd, 2); - - elandev->cmd = cmd; + self->cmd = cmd; if (cmd_timeout != -1) - elandev->cmd_timeout = cmd_timeout; + self->cmd_timeout = cmd_timeout; - if (cmd->devices != ELAN_ALL_DEV && !(cmd->devices & elandev->dev_type)) { + if (cmd->devices != ELAN_ALL_DEV && !(cmd->devices & self->dev_type)) { fp_dbg("skipping command 0x%x 0x%x for this device (for devices 0x%x but device is 0x%x)", - cmd->cmd[0], cmd->cmd[1], cmd->devices, elandev->dev_type); + cmd->cmd[0], cmd->cmd[1], cmd->devices, self->dev_type); elan_cmd_done(ssm); return; } - elandev->cur_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), - ssm, - ELAN_EP_CMD_OUT, - g_memdup((char *) cmd->cmd, ELAN_CMD_LEN), - ELAN_CMD_LEN, - elan_cmd_cb, - NULL, - elandev->cmd_timeout); - int r = fpi_usb_submit_transfer(elandev->cur_transfer); - if (r < 0) - fpi_ssm_mark_failed(ssm, r); + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + + fpi_usb_transfer_fill_bulk_full (transfer, + ELAN_EP_CMD_OUT, + (guint8*) cmd->cmd, + ELAN_CMD_LEN, + NULL); + + if (!self->cmd->never_cancel) + cancellable = fpi_device_get_cancellable (dev); + + fpi_usb_transfer_submit (transfer, + self->cmd_timeout, + cancellable, + elan_cmd_cb, + NULL); + fpi_usb_transfer_unref (transfer); } enum stop_capture_states { @@ -448,53 +431,57 @@ enum stop_capture_states { STOP_CAPTURE_NUM_STATES, }; -static void stop_capture_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) +static void stop_capture_run_state(FpiSsm *ssm, FpDevice *dev, + void *user_data) { G_DEBUG_HERE(); switch (fpi_ssm_get_cur_state(ssm)) { case STOP_CAPTURE: - elan_run_cmd(ssm, FP_IMG_DEV(dev), &stop_cmd, ELAN_CMD_TIMEOUT); + elan_run_cmd(ssm, dev, &stop_cmd, + ELAN_CMD_TIMEOUT); break; } } -static void stop_capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void stop_capture_complete(FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); - int error = fpi_ssm_get_error(ssm); + FpImageDevice *dev = user_data; + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); fpi_ssm_free(ssm); + /* The device is inactive at this point. */ + self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE; + + if (self->deactivating) { + /* Simply complete the pending deactivation. */ + self->deactivating = FALSE; + fpi_image_device_deactivate_complete (dev, error); + return; + } + if (!error) { - fpi_imgdev_report_finger_status(dev, FALSE); - - /* If verify or identify fails because of short swipe, we need to restart - * capture manually. It feels like libfprint or the application should know - * better if they want to retry, but they don't. Unless we've been asked to - * deactivate, try to re-enter the capture loop. Since state change is - * async, there's still a chance to be deactivated by another pending - * event. */ - if (elandev->dev_state_next != IMGDEV_STATE_INACTIVE) - dev_change_state(dev, IMGDEV_STATE_AWAIT_FINGER_ON); - - } else if (error != -ECANCELED) - fpi_imgdev_abort_scan(dev, error); + fpi_image_device_report_finger_status(dev, FALSE); + } else { + /* NOTE: We cannot get a cancellation error here. */ + fpi_image_device_session_error (dev, error); + } } -static void elan_stop_capture(struct fp_img_dev *dev) +static void elan_stop_capture(FpDevice *dev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - elan_dev_reset(elandev); + elan_dev_reset_state(self); - fpi_ssm *ssm = - fpi_ssm_new(FP_DEV(dev), stop_capture_run_state, + FpiSsm *ssm = + fpi_ssm_new(dev, stop_capture_run_state, STOP_CAPTURE_NUM_STATES, dev); fpi_ssm_start(ssm, stop_capture_complete); } @@ -507,10 +494,10 @@ enum capture_states { CAPTURE_NUM_STATES, }; -static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); + FpImageDevice *idev = FP_IMAGE_DEVICE(dev); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); int r; switch (fpi_ssm_get_cur_state(ssm)) { @@ -521,22 +508,24 @@ static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data elan_run_cmd(ssm, dev, &pre_scan_cmd, -1); break; case CAPTURE_READ_DATA: + self->dev_state = FP_IMAGE_DEVICE_STATE_CAPTURE; + /* 0x55 - finger present * 0xff - device not calibrated (probably) */ - if (elandev->last_read && elandev->last_read[0] == 0x55) { - if (elandev->dev_state == IMGDEV_STATE_AWAIT_FINGER_ON) - fpi_imgdev_report_finger_status(dev, TRUE); + if (self->last_read && self->last_read[0] == 0x55) { + fpi_image_device_report_finger_status(idev, TRUE); elan_run_cmd(ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT); - } else - fpi_ssm_mark_failed(ssm, -EBADMSG); + } else { + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + } break; case CAPTURE_CHECK_ENOUGH_FRAMES: - r = elan_save_img_frame(elandev); + r = elan_save_img_frame(self); if (r < 0) - fpi_ssm_mark_failed(ssm, r); - else if (elandev->num_frames < ELAN_MAX_FRAMES) { + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + else if (self->num_frames < ELAN_MAX_FRAMES) { /* quickly stop if finger is removed */ - elandev->cmd_timeout = ELAN_FINGER_TIMEOUT; + self->cmd_timeout = ELAN_FINGER_TIMEOUT; fpi_ssm_jump_to_state(ssm, CAPTURE_WAIT_FINGER); } else { fpi_ssm_next_state(ssm); @@ -545,54 +534,51 @@ static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data } } -static void capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceElan *self = FPI_DEVICE_ELAN(_dev); G_DEBUG_HERE(); - if (fpi_ssm_get_error(ssm) == -ECANCELED) { - fpi_ssm_free(ssm); - return; - } + /* XXX: cancellation was specially handled by doing nothing! */ /* either max frames captured or timed out waiting for the next frame */ - if (!fpi_ssm_get_error(ssm) - || (fpi_ssm_get_error(ssm) == -ETIMEDOUT - && fpi_ssm_get_cur_state(ssm) == CAPTURE_WAIT_FINGER)) - if (elandev->num_frames >= ELAN_MIN_FRAMES) + if (!error || + (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) && + fpi_ssm_get_cur_state(ssm) == CAPTURE_WAIT_FINGER)) { + if (self->num_frames >= ELAN_MIN_FRAMES) elan_submit_image(dev); else { fp_dbg("swipe too short: want >= %d frames, got %d", - ELAN_MIN_FRAMES, elandev->num_frames); - fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY_TOO_SHORT); + ELAN_MIN_FRAMES, self->num_frames); + fpi_image_device_retry_scan(dev, FP_DEVICE_RETRY_TOO_SHORT); } - - /* other error - * It says "...abort_scan" but reporting 1 during verification makes it - * successful! */ - else - fpi_imgdev_abort_scan(dev, fpi_ssm_get_error(ssm)); + g_clear_error (&error); + } else { + fpi_image_device_session_error (dev, error); + } fpi_ssm_free(ssm); } -static void elan_capture(struct fp_img_dev *dev) +static void elan_capture(FpDevice *dev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - elan_dev_reset(elandev); - fpi_ssm *ssm = - fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); + elan_dev_reset_state(self); + FpiSsm *ssm = + fpi_ssm_new(dev, capture_run_state, CAPTURE_NUM_STATES, + dev); fpi_ssm_start(ssm, capture_complete); } /* this function needs to have elandev->background and elandev->last_read to be * the calibration mean */ -static int elan_need_calibration(struct elan_dev *elandev) +static int elan_need_calibration(FpiDeviceElan *elandev) { G_DEBUG_HERE(); @@ -635,7 +621,7 @@ enum calibrate_states { CALIBRATE_NUM_STATES, }; -static gboolean elan_supports_calibration(struct elan_dev *elandev) +static gboolean elan_supports_calibration(FpiDeviceElan *elandev) { if (elandev->dev_type == ELAN_0C42) return TRUE; @@ -643,10 +629,9 @@ static gboolean elan_supports_calibration(struct elan_dev *elandev) return elandev->fw_ver >= ELAN_MIN_CALIBRATION_FW; } -static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void calibrate_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); @@ -655,8 +640,8 @@ static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_da elan_run_cmd(ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT); break; case CALIBRATE_SAVE_BACKGROUND: - elan_save_background(elandev); - if (!elan_supports_calibration(elandev)) { + elan_save_background(self); + if (!elan_supports_calibration(self)) { fp_dbg("FW does not support calibration"); fpi_ssm_mark_completed(ssm); } else @@ -666,20 +651,22 @@ static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_da elan_run_cmd(ssm, dev, &get_calib_mean_cmd, ELAN_CMD_TIMEOUT); break; case CALIBRATE_CHECK_NEEDED: - if (elan_need_calibration(elandev)) { - elandev->calib_status = 0; + if (elan_need_calibration(self)) { + self->calib_status = 0; fpi_ssm_next_state(ssm); } else fpi_ssm_mark_completed(ssm); break; case CALIBRATE_GET_STATUS: - elandev->calib_atts_left -= 1; - if (elandev->calib_atts_left) + self->calib_atts_left -= 1; + if (self->calib_atts_left) elan_run_cmd(ssm, dev, &get_calib_status_cmd, ELAN_CMD_TIMEOUT); else { fp_dbg("calibration failed"); - fpi_ssm_mark_failed(ssm, -1); + fpi_ssm_mark_failed(ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Callibration failed!")); } break; case CALIBRATE_CHECK_STATUS: @@ -689,19 +676,21 @@ static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_da * changes to 0x01. It stays that way for some time and then changes back * to 0x03. Because of this we don't just expect 0x03, we want to see 0x01 * first. This is to make sure that a full calibration loop has completed */ - fp_dbg("calibration status: 0x%02x", elandev->last_read[0]); - if (elandev->calib_status == 0x01 - && elandev->last_read[0] == 0x03) { - elandev->calib_status = 0x03; + fp_dbg("calibration status: 0x%02x", self->last_read[0]); + if (self->calib_status == 0x01 + && self->last_read[0] == 0x03) { + self->calib_status = 0x03; fpi_ssm_jump_to_state(ssm, CALIBRATE_GET_BACKGROUND); } else { - fpi_timeout *timeout; + GSource *timeout; - if (elandev->calib_status == 0x00 - && elandev->last_read[0] == 0x01) - elandev->calib_status = 0x01; - timeout = fpi_timeout_add(50, fpi_ssm_next_state_timeout_cb, _dev, ssm); - fpi_timeout_set_name(timeout, "calibrate_run_state"); + if (self->calib_status == 0x00 + && self->last_read[0] == 0x01) + self->calib_status = 0x01; + timeout = fpi_device_add_timeout(dev, 50, + fpi_ssm_next_state_timeout_cb, + ssm); + g_source_set_name(timeout, "calibrate_run_state"); } break; case CALIBRATE_REPEAT_STATUS: @@ -710,29 +699,34 @@ static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_da } } -static void calibrate_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void calibrate_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - - if (fpi_ssm_get_error(ssm) != -ECANCELED) + if (error) { + self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE; + fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error); + } else { + self->dev_state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON; elan_capture(dev); + } fpi_ssm_free(ssm); } -static void elan_calibrate(struct fp_img_dev *dev) +static void elan_calibrate(FpDevice *dev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - elan_dev_reset(elandev); - elandev->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS; + elan_dev_reset_state(self); + self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS; - fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), calibrate_run_state, + FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), calibrate_run_state, CALIBRATE_NUM_STATES, dev); fpi_ssm_start(ssm, calibrate_complete); } @@ -746,10 +740,9 @@ enum activate_states { ACTIVATE_NUM_STATES, }; -static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); @@ -758,9 +751,9 @@ static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_dat elan_run_cmd(ssm, dev, &get_fw_ver_cmd, ELAN_CMD_TIMEOUT); break; case ACTIVATE_SET_FW_VER: - elandev->fw_ver = - (elandev->last_read[0] << 8 | elandev->last_read[1]); - fp_dbg("FW ver 0x%04hx", elandev->fw_ver); + self->fw_ver = + (self->last_read[0] << 8 | self->last_read[1]); + fp_dbg("FW ver 0x%04hx", self->fw_ver); fpi_ssm_next_state(ssm); break; case ACTIVATE_GET_SENSOR_DIM: @@ -768,27 +761,27 @@ static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_dat break; case ACTIVATE_SET_SENSOR_DIM: /* see elan_save_frame for details */ - if (elandev->dev_type & ELAN_NOT_ROTATED) { - elandev->frame_width = elandev->last_read[0]; - elandev->frame_height = elandev->raw_frame_height = - elandev->last_read[2]; + if (self->dev_type & ELAN_NOT_ROTATED) { + self->frame_width = self->last_read[0]; + self->frame_height = self->raw_frame_height = + self->last_read[2]; } else { - elandev->frame_width = elandev->last_read[2]; - elandev->frame_height = elandev->raw_frame_height = - elandev->last_read[0]; + self->frame_width = self->last_read[2]; + self->frame_height = self->raw_frame_height = + self->last_read[0]; } /* Work-around sensors returning the sizes as zero-based index * rather than the number of pixels. */ - if ((elandev->frame_width % 2 == 1) && - (elandev->frame_height % 2 == 1)) { - elandev->frame_width++; - elandev->frame_height++; - elandev->raw_frame_height = elandev->frame_height; + if ((self->frame_width % 2 == 1) && + (self->frame_height % 2 == 1)) { + self->frame_width++; + self->frame_height++; + self->raw_frame_height = self->frame_height; } - if (elandev->frame_height > ELAN_MAX_FRAME_HEIGHT) - elandev->frame_height = ELAN_MAX_FRAME_HEIGHT; - fp_dbg("sensor dimensions, WxH: %dx%d", elandev->frame_width, - elandev->raw_frame_height); + if (self->frame_height > ELAN_MAX_FRAME_HEIGHT) + self->frame_height = ELAN_MAX_FRAME_HEIGHT; + fp_dbg("sensor dimensions, WxH: %dx%d", self->frame_width, + self->raw_frame_height); fpi_ssm_next_state(ssm); break; case ACTIVATE_CMD_1: @@ -798,191 +791,195 @@ static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_dat } } -static void activate_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); G_DEBUG_HERE(); - if (fpi_ssm_get_error(ssm) != -ECANCELED) { - fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm)); - } + fpi_image_device_activate_complete (idev, error); fpi_ssm_free(ssm); } -static void elan_activate(struct fp_img_dev *dev) +static void elan_activate(FpImageDevice *dev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - elan_dev_reset(elandev); + elan_dev_reset_state(self); - fpi_ssm *ssm = - fpi_ssm_new(FP_DEV(dev), activate_run_state, ACTIVATE_NUM_STATES, dev); + FpiSsm *ssm = + fpi_ssm_new(FP_DEVICE(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); fpi_ssm_start(ssm, activate_complete); } -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) +static void dev_init(FpImageDevice *dev) { - struct elan_dev *elandev; - int r; + GError *error = NULL; + FpiDeviceElan *self; G_DEBUG_HERE(); - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; + if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { + fpi_image_device_open_complete(dev, error); + return; } - elandev = g_malloc0(sizeof(struct elan_dev)); - fp_dev_set_instance_data(FP_DEV(dev), elandev); + self = FPI_DEVICE_ELAN(dev); /* common params */ - elandev->dev_type = driver_data; - elandev->background = NULL; - elandev->process_frame = elan_process_frame_thirds; + self->dev_type = fpi_device_get_driver_data (FP_DEVICE (dev)); + self->background = NULL; + self->process_frame = elan_process_frame_thirds; - switch (driver_data) { + switch (self->dev_type) { case ELAN_0907: - elandev->process_frame = elan_process_frame_linear; + self->process_frame = elan_process_frame_linear; break; } - fpi_imgdev_open_complete(dev, 0); - return 0; + fpi_image_device_open_complete(dev, NULL); } -static void elan_deactivate(struct fp_img_dev *dev) +static void dev_deinit(FpImageDevice *dev) { - G_DEBUG_HERE(); - - fpi_imgdev_deactivate_complete(dev); -} - -static void dev_deinit(struct fp_img_dev *dev) -{ - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + GError *error = NULL; + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - elan_dev_reset(elandev); - g_free(elandev->background); - g_free(elandev); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); + elan_dev_reset_state(self); + g_free(self->background); + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + fpi_image_device_close_complete(dev, error); } -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { G_DEBUG_HERE(); elan_activate(dev); - return 0; } -static void elan_change_state(struct fp_img_dev *dev) +static void elan_change_state(FpImageDevice *idev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); - enum fp_imgdev_state next_state = elandev->dev_state_next; + FpDevice *dev = FP_DEVICE(idev); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); + FpImageDeviceState next_state = self->dev_state_next; - if (elandev->dev_state == next_state) { + if (self->dev_state == next_state) { fp_dbg("already in %d", next_state); return; - } else + } else { fp_dbg("changing to %d", next_state); + } switch (next_state) { - case IMGDEV_STATE_INACTIVE: - if (elandev->cur_transfer) - /* deactivation will complete in transfer callback */ - fpi_usb_cancel_transfer(elandev->cur_transfer); - else - elan_deactivate(dev); break; - case IMGDEV_STATE_AWAIT_FINGER_ON: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: /* activation completed or another enroll stage started */ elan_calibrate(dev); break; - case IMGDEV_STATE_CAPTURE: + case FP_IMAGE_DEVICE_STATE_CAPTURE: /* not used */ break; - case IMGDEV_STATE_AWAIT_FINGER_OFF: - elan_stop_capture(dev); + case FP_IMAGE_DEVICE_STATE_INACTIVE: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: + if (self->dev_state != FP_IMAGE_DEVICE_STATE_INACTIVE || + self->dev_state != FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) + elan_stop_capture(dev); } - - elandev->dev_state = next_state; } static void -elan_change_state_async(struct fp_dev *dev, +elan_change_state_async(FpDevice *dev, void *data) { g_message ("state change dev: %p", dev); - elan_change_state(FP_IMG_DEV (dev)); + elan_change_state(FP_IMAGE_DEVICE(dev)); } -static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state) +static void dev_change_state(FpImageDevice *dev, FpImageDeviceState state) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_timeout *timeout; + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); + GSource *timeout; G_DEBUG_HERE(); + /* Inactive and await finger off are equivalent for the elan driver. */ + if (state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) + state = FP_IMAGE_DEVICE_STATE_INACTIVE; + + if (self->dev_state_next == state) { + fp_dbg ("change to state %d already queued", state); + } + switch (state) { - case IMGDEV_STATE_INACTIVE: - case IMGDEV_STATE_AWAIT_FINGER_ON: - case IMGDEV_STATE_AWAIT_FINGER_OFF: { + case FP_IMAGE_DEVICE_STATE_INACTIVE: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: { char *name; /* schedule state change instead of calling it directly to allow all actions * related to the previous state to complete */ - elandev->dev_state_next = state; - timeout = fpi_timeout_add(10, elan_change_state_async, FP_DEV(dev), NULL); + self->dev_state_next = state; + timeout = fpi_device_add_timeout(FP_DEVICE(dev), 10, + elan_change_state_async, + NULL); name = g_strdup_printf ("dev_change_state to %d", state); - fpi_timeout_set_name(timeout, name); + g_source_set_name(timeout, name); g_free (name); break; } - case IMGDEV_STATE_CAPTURE: + case FP_IMAGE_DEVICE_STATE_CAPTURE: /* TODO MAYBE: split capture ssm into smaller ssms and use this state */ - elandev->dev_state = state; - elandev->dev_state_next = state; + self->dev_state = state; + self->dev_state_next = state; break; default: - fp_err("unrecognized state %d", state); - fpi_imgdev_session_error(dev, -EINVAL); - return -EINVAL; + g_assert_not_reached(); } - - /* as of time of writing libfprint never checks the return value */ - return 0; } -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - dev_change_state(dev, IMGDEV_STATE_INACTIVE); + if (self->dev_state == FP_IMAGE_DEVICE_STATE_INACTIVE) { + /* The device is inactive already, complete the operation immediately. */ + fpi_image_device_deactivate_complete (dev, NULL); + } else { + /* The device is not yet inactive, flag that we are deactivating (and + * need to signal back deactivation) and then ensure we will change + * to the inactive state eventually. */ + self->deactivating = TRUE; + dev_change_state (dev, FP_IMAGE_DEVICE_STATE_INACTIVE); + } } -struct fp_img_driver elan_driver = { - .driver = { - .id = ELAN_ID, - .name = FP_COMPONENT, - .full_name = "ElanTech Fingerprint Sensor", - .id_table = elan_id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - }, - .flags = 0, +static void fpi_device_elan_init(FpiDeviceElan *self) { +} +static void fpi_device_elan_class_init(FpiDeviceElanClass *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - .bz3_threshold = 24, + dev_class->id = "elan"; + dev_class->full_name = "ElanTech Fingerprint Sensor"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = elan_id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - .open = dev_init, - .close = dev_deinit, - .activate = dev_activate, - .deactivate = dev_deactivate, - .change_state = dev_change_state, -}; + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + img_class->change_state = dev_change_state; + + img_class->bz3_threshold = 24; +} diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h index c5f0f191..059f00ac 100644 --- a/libfprint/drivers/elan.h +++ b/libfprint/drivers/elan.h @@ -21,7 +21,7 @@ #ifndef __ELAN_H #define __ELAN_H -#include +#include #define ELAN_VEND_ID 0x04f3 @@ -59,9 +59,9 @@ #define ELAN_SKIP_LAST_FRAMES 2 #define ELAN_CMD_LEN 0x2 -#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT) -#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN) -#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN) +#define ELAN_EP_CMD_OUT (0x1 | FPI_USB_ENDPOINT_OUT) +#define ELAN_EP_CMD_IN (0x3 | FPI_USB_ENDPOINT_IN) +#define ELAN_EP_IMG_IN (0x2 | FPI_USB_ENDPOINT_IN) /* used as response length to tell the driver to skip reading response */ #define ELAN_CMD_SKIP_READ 0 @@ -76,6 +76,7 @@ struct elan_cmd { int response_len; int response_in; unsigned short devices; + gboolean never_cancel; }; static const struct elan_cmd get_sensor_dim_cmd = { @@ -152,73 +153,73 @@ static const struct elan_cmd stop_cmd = { .response_len = ELAN_CMD_SKIP_READ, .response_in = ELAN_EP_CMD_IN, .devices = ELAN_ALL_DEV, + .never_cancel = TRUE, }; -static const struct usb_id elan_id_table[] = { - {.vendor = ELAN_VEND_ID,.product = 0x0903,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0907,.driver_data = ELAN_0907}, - {.vendor = ELAN_VEND_ID,.product = 0x0c01,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c02,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c03,.driver_data = ELAN_0C03}, - {.vendor = ELAN_VEND_ID,.product = 0x0c04,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c05,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c06,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c07,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c08,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c09,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c0a,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c0b,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c0c,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c0d,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c0e,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c0f,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c10,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c11,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c12,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c13,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c14,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c15,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c16,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c17,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c18,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c19,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c1a,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c1b,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c1c,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c1d,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c1e,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c1f,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c20,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c21,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c22,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c23,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c24,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c25,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c26,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c27,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c28,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c29,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c2a,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c2b,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c2c,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c2d,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c2e,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c2f,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c30,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c31,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c32,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c33,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c42,.driver_data = ELAN_0C42}, - {0, 0, 0,}, +static const FpIdEntry elan_id_table [ ] = { + {.vid = ELAN_VEND_ID, .pid = 0x0903, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0907, .driver_data = ELAN_0907}, + {.vid = ELAN_VEND_ID, .pid = 0x0c01, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c02, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c03, .driver_data = ELAN_0C03}, + {.vid = ELAN_VEND_ID, .pid = 0x0c04, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c05, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c06, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c07, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c08, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c09, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0a, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0b, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0c, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0d, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0e, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0f, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c10, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c11, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c12, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c13, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c14, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c15, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c16, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c17, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c18, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c19, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1a, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1b, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1c, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1d, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1e, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1f, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c20, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c21, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c22, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c23, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c24, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c25, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c26, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c27, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c28, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c29, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2a, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2b, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2c, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2d, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2e, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2f, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c30, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42}, + {.vid = 0, .pid = 0, .driver_data = 0}, }; -static void elan_cmd_done(fpi_ssm *ssm); -static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev); +static void elan_cmd_done(FpiSsm *ssm); +static void elan_cmd_read(FpiSsm *ssm, FpDevice *dev); -static void elan_calibrate(struct fp_img_dev *dev); -static void elan_capture(struct fp_img_dev *dev); -static void elan_deactivate(struct fp_img_dev *dev); +static void elan_calibrate(FpDevice *dev); +static void elan_capture(FpDevice *dev); -static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state); +static void dev_change_state(FpImageDevice *dev, FpImageDeviceState state); #endif diff --git a/meson.build b/meson.build index 5552e200..899d8068 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics'] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics', 'elan'] all_drivers = default_drivers + virtual_drivers