From 75fe328f64f33b09e02d519e079efeb965af5a10 Mon Sep 17 00:00:00 2001 From: Igor Filatov Date: Wed, 28 Feb 2018 11:36:33 +0200 Subject: [PATCH] elan: Don't rotate frames on 0x0c03 There has been a report that a 0x0c03 was installed straight (other readers so far have produced images that are 90 degrees rotated). There is no way for the dirver to know how a device is installed, so for now just make an exception. --- libfprint/drivers/elan.c | 60 ++++++++++++++++++++++++++-------------- libfprint/drivers/elan.h | 8 ++++-- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c index 20e33ad..cc54fb7 100644 --- a/libfprint/drivers/elan.c +++ b/libfprint/drivers/elan.c @@ -77,7 +77,7 @@ struct elan_dev { unsigned short *background; unsigned char frame_width; unsigned char frame_height; - unsigned char raw_frame_width; + unsigned char raw_frame_height; int num_frames; GSList *frames; /* end state */ @@ -111,18 +111,33 @@ static void elan_save_frame(struct elan_dev *elandev, unsigned short *frame) { G_DEBUG_HERE(); - unsigned char raw_height = elandev->frame_width; - unsigned char raw_width = elandev->raw_frame_width; + /* so far 3 types of readers by sensor dimensions and orientation have been + * seen in the wild: + * 1. 144x64. Raw images are in portrait orientation while readers themselves + * are placed (e.g. built into a touchpad) in landscape orientation. These + * need to be rotated before assembling. + * 2. 96x96 rotated. Like the first type but square. Likewise, need to be + * rotated before assembling. + * 3. 96x96 normal. Square and need NOT be rotated. So far there's only been + * 1 report of a 0c03 of this type. Hopefully this type can be identified + * by device id (and manufacturers don't just install the readers as they + * please). + * we also discard stripes of 'frame_margin' from bottom and top because + * assembling works bad for tall frames */ - /* Raw images are vertical and perpendicular to swipe direction of a - * normalized image, which means we need to make them horizontal before - * assembling. We also discard stripes of 'frame_margin' along raw - * height. */ - unsigned char frame_margin = (raw_width - elandev->frame_height) / 2; - for (int y = 0; y < raw_height; y++) - for (int x = frame_margin; x < raw_width - frame_margin; x++) { - int frame_idx = y + (x - frame_margin) * raw_height; - int raw_idx = x + y * raw_width; + 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; + 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) + 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]; } @@ -344,7 +359,7 @@ static void elan_cmd_read(struct fpi_ssm *ssm) if (elandev->cmd->cmd == get_image_cmd.cmd) /* raw data has 2-byte "pixels" and the frame is vertical */ response_len = - elandev->raw_frame_width * elandev->frame_width * 2; + elandev->raw_frame_height * elandev->frame_width * 2; struct libusb_transfer *transfer = libusb_alloc_transfer(0); if (!transfer) { @@ -701,15 +716,20 @@ static void activate_run_state(struct fpi_ssm *ssm) elan_run_cmd(ssm, &get_sensor_dim_cmd, ELAN_CMD_TIMEOUT); break; case ACTIVATE_SET_SENSOR_DIM: - elandev->frame_width = elandev->last_read[2]; - elandev->raw_frame_width = elandev->last_read[0]; - if (elandev->raw_frame_width < ELAN_MAX_FRAME_HEIGHT) - elandev->frame_height = elandev->raw_frame_width; - else + /* 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]; + } else { + elandev->frame_width = elandev->last_read[2]; + elandev->frame_height = elandev->raw_frame_height = + elandev->last_read[0]; + } + if (elandev->frame_height > ELAN_MAX_FRAME_HEIGHT) elandev->frame_height = ELAN_MAX_FRAME_HEIGHT; - /* see elan_save_frame for why it's width x raw_width */ fp_dbg("sensor dimensions, WxH: %dx%d", elandev->frame_width, - elandev->raw_frame_width); + elandev->raw_frame_height); fpi_ssm_next_state(ssm); break; case ACTIVATE_CMD_1: diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h index 9002a0e..7c4e81a 100644 --- a/libfprint/drivers/elan.h +++ b/libfprint/drivers/elan.h @@ -30,7 +30,11 @@ #define ELAN_ALL_DEV 0 /* devices with quirks */ -#define ELAN_0907 1 +#define ELAN_0907 (1 << 0) +#define ELAN_0C03 (1 << 1) + +/* devices which don't require frame rotation before assembling */ +#define ELAN_NOT_ROTATED ELAN_0C03 /* min FW version that supports calibration */ #define ELAN_MIN_CALIBRATION_FW 0x0138 @@ -155,7 +159,7 @@ static const struct usb_id elan_id_table[] = { {.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_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},