mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2026-05-11 08:28:08 +02:00
upeksonly: make 147e:1002 enrollment work
This commit is contained in:
parent
17a13fec10
commit
fafa3718da
2 changed files with 794 additions and 49 deletions
|
|
@ -31,7 +31,15 @@
|
|||
#define CTRL_TIMEOUT 1000
|
||||
#define NUM_BULK_TRANSFERS 24
|
||||
#define MAX_ROWS 2048
|
||||
#define MAX_ROWS_1002 24000
|
||||
#define MIN_ROWS 64
|
||||
#define DETAIL_THRESHOLD_SQ_1002 800.0
|
||||
#define MOTION_THRESHOLD_1002 18.0
|
||||
#define DETAIL_TRIGGER_ROWS_1002 3
|
||||
#define MIN_DETECTION_ROW_1002 1000
|
||||
#define INITIAL_FINGER_IRQ_IGNORE_MS_1002 250
|
||||
#define MAX_EARLY_FINGER_IRQS_1002 3
|
||||
#define AWAIT_FINGER_SETTLE_DELAY_MS_1002 100
|
||||
|
||||
#define BLANK_THRESHOLD 250
|
||||
#define FINGER_PRESENT_THRESHOLD 32
|
||||
|
|
@ -61,6 +69,18 @@ enum sonly_fs {
|
|||
FINGER_REMOVED,
|
||||
};
|
||||
|
||||
enum loopsm_states {
|
||||
LOOPSM_RUN_AWFSM,
|
||||
LOOPSM_DELAY_AWAIT_FINGER,
|
||||
LOOPSM_STATUS_READ,
|
||||
LOOPSM_AWAIT_FINGER,
|
||||
LOOPSM_RUN_CAPSM,
|
||||
LOOPSM_CAPTURE,
|
||||
LOOPSM_RUN_DEINITSM,
|
||||
LOOPSM_FINAL,
|
||||
LOOPSM_NUM_STATES,
|
||||
};
|
||||
|
||||
struct _FpiDeviceUpeksonly
|
||||
{
|
||||
FpImageDevice parent;
|
||||
|
|
@ -76,6 +96,7 @@ struct _FpiDeviceUpeksonly
|
|||
|
||||
/* Do we really need multiple concurrent transfers? */
|
||||
GCancellable *img_cancellable;
|
||||
GCancellable *await_cancellable;
|
||||
GPtrArray *img_transfers;
|
||||
int num_flying;
|
||||
|
||||
|
|
@ -89,6 +110,14 @@ struct _FpiDeviceUpeksonly
|
|||
int num_nonblank;
|
||||
enum sonly_fs finger_state;
|
||||
int last_seqnum;
|
||||
guint32 marker_window;
|
||||
int marker_skip;
|
||||
int finger_start_row_1002;
|
||||
unsigned detail_rows_1002;
|
||||
gboolean have_avg_row_1002;
|
||||
guchar avg_row_1002[IMG_CROP_WIDTH_1002];
|
||||
gint64 await_intr_start_us;
|
||||
unsigned early_finger_irq_count_1002;
|
||||
|
||||
enum sonly_kill_transfers_action killing_transfers;
|
||||
GError *kill_error;
|
||||
|
|
@ -150,6 +179,43 @@ upeksonly_get_pixel (struct fpi_line_asmbl_ctx *ctx,
|
|||
return buf[offset];
|
||||
}
|
||||
|
||||
static int
|
||||
upeksonly_get_deviation_simple (struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *line1,
|
||||
GSList *line2)
|
||||
{
|
||||
unsigned char *buf1 = line1->data, *buf2 = line2->data;
|
||||
int res = 0, mean = 0;
|
||||
|
||||
g_assert (ctx->line_width > 0);
|
||||
|
||||
for (int i = 0; i < ctx->line_width; i++)
|
||||
mean += (int) buf1[i] + (int) buf2[i];
|
||||
|
||||
mean /= ctx->line_width;
|
||||
|
||||
for (int i = 0; i < ctx->line_width; i++)
|
||||
{
|
||||
int dev = (int) buf1[i] + (int) buf2[i] - mean;
|
||||
res += dev * dev;
|
||||
}
|
||||
|
||||
return res / ctx->line_width;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
upeksonly_get_pixel_simple (struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *row,
|
||||
unsigned x)
|
||||
{
|
||||
unsigned char *buf = row->data;
|
||||
|
||||
if (x >= ctx->line_width)
|
||||
return 0;
|
||||
|
||||
return buf[x];
|
||||
}
|
||||
|
||||
/***** IMAGE PROCESSING *****/
|
||||
|
||||
static void
|
||||
|
|
@ -197,7 +263,9 @@ cancel_img_transfers (FpImageDevice *dev)
|
|||
static gboolean
|
||||
is_capturing (FpiDeviceUpeksonly *sdev)
|
||||
{
|
||||
return sdev->num_rows < MAX_ROWS && (sdev->finger_state != FINGER_REMOVED);
|
||||
guint max_rows = sdev->dev_model == UPEKSONLY_1002 ? MAX_ROWS_1002 : MAX_ROWS;
|
||||
|
||||
return sdev->num_rows < max_rows && (sdev->finger_state != FINGER_REMOVED);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -217,7 +285,64 @@ handoff_img (FpImageDevice *dev)
|
|||
self->rows = g_slist_reverse (self->rows);
|
||||
|
||||
fp_dbg ("%u rows", self->num_rows);
|
||||
img = fpi_assemble_lines (&self->assembling_ctx, self->rows, self->num_rows);
|
||||
|
||||
if (self->dev_model == UPEKSONLY_1002)
|
||||
{
|
||||
guint crop_start = 0;
|
||||
guint cropped_rows;
|
||||
guint out_height;
|
||||
guint row_count = g_slist_length (self->rows);
|
||||
g_autofree guchar **rows = g_new (guchar *, row_count);
|
||||
guint row_idx = 0;
|
||||
|
||||
if (row_count != self->num_rows)
|
||||
{
|
||||
fp_warn ("1002 row list length %u differs from row counter %u",
|
||||
row_count,
|
||||
self->num_rows);
|
||||
self->num_rows = row_count;
|
||||
}
|
||||
|
||||
if (self->finger_start_row_1002 >= 0)
|
||||
crop_start = self->finger_start_row_1002 + IMG_CROP_OFFSET_1002;
|
||||
else if (row_count > IMG_CROP_ROWS_1002)
|
||||
crop_start = row_count - IMG_CROP_ROWS_1002;
|
||||
|
||||
if (crop_start >= row_count)
|
||||
crop_start = 0;
|
||||
|
||||
cropped_rows = MIN (IMG_CROP_ROWS_1002, row_count - crop_start);
|
||||
out_height = cropped_rows / IMG_HEIGHT_SCALE_1002;
|
||||
|
||||
for (GSList *row = self->rows; row; row = g_slist_next (row))
|
||||
rows[row_idx++] = row->data;
|
||||
|
||||
img = fp_image_new (IMG_CROP_WIDTH_1002, out_height);
|
||||
img->flags = FPI_IMAGE_COLORS_INVERTED;
|
||||
|
||||
for (guint y = 0; y < out_height; y++)
|
||||
{
|
||||
for (guint x = 0; x < IMG_CROP_WIDTH_1002; x++)
|
||||
{
|
||||
guint sum = 0;
|
||||
|
||||
for (guint i = 0; i < IMG_HEIGHT_SCALE_1002; i++)
|
||||
{
|
||||
guint src_y = crop_start + y * IMG_HEIGHT_SCALE_1002 + i;
|
||||
guint src_x = IMG_CROP_X_1002 + x;
|
||||
|
||||
sum += rows[src_y][src_x];
|
||||
}
|
||||
|
||||
img->data[y * IMG_CROP_WIDTH_1002 + x] = sum / IMG_HEIGHT_SCALE_1002;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
img = fpi_assemble_lines (&self->assembling_ctx, self->rows, self->num_rows);
|
||||
}
|
||||
|
||||
g_slist_free_full (self->rows, g_free);
|
||||
self->rows = NULL;
|
||||
|
|
@ -230,21 +355,116 @@ handoff_img (FpImageDevice *dev)
|
|||
cancel_img_transfers (dev);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_1002_finger_detection (FpiDeviceUpeksonly *self)
|
||||
{
|
||||
GSList *row;
|
||||
double sum = 0.0;
|
||||
double sq_sum = 0.0;
|
||||
double motion = 0.0;
|
||||
guchar avg_row[IMG_CROP_WIDTH_1002];
|
||||
|
||||
if (self->num_rows % IMG_HEIGHT_SCALE_1002 != 0)
|
||||
return FALSE;
|
||||
|
||||
for (guint x = 0; x < IMG_CROP_WIDTH_1002; x++)
|
||||
{
|
||||
guint col_sum = 0;
|
||||
|
||||
row = self->rows;
|
||||
for (guint i = 0; i < IMG_HEIGHT_SCALE_1002 && row; i++, row = g_slist_next (row))
|
||||
col_sum += ((guchar *) row->data)[IMG_CROP_X_1002 + x];
|
||||
|
||||
avg_row[x] = col_sum / IMG_HEIGHT_SCALE_1002;
|
||||
sum += avg_row[x];
|
||||
sq_sum += avg_row[x] * avg_row[x];
|
||||
|
||||
if (self->have_avg_row_1002)
|
||||
motion += ABS ((int) avg_row[x] - (int) self->avg_row_1002[x]);
|
||||
}
|
||||
|
||||
if (self->have_avg_row_1002)
|
||||
motion /= IMG_CROP_WIDTH_1002;
|
||||
|
||||
if (self->num_rows >= MIN_DETECTION_ROW_1002 &&
|
||||
(sq_sum / IMG_CROP_WIDTH_1002) -
|
||||
(sum / IMG_CROP_WIDTH_1002) * (sum / IMG_CROP_WIDTH_1002) > DETAIL_THRESHOLD_SQ_1002 &&
|
||||
self->have_avg_row_1002 &&
|
||||
motion > MOTION_THRESHOLD_1002)
|
||||
{
|
||||
self->detail_rows_1002++;
|
||||
|
||||
if (self->finger_start_row_1002 < 0 &&
|
||||
self->detail_rows_1002 >= DETAIL_TRIGGER_ROWS_1002)
|
||||
{
|
||||
self->finger_start_row_1002 =
|
||||
MAX (0, (int) self->num_rows -
|
||||
(int) self->detail_rows_1002 * IMG_HEIGHT_SCALE_1002);
|
||||
fp_dbg ("detected 1002 finger data at row %d", self->finger_start_row_1002);
|
||||
}
|
||||
}
|
||||
else if (self->finger_start_row_1002 < 0)
|
||||
{
|
||||
self->detail_rows_1002 = 0;
|
||||
}
|
||||
|
||||
memcpy (self->avg_row_1002, avg_row, sizeof (avg_row));
|
||||
self->have_avg_row_1002 = TRUE;
|
||||
|
||||
return self->finger_start_row_1002 >= 0 &&
|
||||
self->num_rows >= (guint) self->finger_start_row_1002 +
|
||||
IMG_CROP_OFFSET_1002 +
|
||||
IMG_CROP_ROWS_1002;
|
||||
}
|
||||
|
||||
static void
|
||||
row_complete (FpImageDevice *dev)
|
||||
{
|
||||
FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev);
|
||||
int line_width = self->assembling_ctx.line_width;
|
||||
|
||||
self->rowbuf_offset = -1;
|
||||
|
||||
if (self->dev_model == UPEKSONLY_1002)
|
||||
{
|
||||
if (!is_capturing (self) || self->killing_transfers)
|
||||
{
|
||||
g_clear_pointer (&self->rowbuf, g_free);
|
||||
return;
|
||||
}
|
||||
|
||||
self->rows = g_slist_prepend (self->rows, self->rowbuf);
|
||||
self->num_rows++;
|
||||
self->rowbuf = NULL;
|
||||
|
||||
if (update_1002_finger_detection (self))
|
||||
{
|
||||
fp_dbg ("row limit met");
|
||||
self->finger_state = FINGER_REMOVED;
|
||||
handoff_img (dev);
|
||||
}
|
||||
else if (self->num_rows >= MAX_ROWS_1002)
|
||||
{
|
||||
fp_dbg ("1002 capture timed out without finger data");
|
||||
self->finger_state = FINGER_REMOVED;
|
||||
fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
|
||||
fpi_image_device_report_finger_status (dev, FALSE);
|
||||
self->killing_transfers = ITERATE_SSM;
|
||||
self->kill_ssm = self->loopsm;
|
||||
cancel_img_transfers (dev);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->num_rows > 0)
|
||||
{
|
||||
unsigned char *lastrow = self->rows->data;
|
||||
int std_sq_dev, mean_sq_diff;
|
||||
|
||||
std_sq_dev = fpi_std_sq_dev (self->rowbuf, self->img_width);
|
||||
std_sq_dev = fpi_std_sq_dev (self->rowbuf, line_width);
|
||||
mean_sq_diff = fpi_mean_sq_diff_norm (lastrow, self->rowbuf,
|
||||
self->img_width);
|
||||
line_width);
|
||||
|
||||
switch (self->finger_state)
|
||||
{
|
||||
|
|
@ -498,6 +718,56 @@ handle_packet (FpImageDevice *dev, unsigned char *data)
|
|||
start_new_row (self, data + diff, 62 - diff);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_packet_1002 (FpImageDevice *dev, unsigned char *data)
|
||||
{
|
||||
FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev);
|
||||
|
||||
data += 2; /* skip sequence number */
|
||||
|
||||
for (int i = 0; i < 62; i++)
|
||||
{
|
||||
guint8 byte = data[i];
|
||||
|
||||
if (self->marker_skip > 0)
|
||||
{
|
||||
self->marker_skip--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (self->rowbuf)
|
||||
{
|
||||
if (self->rowbuf_offset < self->img_width)
|
||||
self->rowbuf[self->rowbuf_offset++] = byte;
|
||||
}
|
||||
|
||||
self->marker_window = ((self->marker_window << 8) | byte) & 0xffffff;
|
||||
|
||||
if (self->marker_window == 0xffa5a5)
|
||||
{
|
||||
if (self->rowbuf)
|
||||
{
|
||||
if (self->rowbuf_offset >= 3)
|
||||
self->rowbuf_offset -= 3;
|
||||
|
||||
if (self->rowbuf_offset > IMG_WIDTH_1002 / 2)
|
||||
{
|
||||
row_complete (dev);
|
||||
if (!is_capturing (self))
|
||||
return;
|
||||
}
|
||||
else
|
||||
g_clear_pointer (&self->rowbuf, g_free);
|
||||
}
|
||||
|
||||
self->rowbuf = g_malloc0 (self->img_width);
|
||||
self->rowbuf_offset = 0;
|
||||
self->marker_skip = 5;
|
||||
self->marker_window = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
|
|
@ -508,11 +778,12 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|||
|
||||
self->num_flying--;
|
||||
|
||||
fp_dbg ("bulk cb: error=%s actual_length=%zu num_flying=%d capturing=%d",
|
||||
error ? error->message : "none",
|
||||
transfer->actual_length,
|
||||
self->num_flying,
|
||||
self->capturing);
|
||||
if (self->dev_model != UPEKSONLY_1002)
|
||||
fp_dbg ("bulk cb: error=%s actual_length=%zu num_flying=%d capturing=%d",
|
||||
error ? error->message : "none",
|
||||
transfer->actual_length,
|
||||
self->num_flying,
|
||||
self->capturing);
|
||||
|
||||
if (self->killing_transfers)
|
||||
{
|
||||
|
|
@ -556,15 +827,20 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|||
{
|
||||
if (!is_capturing (self))
|
||||
return;
|
||||
handle_packet (dev, transfer->buffer + i);
|
||||
|
||||
if (self->dev_model == UPEKSONLY_1002)
|
||||
handle_packet_1002 (dev, transfer->buffer + i);
|
||||
else
|
||||
handle_packet (dev, transfer->buffer + i);
|
||||
}
|
||||
|
||||
if (is_capturing (self))
|
||||
{
|
||||
fp_dbg ("re-submitting bulk transfer actual_length=%zu rows=%u finger_state=%d",
|
||||
transfer->actual_length,
|
||||
self->num_rows,
|
||||
self->finger_state);
|
||||
if (self->dev_model != UPEKSONLY_1002)
|
||||
fp_dbg ("re-submitting bulk transfer actual_length=%zu rows=%u finger_state=%d",
|
||||
transfer->actual_length,
|
||||
self->num_rows,
|
||||
self->finger_state);
|
||||
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer),
|
||||
0,
|
||||
self->img_cancellable,
|
||||
|
|
@ -586,6 +862,17 @@ struct write_regs_data
|
|||
size_t regs_written;
|
||||
};
|
||||
|
||||
struct write_regs_data_data
|
||||
{
|
||||
FpDevice *dev;
|
||||
FpiSsm *ssm;
|
||||
const struct sonly_regwrite_data *regs;
|
||||
size_t num_regs;
|
||||
size_t regs_written;
|
||||
};
|
||||
|
||||
static void sm_await_intr (FpiSsm *ssm, FpImageDevice *dev);
|
||||
|
||||
static void
|
||||
write_regs_finished (struct write_regs_data *wrdata, GError *error)
|
||||
{
|
||||
|
|
@ -663,6 +950,161 @@ sm_write_regs (FpiSsm *ssm,
|
|||
write_regs_iterate (wrdata);
|
||||
}
|
||||
|
||||
static void write_regs_data_iterate (struct write_regs_data_data *wrdata);
|
||||
static void write_regs_data_finished (struct write_regs_data_data *wrdata, GError *error);
|
||||
|
||||
static void
|
||||
write_regs_data_readback_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
struct write_regs_data_data *wrdata = user_data;
|
||||
|
||||
if (error)
|
||||
{
|
||||
write_regs_data_finished (wrdata, error);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_dbg ("read %02x result = %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
transfer->endpoint & 0xff,
|
||||
transfer->buffer[0], transfer->buffer[1], transfer->buffer[2], transfer->buffer[3],
|
||||
transfer->buffer[4], transfer->buffer[5], transfer->buffer[6], transfer->buffer[7]);
|
||||
|
||||
wrdata->regs_written++;
|
||||
write_regs_data_iterate (wrdata);
|
||||
}
|
||||
|
||||
static void
|
||||
write_regs_data_finished (struct write_regs_data_data *wrdata, GError *error)
|
||||
{
|
||||
if (!error)
|
||||
fpi_ssm_next_state (wrdata->ssm);
|
||||
else
|
||||
fpi_ssm_mark_failed (wrdata->ssm, error);
|
||||
|
||||
g_free (wrdata);
|
||||
}
|
||||
|
||||
static void
|
||||
write_regs_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
struct write_regs_data_data *wrdata = user_data;
|
||||
const struct sonly_regwrite_data *regwrite;
|
||||
|
||||
if (error)
|
||||
{
|
||||
write_regs_data_finished (wrdata, error);
|
||||
return;
|
||||
}
|
||||
|
||||
regwrite = &wrdata->regs[wrdata->regs_written];
|
||||
|
||||
if (regwrite->reg == 0x47 &&
|
||||
regwrite->len == 1 &&
|
||||
(regwrite->value[0] == 0x00 || regwrite->value[0] == 0x04))
|
||||
{
|
||||
FpiUsbTransfer *read_transfer = fpi_usb_transfer_new (wrdata->dev);
|
||||
|
||||
fp_dbg ("read 58 len=8");
|
||||
fpi_usb_transfer_fill_control (read_transfer,
|
||||
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
||||
0x0c,
|
||||
0,
|
||||
0x58,
|
||||
8);
|
||||
read_transfer->short_is_error = TRUE;
|
||||
read_transfer->ssm = wrdata->ssm;
|
||||
read_transfer->endpoint = 0x58;
|
||||
|
||||
fpi_usb_transfer_submit (read_transfer,
|
||||
CTRL_TIMEOUT,
|
||||
NULL,
|
||||
write_regs_data_readback_cb,
|
||||
wrdata);
|
||||
return;
|
||||
}
|
||||
|
||||
wrdata->regs_written++;
|
||||
write_regs_data_iterate (wrdata);
|
||||
}
|
||||
|
||||
static void
|
||||
write_regs_data_iterate (struct write_regs_data_data *wrdata)
|
||||
{
|
||||
FpiUsbTransfer *transfer;
|
||||
const struct sonly_regwrite_data *regwrite;
|
||||
|
||||
if (wrdata->regs_written >= wrdata->num_regs)
|
||||
{
|
||||
write_regs_data_finished (wrdata, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
regwrite = &wrdata->regs[wrdata->regs_written];
|
||||
fp_dbg ("set %02x len=%u", regwrite->reg, regwrite->len);
|
||||
|
||||
if (regwrite->len == 0)
|
||||
{
|
||||
guint8 read_len = regwrite->value[0] ? regwrite->value[0] : 8;
|
||||
|
||||
fp_dbg ("read %02x len=%u", regwrite->reg, read_len);
|
||||
transfer = fpi_usb_transfer_new (wrdata->dev);
|
||||
fpi_usb_transfer_fill_control (transfer,
|
||||
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
||||
0x0c,
|
||||
0,
|
||||
regwrite->reg,
|
||||
read_len);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->ssm = wrdata->ssm;
|
||||
transfer->endpoint = regwrite->reg;
|
||||
|
||||
fpi_usb_transfer_submit (transfer,
|
||||
CTRL_TIMEOUT,
|
||||
NULL,
|
||||
write_regs_data_readback_cb,
|
||||
wrdata);
|
||||
return;
|
||||
}
|
||||
|
||||
transfer = fpi_usb_transfer_new (wrdata->dev);
|
||||
fpi_usb_transfer_fill_control (transfer,
|
||||
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
|
||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
||||
0x0c,
|
||||
0,
|
||||
regwrite->reg,
|
||||
regwrite->len);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->ssm = wrdata->ssm;
|
||||
memcpy (transfer->buffer, regwrite->value, regwrite->len);
|
||||
|
||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, write_regs_data_cb, wrdata);
|
||||
}
|
||||
|
||||
static void
|
||||
sm_write_regs_data (FpiSsm *ssm,
|
||||
FpDevice *dev,
|
||||
const struct sonly_regwrite_data *regs,
|
||||
size_t num_regs)
|
||||
{
|
||||
struct write_regs_data_data *wrdata = g_malloc (sizeof (*wrdata));
|
||||
|
||||
wrdata->ssm = ssm;
|
||||
wrdata->regs = regs;
|
||||
wrdata->num_regs = num_regs;
|
||||
wrdata->regs_written = 0;
|
||||
wrdata->dev = dev;
|
||||
|
||||
write_regs_data_iterate (wrdata);
|
||||
}
|
||||
|
||||
static void
|
||||
sm_write_reg (FpiSsm *ssm,
|
||||
FpImageDevice *dev,
|
||||
|
|
@ -732,15 +1174,65 @@ sm_read_reg (FpiSsm *ssm,
|
|||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sm_read_status_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_dbg ("read status result = %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
transfer->buffer[0], transfer->buffer[1], transfer->buffer[2], transfer->buffer[3],
|
||||
transfer->buffer[4], transfer->buffer[5], transfer->buffer[6], transfer->buffer[7]);
|
||||
fpi_ssm_next_state (transfer->ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
sm_read_status (FpiSsm *ssm,
|
||||
FpImageDevice *dev)
|
||||
{
|
||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||
|
||||
fp_dbg ("read status");
|
||||
fpi_usb_transfer_fill_control (transfer,
|
||||
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
||||
0x04,
|
||||
0,
|
||||
0,
|
||||
8);
|
||||
transfer->ssm = ssm;
|
||||
transfer->short_is_error = TRUE;
|
||||
fpi_usb_transfer_submit (transfer,
|
||||
CTRL_TIMEOUT,
|
||||
NULL,
|
||||
sm_read_status_cb,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sm_await_intr_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||
FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev);
|
||||
gboolean finger_detected = TRUE;
|
||||
|
||||
g_clear_object (&self->await_cancellable);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (self->deactivating &&
|
||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
fpi_ssm_mark_completed (transfer->ssm);
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
return;
|
||||
}
|
||||
|
|
@ -749,6 +1241,42 @@ sm_await_intr_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|||
transfer->buffer[0], transfer->buffer[1],
|
||||
transfer->buffer[2], transfer->buffer[3]);
|
||||
|
||||
if (self->dev_model == UPEKSONLY_1002)
|
||||
{
|
||||
gint64 elapsed_ms = (g_get_monotonic_time () - self->await_intr_start_us) / 1000;
|
||||
|
||||
/* Windows keeps polling 0x83 with 12 12 12 12 while idle and only
|
||||
* switches to 01 00 00 00 when a finger is actually detected. */
|
||||
finger_detected = transfer->buffer[0] == 0x01 &&
|
||||
transfer->buffer[1] == 0x00 &&
|
||||
transfer->buffer[2] == 0x00 &&
|
||||
transfer->buffer[3] == 0x00;
|
||||
|
||||
if (finger_detected && elapsed_ms < INITIAL_FINGER_IRQ_IGNORE_MS_1002)
|
||||
{
|
||||
self->early_finger_irq_count_1002++;
|
||||
|
||||
if (self->early_finger_irq_count_1002 < MAX_EARLY_FINGER_IRQS_1002)
|
||||
{
|
||||
fp_dbg ("1002 early finger interrupt after %" G_GINT64_FORMAT " ms, restart wait setup",
|
||||
elapsed_ms);
|
||||
fpi_ssm_jump_to_state_delayed (transfer->ssm, LOOPSM_RUN_AWFSM, 200);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_dbg ("1002 accepting repeated early finger interrupt after %u attempts",
|
||||
self->early_finger_irq_count_1002);
|
||||
}
|
||||
|
||||
if (!finger_detected)
|
||||
{
|
||||
fp_dbg ("1002 idle interrupt, continue waiting");
|
||||
sm_await_intr (transfer->ssm, dev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self->early_finger_irq_count_1002 = 0;
|
||||
self->finger_state = FINGER_DETECTED;
|
||||
fpi_image_device_report_finger_status (dev, TRUE);
|
||||
fpi_ssm_next_state (transfer->ssm);
|
||||
|
|
@ -759,9 +1287,14 @@ sm_await_intr (FpiSsm *ssm,
|
|||
FpImageDevice *dev)
|
||||
{
|
||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||
FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev);
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
self->await_intr_start_us = g_get_monotonic_time ();
|
||||
g_clear_object (&self->await_cancellable);
|
||||
self->await_cancellable = g_cancellable_new ();
|
||||
|
||||
fpi_usb_transfer_fill_interrupt (transfer, 0x83, 4);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->ssm = ssm;
|
||||
|
|
@ -769,7 +1302,7 @@ sm_await_intr (FpiSsm *ssm,
|
|||
/* NOTE: This was changed to be cancellable with the version 2 port! */
|
||||
fpi_usb_transfer_submit (transfer,
|
||||
0,
|
||||
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||
self->await_cancellable,
|
||||
sm_await_intr_cb,
|
||||
NULL);
|
||||
}
|
||||
|
|
@ -860,7 +1393,10 @@ awfsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case AWFSM_1000_WRITEV_1:
|
||||
sm_write_regs (ssm, _dev, awfsm_1000_writev_1, G_N_ELEMENTS (awfsm_1000_writev_1));
|
||||
if (FPI_DEVICE_UPEKSONLY (_dev)->dev_model == UPEKSONLY_1002)
|
||||
fpi_ssm_next_state (ssm);
|
||||
else
|
||||
sm_write_regs (ssm, _dev, awfsm_1000_writev_1, G_N_ELEMENTS (awfsm_1000_writev_1));
|
||||
break;
|
||||
|
||||
case AWFSM_1000_WRITEV_2:
|
||||
|
|
@ -892,8 +1428,9 @@ enum capsm_1000_states {
|
|||
|
||||
enum capsm_1002_states {
|
||||
CAPSM_1002_INIT,
|
||||
CAPSM_1002_WRITEV,
|
||||
CAPSM_1002_STREAM_SETUP,
|
||||
CAPSM_1002_FIRE_BULK,
|
||||
CAPSM_1002_WRITEV,
|
||||
CAPSM_1002_NUM_STATES,
|
||||
};
|
||||
|
||||
|
|
@ -933,6 +1470,14 @@ capsm_fire_bulk (FpiSsm *ssm,
|
|||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
clear_capture_rows (FpiDeviceUpeksonly *self)
|
||||
{
|
||||
g_clear_pointer (&self->rowbuf, g_free);
|
||||
g_slist_free_full (self->rows, g_free);
|
||||
self->rows = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
capsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
{
|
||||
|
|
@ -942,6 +1487,7 @@ capsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case CAPSM_2016_INIT:
|
||||
clear_capture_rows (self);
|
||||
self->rowbuf_offset = -1;
|
||||
self->num_rows = 0;
|
||||
self->wraparounds = -1;
|
||||
|
|
@ -949,6 +1495,8 @@ capsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
self->num_nonblank = 0;
|
||||
self->finger_state = FINGER_DETECTED;
|
||||
self->last_seqnum = 16383;
|
||||
self->marker_window = 0;
|
||||
self->marker_skip = 0;
|
||||
self->killing_transfers = 0;
|
||||
fpi_ssm_next_state (ssm);
|
||||
break;
|
||||
|
|
@ -979,6 +1527,7 @@ capsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case CAPSM_1000_INIT:
|
||||
clear_capture_rows (self);
|
||||
self->rowbuf_offset = -1;
|
||||
self->num_rows = 0;
|
||||
self->wraparounds = -1;
|
||||
|
|
@ -986,6 +1535,8 @@ capsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
self->num_nonblank = 0;
|
||||
self->finger_state = FINGER_DETECTED;
|
||||
self->last_seqnum = 16383;
|
||||
self->marker_window = 0;
|
||||
self->marker_skip = 0;
|
||||
self->killing_transfers = 0;
|
||||
fpi_ssm_next_state (ssm);
|
||||
break;
|
||||
|
|
@ -1008,6 +1559,7 @@ capsm_1001_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case CAPSM_1001_INIT:
|
||||
clear_capture_rows (self);
|
||||
self->rowbuf_offset = -1;
|
||||
self->num_rows = 0;
|
||||
self->wraparounds = -1;
|
||||
|
|
@ -1015,6 +1567,8 @@ capsm_1001_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
self->num_nonblank = 0;
|
||||
self->finger_state = AWAIT_FINGER;
|
||||
self->last_seqnum = 16383;
|
||||
self->marker_window = 0;
|
||||
self->marker_skip = 0;
|
||||
self->killing_transfers = 0;
|
||||
fpi_ssm_next_state (ssm);
|
||||
break;
|
||||
|
|
@ -1053,6 +1607,7 @@ capsm_1002_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case CAPSM_1002_INIT:
|
||||
clear_capture_rows (self);
|
||||
self->rowbuf_offset = -1;
|
||||
self->num_rows = 0;
|
||||
self->wraparounds = -1;
|
||||
|
|
@ -1060,17 +1615,27 @@ capsm_1002_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
self->num_nonblank = 0;
|
||||
self->finger_state = FINGER_DETECTED;
|
||||
self->last_seqnum = 16383;
|
||||
self->marker_window = 0;
|
||||
self->marker_skip = 0;
|
||||
self->finger_start_row_1002 = -1;
|
||||
self->detail_rows_1002 = 0;
|
||||
self->have_avg_row_1002 = FALSE;
|
||||
self->early_finger_irq_count_1002 = 0;
|
||||
self->killing_transfers = 0;
|
||||
fpi_ssm_next_state (ssm);
|
||||
break;
|
||||
|
||||
case CAPSM_1002_FIRE_BULK:
|
||||
capsm_fire_bulk (ssm, _dev);
|
||||
case CAPSM_1002_STREAM_SETUP:
|
||||
sm_write_regs_data (ssm, _dev, capsm_1002_writev_data, G_N_ELEMENTS (capsm_1002_writev_data));
|
||||
break;
|
||||
|
||||
case CAPSM_1002_WRITEV:
|
||||
sm_write_regs (ssm, _dev, capsm_1002_writev, G_N_ELEMENTS (capsm_1002_writev));
|
||||
break;
|
||||
|
||||
case CAPSM_1002_FIRE_BULK:
|
||||
capsm_fire_bulk (ssm, _dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1196,7 +1761,7 @@ initsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
{
|
||||
case INITSM_1000_WRITEV_1:
|
||||
if (FPI_DEVICE_UPEKSONLY (_dev)->dev_model == UPEKSONLY_1002)
|
||||
sm_write_regs (ssm, _dev, initsm_1002_writev_1, G_N_ELEMENTS (initsm_1002_writev_1));
|
||||
sm_write_regs_data (ssm, _dev, initsm_1002_writev_1, G_N_ELEMENTS (initsm_1002_writev_1));
|
||||
else
|
||||
sm_write_regs (ssm, _dev, initsm_1000_writev_1, G_N_ELEMENTS (initsm_1000_writev_1));
|
||||
break;
|
||||
|
|
@ -1232,16 +1797,6 @@ initsm_1001_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
|
||||
/***** CAPTURE LOOP *****/
|
||||
|
||||
enum loopsm_states {
|
||||
LOOPSM_RUN_AWFSM,
|
||||
LOOPSM_AWAIT_FINGER,
|
||||
LOOPSM_RUN_CAPSM,
|
||||
LOOPSM_CAPTURE,
|
||||
LOOPSM_RUN_DEINITSM,
|
||||
LOOPSM_FINAL,
|
||||
LOOPSM_NUM_STATES,
|
||||
};
|
||||
|
||||
static void
|
||||
loopsm_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
{
|
||||
|
|
@ -1292,7 +1847,39 @@ loopsm_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
}
|
||||
break;
|
||||
|
||||
case LOOPSM_DELAY_AWAIT_FINGER:
|
||||
if (self->deactivating)
|
||||
{
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
break;
|
||||
}
|
||||
|
||||
if (self->dev_model == UPEKSONLY_1002)
|
||||
fpi_ssm_next_state_delayed (ssm, AWAIT_FINGER_SETTLE_DELAY_MS_1002);
|
||||
else
|
||||
fpi_ssm_next_state (ssm);
|
||||
break;
|
||||
|
||||
case LOOPSM_STATUS_READ:
|
||||
if (self->deactivating)
|
||||
{
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
break;
|
||||
}
|
||||
|
||||
if (self->dev_model == UPEKSONLY_1002)
|
||||
sm_read_status (ssm, dev);
|
||||
else
|
||||
fpi_ssm_next_state (ssm);
|
||||
break;
|
||||
|
||||
case LOOPSM_AWAIT_FINGER:
|
||||
if (self->deactivating)
|
||||
{
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (self->dev_model)
|
||||
{
|
||||
case UPEKSONLY_1001:
|
||||
|
|
@ -1373,7 +1960,10 @@ loopsm_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||
break;
|
||||
|
||||
case LOOPSM_FINAL:
|
||||
fpi_ssm_jump_to_state (ssm, LOOPSM_RUN_AWFSM);
|
||||
if (self->deactivating)
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
else
|
||||
fpi_ssm_jump_to_state (ssm, LOOPSM_RUN_AWFSM);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1388,6 +1978,7 @@ deactivate_done (FpImageDevice *dev, GError *error)
|
|||
|
||||
G_DEBUG_HERE ();
|
||||
free_img_transfers (self);
|
||||
g_clear_object (&self->await_cancellable);
|
||||
g_free (self->rowbuf);
|
||||
self->rowbuf = NULL;
|
||||
|
||||
|
|
@ -1404,7 +1995,16 @@ dev_deactivate (FpImageDevice *dev)
|
|||
|
||||
if (!self->capturing)
|
||||
{
|
||||
deactivate_done (dev, NULL);
|
||||
if (self->loopsm)
|
||||
{
|
||||
self->deactivating = TRUE;
|
||||
if (self->await_cancellable)
|
||||
g_cancellable_cancel (self->await_cancellable);
|
||||
}
|
||||
else
|
||||
{
|
||||
deactivate_done (dev, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1421,6 +2021,8 @@ loopsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
|||
FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev);
|
||||
|
||||
|
||||
self->loopsm = NULL;
|
||||
|
||||
if (self->deactivating)
|
||||
{
|
||||
deactivate_done (dev, error);
|
||||
|
|
@ -1591,20 +2193,29 @@ dev_init (FpImageDevice *dev)
|
|||
self->assembling_ctx.resolution = 8;
|
||||
self->assembling_ctx.median_filter_size = 25;
|
||||
self->assembling_ctx.max_search_offset = 30;
|
||||
self->assembling_ctx.get_deviation = upeksonly_get_deviation2;
|
||||
self->assembling_ctx.get_pixel = upeksonly_get_pixel;
|
||||
|
||||
self = FPI_DEVICE_UPEKSONLY (dev);
|
||||
self->dev_model = (int) fpi_device_get_driver_data (FP_DEVICE (dev));
|
||||
switch (self->dev_model)
|
||||
{
|
||||
case UPEKSONLY_1000:
|
||||
case UPEKSONLY_1002:
|
||||
self->assembling_ctx.get_deviation = upeksonly_get_deviation2;
|
||||
self->assembling_ctx.get_pixel = upeksonly_get_pixel;
|
||||
self->img_width = IMG_WIDTH_1000;
|
||||
self->assembling_ctx.line_width = IMG_WIDTH_1000;
|
||||
break;
|
||||
|
||||
case UPEKSONLY_1002:
|
||||
self->assembling_ctx.get_deviation = upeksonly_get_deviation_simple;
|
||||
self->assembling_ctx.get_pixel = upeksonly_get_pixel_simple;
|
||||
self->img_width = IMG_WIDTH_1002;
|
||||
self->assembling_ctx.line_width = IMG_WIDTH_1002;
|
||||
fpi_image_device_set_bz3_threshold (dev, 7);
|
||||
break;
|
||||
|
||||
case UPEKSONLY_1001:
|
||||
self->assembling_ctx.get_deviation = upeksonly_get_deviation2;
|
||||
self->assembling_ctx.get_pixel = upeksonly_get_pixel;
|
||||
self->img_width = IMG_WIDTH_1001;
|
||||
self->assembling_ctx.line_width = IMG_WIDTH_1001;
|
||||
|
||||
|
|
@ -1613,6 +2224,8 @@ dev_init (FpImageDevice *dev)
|
|||
break;
|
||||
|
||||
case UPEKSONLY_2016:
|
||||
self->assembling_ctx.get_deviation = upeksonly_get_deviation2;
|
||||
self->assembling_ctx.get_pixel = upeksonly_get_pixel;
|
||||
self->img_width = IMG_WIDTH_2016;
|
||||
self->assembling_ctx.line_width = IMG_WIDTH_2016;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
|
||||
#define IMG_WIDTH_2016 288
|
||||
#define IMG_WIDTH_1000 288
|
||||
#define IMG_WIDTH_1002 162
|
||||
#define IMG_CROP_X_1002 18
|
||||
#define IMG_CROP_WIDTH_1002 108
|
||||
#define IMG_CROP_ROWS_1002 992
|
||||
#define IMG_CROP_OFFSET_1002 0
|
||||
#define IMG_HEIGHT_SCALE_1002 4
|
||||
#define IMG_WIDTH_1001 216
|
||||
|
||||
struct sonly_regwrite
|
||||
|
|
@ -33,6 +39,15 @@ struct sonly_regwrite
|
|||
guint8 value;
|
||||
};
|
||||
|
||||
struct sonly_regwrite_data
|
||||
{
|
||||
guint8 reg;
|
||||
guint8 len;
|
||||
guint8 value[8];
|
||||
};
|
||||
|
||||
#define UPEKSONLY_READ(reg, len) { reg, 0, { len } }
|
||||
|
||||
/***** AWAIT FINGER *****/
|
||||
|
||||
static const struct sonly_regwrite awfsm_2016_writev_1[] = {
|
||||
|
|
@ -55,6 +70,15 @@ static const struct sonly_regwrite awfsm_1000_writev_1[] = {
|
|||
{ 0x10, 0x00 }, { 0x11, 0xbf },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite awfsm_1002_writev_1[] = {
|
||||
/* Windows sets up the 1002 wait path with this 3e/1a prelude before
|
||||
* enabling the finger detector. */
|
||||
{ 0x49, 0x08 },
|
||||
{ 0x3e, 0x45 }, { 0x3e, 0x92 }, { 0x3e, 0xd9 }, { 0x3e, 0x3a },
|
||||
{ 0x3e, 0x99 }, { 0x3e, 0x8c }, { 0x3e, 0xc6 }, { 0x3e, 0xb9 },
|
||||
{ 0x1a, 0x01 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite awfsm_2016_writev_2[] = {
|
||||
{ 0x01, 0xc6 }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, { 0x0e, 0x0e },
|
||||
{ 0x0f, 0x0d }, { 0x0b, 0x00 },
|
||||
|
|
@ -66,7 +90,9 @@ static const struct sonly_regwrite awfsm_1000_writev_2[] = {
|
|||
};
|
||||
|
||||
static const struct sonly_regwrite awfsm_1002_writev_2[] = {
|
||||
/* Windows enables 147e:1002 finger detection with bit 0x01 clear here. */
|
||||
/* Windows arms 147e:1002 wait mode with the 1a/0b/49 prelude followed by
|
||||
* the actual detector-enable writes on 0x30/0x15. */
|
||||
{ 0x1a, 0x03 }, { 0x0b, 0x00 }, { 0x49, 0x0c },
|
||||
{ 0x30, 0xe1 }, { 0x15, 0x05 }, { 0x15, 0x85 },
|
||||
};
|
||||
|
||||
|
|
@ -98,13 +124,49 @@ static const struct sonly_regwrite capsm_1000_writev[] = {
|
|||
};
|
||||
|
||||
static const struct sonly_regwrite capsm_1002_writev[] = {
|
||||
/* 147e:1002 appears close to the 1000 family for init/interrupts, but it
|
||||
* does not start streaming image data with the plain 1000/2016 capture
|
||||
* writes. This sequence matches the Windows driver immediately before bulk
|
||||
* image packets start arriving on endpoint 0x81.
|
||||
*/
|
||||
{ 0x15, 0x25 }, { 0x30, 0xe0 }, { 0x09, 0x23 }, { 0x13, 0x75 },
|
||||
{ 0x0b, 0x80 },
|
||||
/* BSAPI submits bulk URBs before these capture-start writes. */
|
||||
{ 0x09, 0x22 }, { 0x13, 0x75 }, { 0x0b, 0x80 },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite_data capsm_1002_writev_data[] = {
|
||||
/* Finger-detect mode changes security state; replay the final BSAPI
|
||||
* key/tail immediately before the low-security streaming setup. */
|
||||
{ 0x49, 1, { 0x08 } },
|
||||
{ 0x3e, 1, { 0x15 } }, { 0x3e, 1, { 0x5c } },
|
||||
{ 0x3e, 1, { 0x27 } }, { 0x3e, 1, { 0xf5 } },
|
||||
{ 0x3e, 1, { 0xfb } }, { 0x3e, 1, { 0x82 } },
|
||||
{ 0x3e, 1, { 0x25 } }, { 0x3e, 1, { 0x61 } },
|
||||
{ 0x09, 1, { 0x2a } }, { 0x1a, 1, { 0x01 } },
|
||||
UPEKSONLY_READ (0x0b, 8), { 0x0b, 1, { 0x00 } },
|
||||
UPEKSONLY_READ (0x13, 8), { 0x13, 1, { 0x45 } },
|
||||
{ 0x04, 1, { 0x00 } }, { 0x05, 1, { 0x00 } },
|
||||
|
||||
/* Replay the BSAPI low-security streaming setup after finger-detect mode. */
|
||||
{ 0x7e, 1, { 0x0f } },
|
||||
{ 0x6e, 1, { 0x20 } }, { 0x6e, 1, { 0x00 } },
|
||||
{ 0x6f, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||
{ 0x77, 7, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||
{ 0x74, 8, { 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff } },
|
||||
{ 0x7c, 1, { 0x07 } }, { 0x6e, 1, { 0x10 } },
|
||||
{ 0x7e, 1, { 0x05 } }, { 0x6e, 1, { 0x1f } },
|
||||
{ 0x7e, 1, { 0x0f } }, { 0x6e, 1, { 0x10 } },
|
||||
{ 0x7e, 1, { 0x05 } }, { 0x1a, 1, { 0x03 } },
|
||||
UPEKSONLY_READ (0x17, 8), UPEKSONLY_READ (0x0a, 8),
|
||||
UPEKSONLY_READ (0x03, 8), UPEKSONLY_READ (0x00, 8),
|
||||
UPEKSONLY_READ (0x01, 8), UPEKSONLY_READ (0x30, 8),
|
||||
UPEKSONLY_READ (0x15, 8), UPEKSONLY_READ (0x12, 8),
|
||||
UPEKSONLY_READ (0x25, 8), UPEKSONLY_READ (0x31, 8),
|
||||
UPEKSONLY_READ (0x08, 8), UPEKSONLY_READ (0x07, 8),
|
||||
UPEKSONLY_READ (0x24, 8), UPEKSONLY_READ (0x26, 8),
|
||||
UPEKSONLY_READ (0x1d, 8),
|
||||
{ 0x00, 2, { 0x53, 0xee } },
|
||||
{ 0x03, 1, { 0x27 } },
|
||||
{ 0x07, 8, { 0x00, 0x00, 0x2a, 0x20, 0x00, 0x0f, 0x09, 0x0a } },
|
||||
{ 0x0f, 3, { 0x09, 0x00, 0x8f } },
|
||||
{ 0x1d, 1, { 0x02 } },
|
||||
{ 0x25, 4, { 0x10, 0x00, 0x8f, 0x23 } },
|
||||
{ 0x31, 1, { 0x44 } },
|
||||
{ 0x07, 1, { 0x10 } },
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite capsm_1001_writev_1[] = {
|
||||
|
|
@ -206,14 +268,84 @@ static const struct sonly_regwrite initsm_1000_writev_1[] = {
|
|||
{ 0x0b, 0x00 }, { 0x08, 0x00 }, /* Initialize capture control registers */
|
||||
};
|
||||
|
||||
static const struct sonly_regwrite initsm_1002_writev_1[] = {
|
||||
/* Captured from the Windows 147e:1002 driver before finger detection. */
|
||||
{ 0x49, 0x08 },
|
||||
{ 0x3e, 0x3d }, { 0x3e, 0x18 }, { 0x3e, 0x38 }, { 0x3e, 0x63 },
|
||||
{ 0x3e, 0x9d }, { 0x3e, 0x5c }, { 0x3e, 0xb1 }, { 0x3e, 0x1f },
|
||||
{ 0x1a, 0x01 }, { 0x1a, 0x03 }, { 0x0b, 0x00 }, { 0x49, 0x0c },
|
||||
#define UPEKSONLY_1002_CAL_PASS \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x02 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x02 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x02 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x0a } }, \
|
||||
{ 0x47, 1, { 0x00 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x02 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x02 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x02 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x0a } }, \
|
||||
{ 0x47, 1, { 0x00 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x02 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x02 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x02 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x0a } }, \
|
||||
{ 0x47, 1, { 0x00 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x02 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x02 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x02 } }, \
|
||||
{ 0x47, 1, { 0x02 } }, { 0x47, 1, { 0x0a } }, \
|
||||
{ 0x47, 1, { 0x00 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }, { 0x47, 1, { 0x04 } }, \
|
||||
{ 0x47, 1, { 0x04 } }
|
||||
|
||||
static const struct sonly_regwrite_data initsm_1002_writev_1[] = {
|
||||
/* Captured from Linux BSAPI 4.0 in low sensor-security mode. */
|
||||
UPEKSONLY_READ (0x4b, 8),
|
||||
{ 0x4b, 1, { 0x01 } }, { 0x4f, 1, { 0x06 } },
|
||||
{ 0x4f, 1, { 0x05 } }, { 0x4f, 1, { 0x04 } },
|
||||
{ 0x4b, 1, { 0x00 } },
|
||||
UPEKSONLY_READ (0x49, 8),
|
||||
{ 0x3e, 1, { 0x45 } }, { 0x3e, 1, { 0x92 } },
|
||||
{ 0x3e, 1, { 0xd9 } }, { 0x3e, 1, { 0x3a } },
|
||||
{ 0x3e, 1, { 0x99 } }, { 0x3e, 1, { 0x8c } },
|
||||
{ 0x3e, 1, { 0xc6 } }, { 0x3e, 1, { 0xb9 } },
|
||||
UPEKSONLY_READ (0x1a, 8), UPEKSONLY_READ (0x09, 8),
|
||||
{ 0x09, 1, { 0x2a } }, { 0x1a, 1, { 0x01 } },
|
||||
{ 0x09, 1, { 0x22 } }, { 0x1a, 1, { 0x03 } },
|
||||
{ 0x49, 1, { 0x09 } },
|
||||
UPEKSONLY_1002_CAL_PASS,
|
||||
{ 0x49, 1, { 0x08 } },
|
||||
{ 0x3e, 1, { 0x2e } }, { 0x3e, 1, { 0xfe } },
|
||||
{ 0x3e, 1, { 0x14 } }, { 0x3e, 1, { 0xd5 } },
|
||||
{ 0x3e, 1, { 0x33 } }, { 0x3e, 1, { 0x34 } },
|
||||
{ 0x3e, 1, { 0xc5 } }, { 0x3e, 1, { 0xbf } },
|
||||
{ 0x09, 1, { 0x2a } }, { 0x1a, 1, { 0x01 } },
|
||||
{ 0x09, 1, { 0x22 } }, { 0x1a, 1, { 0x03 } },
|
||||
{ 0x49, 1, { 0x09 } },
|
||||
UPEKSONLY_1002_CAL_PASS,
|
||||
{ 0x49, 1, { 0x08 } },
|
||||
{ 0x3e, 1, { 0x15 } }, { 0x3e, 1, { 0x5c } },
|
||||
{ 0x3e, 1, { 0x27 } }, { 0x3e, 1, { 0xf5 } },
|
||||
{ 0x3e, 1, { 0xfb } }, { 0x3e, 1, { 0x82 } },
|
||||
{ 0x3e, 1, { 0x25 } }, { 0x3e, 1, { 0x61 } },
|
||||
{ 0x09, 1, { 0x2a } }, { 0x1a, 1, { 0x01 } },
|
||||
UPEKSONLY_READ (0x0b, 8), { 0x0b, 1, { 0x00 } },
|
||||
UPEKSONLY_READ (0x13, 8), { 0x13, 1, { 0x45 } },
|
||||
/* Do not preload the capture stream here. The capture-specific low-security
|
||||
* programming is replayed in CAPSM once a real finger interrupt arrives. */
|
||||
{ 0x04, 1, { 0x00 } }, { 0x05, 1, { 0x00 } },
|
||||
};
|
||||
|
||||
#undef UPEKSONLY_1002_CAL_PASS
|
||||
|
||||
static const struct sonly_regwrite initsm_1001_writev_1[] = {
|
||||
{ 0x4a, 0x9d },
|
||||
{ 0x4f, 0x06 },
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue