Skip to content

Instantly share code, notes, and snippets.

@jouyouyun
Last active October 10, 2017 06:48
Show Gist options
  • Save jouyouyun/4c1eecd837373327ab7382619c22e831 to your computer and use it in GitHub Desktop.
Save jouyouyun/4c1eecd837373327ab7382619c22e831 to your computer and use it in GitHub Desktop.
Libfprint etss801u patch, from: https://bugs.freedesktop.org/show_bug.cgi?id=73762 but not work on my laptop. My device: "Bus 001 Device 004: ID 1c7a:0801 LighTuning Technology Inc. Fingerprint Reader"
diff --git a/configure.ac b/configure.ac
index 8b29119..6400aaf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,7 +23,7 @@ AC_SUBST(lt_major)
AC_SUBST(lt_revision)
AC_SUBST(lt_age)
-all_drivers="upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes1660 aes2501 aes2550 aes2660 aes3500 aes4000 vfs101 vfs301 vfs5011 upektc_img etes603 vfs0050"
+all_drivers="upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes1660 aes2501 aes2550 aes2660 aes3500 aes4000 vfs101 vfs301 vfs5011 upektc_img etes603 etss801u vfs0050"
require_imaging='no'
require_aeslib='no'
@@ -48,6 +48,7 @@ enable_vfs301='no'
enable_vfs5011='no'
enable_upektc_img='no'
enable_etes603='no'
+enable_etss801u='no'
enable_vfs0050='no'
AC_ARG_WITH([drivers],[AS_HELP_STRING([--with-drivers],
@@ -151,6 +152,10 @@ for driver in `echo ${drivers} | sed -e 's/,/ /g' -e 's/,$//g'`; do
AC_DEFINE([ENABLE_ETES603], [], [Build EgisTec ES603 driver])
enable_etes603="yes"
;;
+ etss801u)
+ AC_DEFINE([ENABLE_ETSS801U], [], [Build EgisTec SS801U driver])
+ enable_etss801u="yes"
+ ;;
vfs0050)
AC_DEFINE([ENABLE_VFS0050], [], [Build Validity VFS0050 driver])
enable_vfs0050="yes"
@@ -180,6 +185,7 @@ AM_CONDITIONAL([ENABLE_VFS301], [test "$enable_vfs301" = "yes"])
AM_CONDITIONAL([ENABLE_VFS5011], [test "$enable_vfs5011" = "yes"])
AM_CONDITIONAL([ENABLE_UPEKTC_IMG], [test "$enable_upektc_img" = "yes"])
AM_CONDITIONAL([ENABLE_ETES603], [test "$enable_etes603" = "yes"])
+AM_CONDITIONAL([ENABLE_ETSS801U], [test "$enable_etss801u" = "yes"])
AM_CONDITIONAL([ENABLE_VFS0050], [test "$enable_vfs0050" = "yes"])
@@ -402,6 +408,11 @@ if test x$enable_etes603 != xno ; then
else
AC_MSG_NOTICE([ etes603 driver disabled])
fi
+if test x$enable_etss801u != xno ; then
+ AC_MSG_NOTICE([** etss801u driver enabled])
+else
+ AC_MSG_NOTICE([ etss801u driver disabled])
+fi
if test x$enable_vfs0050 != xno ; then
AC_MSG_NOTICE([** vfs0050 driver enabled])
else
diff --git a/libfprint/Makefile.am b/libfprint/Makefile.am
index a7fb162..b68cb46 100644
--- a/libfprint/Makefile.am
+++ b/libfprint/Makefile.am
@@ -21,6 +21,7 @@ VFS301_SRC = drivers/vfs301.c drivers/vfs301_proto.c drivers/vfs301_proto.h dri
VFS5011_SRC = drivers/vfs5011.c drivers/vfs5011_proto.h
UPEKTC_IMG_SRC = drivers/upektc_img.c drivers/upektc_img.h
ETES603_SRC = drivers/etes603.c
+ETSS801U_SRC = drivers/etss801u.c drivers/etss801u.h
VFS0050_SRC = drivers/vfs0050.c drivers/vfs0050.h
EXTRA_DIST = \
@@ -43,6 +44,7 @@ EXTRA_DIST = \
$(VFS5011_SRC) \
$(UPEKTC_IMG_SRC) \
$(ETES603_SRC) \
+ $(ETSS801U_SRC) \
$(VFS0050_SRC) \
drivers/aesx660.c \
drivers/aesx660.h \
@@ -186,6 +188,10 @@ if ENABLE_ETES603
DRIVER_SRC += $(ETES603_SRC)
endif
+if ENABLE_ETSS801U
+DRIVER_SRC += ${ETSS801U_SRC}
+endif
+
if ENABLE_VFS0050
DRIVER_SRC += $(VFS0050_SRC)
endif
diff --git a/libfprint/core.c b/libfprint/core.c
index 8b6fe43..487c00a 100644
--- a/libfprint/core.c
+++ b/libfprint/core.c
@@ -377,6 +377,9 @@ static struct fp_img_driver * const img_drivers[] = {
#ifdef ENABLE_AES1660
&aes1660_driver,
#endif
+#ifdef ENABLE_ETSS801U
+ &etss801u_driver,
+#endif
#ifdef ENABLE_AES2660
&aes2660_driver,
#endif
diff --git a/libfprint/drivers/driver_ids.h b/libfprint/drivers/driver_ids.h
index 8143d01..306d7fe 100644
--- a/libfprint/drivers/driver_ids.h
+++ b/libfprint/drivers/driver_ids.h
@@ -41,6 +41,7 @@ enum {
ETES603_ID = 18,
VFS5011_ID = 19,
VFS0050_ID = 20,
+ ETSS801U_ID = 21,
};
#endif
diff --git a/libfprint/drivers/etss801u.c b/libfprint/drivers/etss801u.c
new file mode 100644
index 0000000..92c51c6
--- /dev/null
+++ b/libfprint/drivers/etss801u.c
@@ -0,0 +1,1804 @@
+/*
+ * EgisTec SS801U driver for libfprint
+ * Copyright (C) 2011 Alexey Prokopchuk <[email protected]>
+ *
+ * Initially based on code from libfprint aes1610 driver.
+ *
+ * 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 "etss801u"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libusb.h>
+
+#include <fp_internal.h>
+#include "driver_ids.h"
+#include "etss801u.h"
+
+#define EP_IN (2 | LIBUSB_ENDPOINT_IN)
+#define EP_OUT (1 | LIBUSB_ENDPOINT_OUT)
+
+#define BULK_TIMEOUT 4000
+
+/* The SS801U is an imaging device using a swipe-type sensor.
+ * It sending eight 768 x 80 frames for each fingerprint scan session.
+ * All those frames are simply collected into the whole image.
+ * But, 768 x 80 image is too fuzzy and big, and causing segfaults
+ * after scan. So when I build result image, only every fourth byte
+ * of every fourth row saved.
+ * Hence, image size always 192 x 160.
+ */
+
+
+/*Command and answer static buffers*/
+char cmd_buf[]={ET_CMD_HDR,ET_BUF_PDATA,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+char ret_buf[8192];
+/*SS801U command structure*/
+static struct et_init einit;
+/*Dynamic image fragmets array*/
+char* et_img_buf[]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+
+
+struct etss801u_dev {
+ gboolean deactivating;
+};
+
+/*Poll functions (when we awaiting for finger)*/
+void build_poll_cmd(struct et_cmd* cmd)
+{
+ memset(cmd,0,sizeof(*cmd));
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_READ_SHORT;
+ cmd->flag2=0x1A00;
+ cmd->flag4=0xB0;
+ cmd->flag5=0x100;
+ fill_init_cmd(cmd);
+}
+
+int et_read_poll(struct fp_img_dev* dev,struct poll_data* adata)
+{
+ int r;
+
+ struct etss801u_dev* edev=dev->priv;
+ if(edev->deactivating)
+ {
+ complete_deactivation(dev);
+ return 0;
+ }
+ struct libusb_transfer* transfer=libusb_alloc_transfer(0);
+ if(!transfer) return -ENOMEM;
+ libusb_fill_bulk_transfer(transfer,dev->udev,EP_IN,(char*)&ret_buf,8192,et_read_poll_cb,adata,BULK_TIMEOUT);
+ r=libusb_submit_transfer(transfer);
+ if(r<0)
+ {
+ r=-EIO;
+ libusb_free_transfer(transfer);
+ }
+ return r;
+}
+
+static void et_write_poll_cb(struct libusb_transfer* transfer)
+{
+ int r;
+
+ struct poll_data* adata=transfer->user_data;
+ struct fp_img_dev* dev=adata->dev;
+ if(transfer->status!=LIBUSB_TRANSFER_COMPLETED)
+ {
+ libusb_free_transfer(transfer);
+ fpi_imgdev_session_error(dev,-EIO);
+ return;
+ }
+ if(transfer->actual_length!=31)
+ {
+ libusb_free_transfer(transfer);
+ fpi_imgdev_session_error(dev,-EIO);
+ return;
+ }
+ libusb_free_transfer(transfer);
+ r=et_read_poll(dev,adata);
+ if(r)
+ {
+ libusb_free_transfer(transfer);
+ fpi_imgdev_session_error(dev,r);
+ return;
+ }
+}
+
+static void et_read_poll_cb(struct libusb_transfer* transfer)
+{
+ int len;
+ char* br;
+ int r;
+
+ struct poll_data* adata=transfer->user_data;
+ struct fp_img_dev* dev=adata->dev;
+ if(transfer->status!=LIBUSB_TRANSFER_COMPLETED)
+ {
+ /*WORKAROUND NEEDED, SOMETIME ALL FREEZES, RESET DEVICE AND REACTIVATE???*/
+ libusb_free_transfer(transfer);
+ fp_dbg("ERROR");
+ fpi_imgdev_session_error(dev,-EIO);
+ //return;
+ goto _st;
+ }
+ len=transfer->actual_length-13;
+ if(len!=512)
+ {
+ fp_dbg("Invalid return buffer, length: %d",transfer->actual_length);
+ libusb_free_transfer(transfer);
+ fpi_imgdev_session_error(dev,-EPROTO);
+ return;
+ }
+ libusb_free_transfer(transfer);
+ //Check poll cmd result
+ br=(char*)&ret_buf[len];
+ r=et_verify_result(br);
+ if(r)
+ {
+ fp_dbg("Invalid result: %s",print_buf(br));
+ fpi_imgdev_session_error(dev,-EPROTO);
+ return;
+ }
+ //fp_dbg("0x%02hhX,0x%02hhX",ret_buf[0],ret_buf[1]);
+ if((unsigned char)ret_buf[0]==0x82)
+ {
+ if(adata->init->rstage<20)
+ {
+ /*VERY UGLY workaround below, but I don't know how to deal with it.
+ Sometime ret_buf[0] equals 0x82 at the first poll rounds, but
+ really no finger on the scanner
+ */
+ fp_dbg("POLL WORKAROUND");
+ goto _st;
+ }
+ //Finger detected
+ //fp_dbg("FINGER DETECTED!");
+ //fp_dbg("BUF: %s",print_buf(ret_buf));
+ fpi_imgdev_report_finger_status(dev,TRUE);
+ start_capture(dev);
+ return;
+ }
+ //No finger detected
+ _st:
+ adata->init->rstage++;
+ start_finger_detection(dev,adata);
+}
+
+int et_write_poll(struct fp_img_dev* dev,struct poll_data* adata)
+{
+ struct et_cmd ecmd;
+ int r;
+ struct timeval tv;
+
+ build_poll_cmd(&ecmd);
+ struct libusb_transfer* transfer=libusb_alloc_transfer(0);
+ if(!transfer) return -ENOMEM;
+ libusb_fill_bulk_transfer(transfer,dev->udev,EP_OUT,(char*)&cmd_buf,31,et_write_poll_cb,adata,BULK_TIMEOUT);
+ //Wait before write next poll
+ tv.tv_sec=0;
+ tv.tv_usec=700;
+ select(0,NULL,NULL,NULL,&tv);
+ r=libusb_submit_transfer(transfer);
+ if(r<0)
+ {
+ libusb_free_transfer(transfer);
+ r=-EIO;
+ }
+ return r;
+}
+
+
+static void start_finger_detection(struct fp_img_dev *dev,struct poll_data* adata)
+{
+ struct etss801u_dev *etdev = dev->priv;
+ int r;
+
+ if (etdev->deactivating) {
+ complete_deactivation(dev);
+ return;
+ }
+
+ r=et_write_poll(dev,adata);
+ if(r)
+ {
+ fpi_imgdev_session_error(dev,r);
+ }
+}
+
+/*Enroll functions (When we capturing an image)*/
+void build_enroll_cmd(struct et_cmd* cmd,int stage)
+{
+ memset(cmd,0,sizeof(*cmd));
+ switch(stage)
+ {
+ case 1:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x20;
+ cmd->flag3=0x8400;
+ cmd->flag4=0x74;
+ cmd->flag5=0x4110;
+ break;
+
+ case 2:
+ case 3:
+ case 4:
+ case 34:
+ case 39:
+ cmd->flag1=0x600;
+ cmd->cmd=ECMD_READ_LONG;
+ cmd->flag2=0x21;
+ cmd->flag4=0x3;
+ break;
+
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x20;
+ cmd->flag3=0x8400;
+ cmd->flag4=0x1074;
+ cmd->flag5=0x4138;
+ break;
+
+ case 16:
+ cmd->flag1=0x1800;
+ cmd->cmd=ECMD_READ_LONG;
+ cmd->flag2=0x21;
+ cmd->flag4=0x0C;
+ break;
+
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ cmd->flag1=0xF000;
+ cmd->cmd=ECMD_READ_LONG;
+ cmd->flag2=0x21;
+ cmd->flag4=0x78;
+ break;
+
+ case 25:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_READ_SHORT;
+ cmd->flag2=0x1300;
+ cmd->flag3=0x300;
+ cmd->flag5=0x100;
+ break;
+
+ case 26:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_WRITE_SHORT;
+ cmd->flag2=0x2300;
+ cmd->flag3=0x300;
+ cmd->flag5=0x100;
+ break;
+
+ case 27:
+ case 32:
+ case 37:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_READ_SHORT;
+ cmd->flag2=0x1200;
+ cmd->flag4=0x21;
+ cmd->flag5=0x100;
+ break;
+
+ case 28:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_READ_SHORT;
+ cmd->flag2=0x1300;
+ cmd->flag3=0x300;
+ cmd->flag4=0x05;
+ cmd->flag5=0x100;
+ break;
+
+ case 29:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_WRITE_SHORT;
+ cmd->flag2=0x2300;
+ cmd->flag3=0x300;
+ cmd->flag4=0x05;
+ cmd->flag5=0x100;
+ break;
+
+ case 30:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_READ_SHORT;
+ cmd->flag2=0x1300;
+ cmd->flag3=0x300;
+ cmd->flag4=0x04;
+ cmd->flag5=0x100;
+ break;
+
+ case 31:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_WRITE_SHORT;
+ cmd->flag2=0x2300;
+ cmd->flag3=0x300;
+ cmd->flag4=0x04;
+ cmd->flag5=0x100;
+ break;
+
+ case 33:
+ case 38:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x20;
+ cmd->flag3=0x8400;
+ cmd->flag4=0x1074;
+ cmd->flag5=0x4118;
+ break;
+
+ case 35:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x8128;
+ cmd->flag3=0xC400;
+ cmd->flag4=0x5D0;
+ cmd->flag5=0xC0C0;
+ break;
+
+ case 36:
+ case 41:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_READ_SHORT;
+ cmd->flag2=0x1A00;
+ cmd->flag4=0xB0;
+ cmd->flag5=0x100;
+ break;
+
+ case 40:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x8128;
+ cmd->flag3=0xC400;
+ cmd->flag4=0x5B0;
+ cmd->flag5=0xC0C0;
+ break;
+ }
+ fill_init_cmd(cmd);
+}
+
+static void et_write_enroll_cb(struct libusb_transfer* transfer)
+{
+ struct init_data* adata=transfer->user_data;
+
+ if(transfer->status!=LIBUSB_TRANSFER_COMPLETED)
+ {
+ fpi_ssm_mark_aborted(adata->ssm,-EIO);
+ }
+ else if(transfer->length!=transfer->actual_length)
+ {
+ fpi_ssm_mark_aborted(adata->ssm,-EPROTO);
+ }
+ else
+ {
+ switch(adata->init->stage)
+ {
+ case 26:
+ case 29:
+ case 31:
+ if(!adata->init->rstage)
+ {
+ adata->init->rstage++;
+ fpi_ssm_jump_to_state(adata->ssm,adata->init->ssm_state);
+ goto _out;
+ }
+ else
+ {
+ adata->init->rstage=0;
+ goto _wedcbn;
+ }
+ break;
+ }
+ //fp_dbg("(%02d) ->: %s",adata->init->stage,print_cmd_buf());
+ _wedcbn:
+ fpi_ssm_next_state(adata->ssm);
+ }
+ _out:
+ libusb_free_transfer(transfer);
+}
+
+void free_img_buf(void)
+{
+ int i;
+
+ for(i=0;i<8;i++)
+ {
+ if(et_img_buf[i])
+ {
+ g_free(et_img_buf[i]);
+ et_img_buf[i]=NULL;
+ }
+ }
+}
+
+int et_write_enroll_data(struct fp_img_dev* dev,struct et_init* dinit,void* user_data)
+{
+ struct et_cmd ecmd;
+ static struct init_data adata;
+ int r;
+
+ adata.init=dinit;
+ adata.ssm=user_data;
+ build_enroll_cmd(&ecmd,dinit->stage);
+ struct libusb_transfer* transfer=libusb_alloc_transfer(0);
+ if(!transfer) return -ENOMEM;
+ libusb_fill_bulk_transfer(transfer,dev->udev,EP_OUT,(char*)&cmd_buf,31,et_write_enroll_cb,&adata,BULK_TIMEOUT);
+ switch(dinit->stage)
+ {
+ case 5:
+ cmd_buf[22]=0x38;
+ break;
+
+ case 6:
+ cmd_buf[22]=0x50;
+ break;
+
+ case 7:
+ case 10:
+ case 14:
+ cmd_buf[22]=0x68;
+ break;
+
+ case 8:
+ cmd_buf[22]=0x78;
+ break;
+
+ case 9:
+ case 13:
+ cmd_buf[22]=0x70;
+ break;
+
+ case 11:
+ cmd_buf[22]=0x60;
+ break;
+
+ case 12:
+ cmd_buf[22]=0x58;
+ break;
+
+ case 15:
+ cmd_buf[22]=0x80;
+ break;
+
+ /*case 16:
+ et_img_buf[0]=g_malloc(6157);
+ break;*/
+
+ case 17:
+ et_img_buf[0]=g_malloc(61453);
+ break;
+
+ case 18:
+ et_img_buf[1]=g_malloc(61453);
+ break;
+
+ case 19:
+ et_img_buf[2]=g_malloc(61453);
+ break;
+
+ case 20:
+ et_img_buf[3]=g_malloc(61453);
+ break;
+
+ case 21:
+ et_img_buf[4]=g_malloc(61453);
+ break;
+
+ case 22:
+ et_img_buf[5]=g_malloc(61453);
+ break;
+
+ case 23:
+ et_img_buf[6]=g_malloc(61453);
+ break;
+
+ case 24:
+ et_img_buf[7]=g_malloc(61453);
+ break;
+
+ case 26:
+ case 29:
+ case 31:
+ if(adata.init->rstage)
+ {
+ libusb_fill_bulk_transfer(transfer,dev->udev,EP_OUT,(char*)&ret_buf,512,et_write_enroll_cb,&adata,BULK_TIMEOUT);
+ //fp_dbg("Send back 512");
+ }
+ break;
+ }
+ r=libusb_submit_transfer(transfer);
+ if(r<0)
+ {
+ libusb_free_transfer(transfer);
+ r=-EIO;
+ }
+ return r;
+}
+
+int et_verify_enroll_data(struct et_init* dinit,int len)
+{
+ int rlen;
+
+ switch(dinit->stage)
+ {
+ case 2:
+ case 3:
+ case 4:
+ case 34:
+ case 39:
+ rlen=1536;
+ if(len!=rlen) goto _eved;
+ break;
+
+ case 16:
+ rlen=6144;
+ if(len!=rlen) goto _eved;
+ break;
+
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ rlen=61440;
+ if(len!=rlen) goto _eved;
+ break;
+
+ case 25:
+ case 27:
+ case 28:
+ case 30:
+ case 32:
+ case 36:
+ case 37:
+ case 41:
+ rlen=512;
+ if(len!=rlen) goto _eved;
+ break;
+
+ //1,5 - 15,26,29,31,33,35,38,40 - skip, no data returned
+ }
+ return 0;
+
+ _eved:
+ fp_dbg("Invalid answer data length: %d received, must be %d\n",len,rlen);
+ return -EPROTO;
+}
+
+static void et_read_enroll_cb(struct libusb_transfer* transfer)
+{
+ int r;
+ int len;
+ int comb=0; //Combined buffer (data+result) flag
+ char* result;
+
+
+ struct init_data* adata=transfer->user_data;
+ if(transfer->status!=LIBUSB_TRANSFER_COMPLETED)
+ {
+ fpi_ssm_mark_aborted(adata->ssm,-EIO);
+ }
+ else
+ {
+ if((transfer->actual_length%2) && transfer->actual_length!=13) comb=1;
+ if(comb)
+ {
+ len=transfer->actual_length-13;
+ //fp_dbg("<-: Read %d (combined)",transfer->actual_length-13);
+ }
+ else
+ {
+ len=transfer->actual_length;
+ //fp_dbg("<-: Read %d",transfer->actual_length);
+ }
+ //Data buffer received
+ if(len!=13) r=et_verify_enroll_data(adata->init,len);
+ else
+ {
+ //fp_dbg("Result: %s",print_buf(ret_buf));
+ r=et_verify_result(ret_buf);
+ if(r) goto _erv;
+ goto _ern;
+ }
+ //fp_dbg("verified");
+ if(r)
+ {
+ _erv:
+ fpi_ssm_mark_aborted(adata->ssm,r);
+ goto _eret;
+ }
+ adata->init->rstage++;
+ if(!comb && len!=13)
+ {
+ fp_dbg("We should not be here!");
+ fpi_ssm_mark_aborted(adata->ssm,-EPROTO);
+ //fpi_ssm_jump_to_state(adata->ssm,adata->init->ssm_state); //Jump back, and receive result
+ }
+ else
+ {
+ //Result received at the end of data
+ switch(adata->init->stage)
+ {
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ //fp_dbg("Piece %d: %s",(adata->init->stage-17)+1,print_buf(et_img_buf[adata->init->stage-17]));
+ result=(char*)&et_img_buf[adata->init->stage-17][len];
+ break;
+
+ default:
+ result=(char*)&ret_buf[len];
+ break;
+ }
+ r=et_verify_result(result);
+ if(r) goto _erv;
+ _ern:
+ adata->init->rstage=0;
+ adata->init->stage++;
+ fpi_ssm_next_state(adata->ssm);
+ }
+ }
+ _eret:
+ libusb_free_transfer(transfer);
+}
+
+int et_read_enroll_data(struct fp_img_dev* dev,struct et_init* dinit,void* user_data)
+{
+ int r;
+ static struct init_data adata;
+
+ struct etss801u_dev* edev=dev->priv;
+ if(edev->deactivating)
+ {
+ complete_deactivation(dev);
+ return 0;
+ }
+ adata.init=dinit;
+ adata.ssm=user_data;
+ struct libusb_transfer* transfer=libusb_alloc_transfer(0);
+ if(!transfer) return -ENOMEM;
+ switch(dinit->stage)
+ {
+ /*case 16:
+ libusb_fill_bulk_transfer(transfer,dev->udev,EP_IN,et_img_buf[dinit->stage-16],6157,et_read_enroll_cb,&adata,BULK_TIMEOUT);
+ break;*/
+
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ libusb_fill_bulk_transfer(transfer,dev->udev,EP_IN,et_img_buf[dinit->stage-17],61453,et_read_enroll_cb,&adata,BULK_TIMEOUT);
+ break;
+
+ default:
+ libusb_fill_bulk_transfer(transfer,dev->udev,EP_IN,(char*)&ret_buf,8192,et_read_enroll_cb,&adata,BULK_TIMEOUT);
+ break;
+ }
+ r=libusb_submit_transfer(transfer);
+ if(r<0)
+ {
+ r=-EIO;
+ libusb_free_transfer(transfer);
+ }
+ return r;
+}
+
+static void capture_run_state(struct fpi_ssm *ssm)
+{
+ struct fp_img_dev *dev = ssm->priv;
+ int r;
+
+ switch(ssm->cur_state)
+ {
+ case 0:
+ //fp_dbg("Initializing before get image data");
+ memset(&einit,0,sizeof(struct et_init));
+ einit.stage=1;
+ case 2:
+ case 4:
+ case 6:
+ case 8:
+ case 10:
+ case 12:
+ case 14:
+ case 16:
+ case 18:
+ case 20:
+ case 22:
+ case 24:
+ case 26:
+ case 28:
+ case 30:
+ case 32:
+ //fp_dbg("Get image from scanner");
+ case 34:
+ case 36:
+ case 38:
+ case 40:
+ case 42:
+ case 44:
+ case 46:
+ goto _castate;
+ case 48:
+ fp_dbg("Image captured, send stop and reinit");
+ case 50:
+ case 52:
+ case 54:
+ case 56:
+ case 58:
+ case 60:
+ case 62:
+ case 64:
+ case 66:
+ case 68:
+ case 70:
+ case 72:
+ case 74:
+ case 76:
+ case 78:
+ case 80:
+ _castate:
+ einit.ssm_state=ssm->cur_state;
+ r=et_write_enroll_data(dev,&einit,ssm);
+ if(r)
+ {
+ _cabort:
+ fpi_ssm_mark_aborted(ssm,r);
+ }
+ break;
+
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ case 9:
+ case 11:
+ case 13:
+ case 15:
+ case 17:
+ case 19:
+ case 21:
+ case 23:
+ case 25:
+ case 27:
+ case 29:
+ case 31:
+ case 33:
+ case 35:
+ case 37:
+ case 39:
+ case 41:
+ case 43:
+ case 45:
+ case 47:
+ case 49:
+ case 51:
+ case 53:
+ case 55:
+ case 57:
+ case 59:
+ case 61:
+ case 63:
+ case 65:
+ case 67:
+ case 69:
+ case 71:
+ case 73:
+ case 75:
+ case 77:
+ case 79:
+ case 81:
+ r=et_read_enroll_data(dev,&einit,ssm);
+ if(r) goto _cabort;
+ break;
+ }
+}
+
+
+char* et_get_row(char* ibuf,int num)
+{
+ return (char*)&ibuf[768*4*num];
+}
+
+void et_assemble_image(struct fp_img_dev* dev)
+{
+ //size_t sz=(61440/4)*8;
+ //size_t sz=(61440*8)+6144;
+ size_t sz=(192*160);
+ //size_t sz=(61440/2)*8;
+ //size_t sz=320*384;
+ struct fp_img* img;
+ int pos=0;
+ char* p;
+
+ img=fpi_img_new(sz);
+ //img->flags=FP_IMG_COLORS_INVERTED;
+ img->flags=FP_IMG_STANDARDIZATION_FLAGS;
+ for(int i=0;i<8;i++)
+ {
+ for(int x=0;x<20;x++)
+ {
+ p=et_get_row(et_img_buf[i],x);
+ for(int y=0;y<768;y+=4,pos++)
+ {
+ img->data[pos]=p[y];
+ }
+ }
+
+ /*if(i)
+ {
+ memcpy(&img->data[pos],et_img_buf[i],61440);
+ pos+=61440;
+ }
+ else
+ {
+ memcpy(&img->data[pos],et_img_buf[i],6144);
+ pos+=6144;
+ }*/
+ /*for(int x=0;x<61440;x+=4,pos++)
+ {
+ img->data[pos]=et_img_buf[i][x];
+ } */
+
+ /*for(int x=0;x<61440;x+=2,pos++)
+ {
+ img->data[pos]=et_img_buf[i][x];
+ }*/
+
+ /*for(int x=0;x<61440;x+=2,pos++)
+ {
+ if(x && !(x%384))
+ {
+ x+=384; //continue;
+ }
+ img->data[pos]=et_img_buf[i][x];
+ }*/
+ }
+ fpi_imgdev_image_captured(dev,img);
+ free_img_buf();
+}
+
+static void capture_sm_complete(struct fpi_ssm *ssm)
+{
+ static struct poll_data adata;
+ struct fp_img_dev *dev = ssm->priv;
+ struct etss801u_dev *etdev = dev->priv;
+
+ fp_dbg("");
+ if (etdev->deactivating)
+ complete_deactivation(dev);
+ else if (ssm->error)
+ fpi_imgdev_session_error(dev, ssm->error);
+ else
+ /*Done finger enrolling, assemble image and give it to library*/
+ et_assemble_image(dev);
+ fpi_imgdev_report_finger_status(dev, FALSE);
+ memset(&einit,0,sizeof(struct et_init));
+ adata.dev=(struct fp_img_dev*)dev;
+ adata.init=&einit;
+ start_finger_detection(dev,&adata);
+ fpi_ssm_free(ssm);
+}
+
+static void start_capture(struct fp_img_dev *dev)
+{
+ struct etss801u_dev *etdev = dev->priv;
+ struct fpi_ssm *ssm;
+
+ if (etdev->deactivating) {
+ complete_deactivation(dev);
+ return;
+ }
+
+ ssm = fpi_ssm_new(dev->dev, capture_run_state, ET_CAPTURE_STATES);
+ fp_dbg("");
+ ssm->priv = dev;
+ fpi_ssm_start(ssm, capture_sm_complete);
+}
+
+
+/*Initialization function (when initializing device before waiting finger)*/
+void build_init_cmd(struct et_cmd* cmd,int stage)
+{
+ memset(cmd,0,sizeof(*cmd));
+ switch(stage)
+ {
+ case 1: //1
+ case 37:
+ case 38:
+ cmd->flag1=0x50;
+ cmd->cmd=ECMD_GETIDENT;
+ cmd->flag3=0x5000;
+ break;
+
+ case 2: //2,4,6
+ case 4:
+ case 6:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_READ_SHORT;
+ cmd->flag2=0x1300;
+ cmd->flag3=0x300;
+ cmd->flag4=0x07;
+ cmd->flag5=0x100;
+ break;
+
+ case 3: //3,5,11,15
+ case 5:
+ case 11:
+ case 15:
+ case 36:
+ case 44:
+ case 50:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_WRITE_SHORT;
+ cmd->flag2=0x2300;
+ cmd->flag3=0x300;
+ cmd->flag4=0x04;
+ cmd->flag5=0x100;
+ break;
+
+ case 7:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_WRITE_SHORT;
+ cmd->flag2=0x2300;
+ cmd->flag3=0x1000;
+ cmd->flag4=0x0F;
+ cmd->flag5=0x100;
+ break;
+
+ case 8:
+ cmd->flag1=0x20;
+ cmd->cmd=ECMD_GETNSTRING;
+ cmd->flag3=0xFF01;
+ cmd->flag6=0x01;
+ break;
+
+ case 9:
+ cmd->flag1=0x20;
+ cmd->cmd=ECMD_GETNSTRING;
+ cmd->flag3=0x9F01;
+ cmd->flag6=0x301;
+ break;
+
+ case 10:
+ case 14:
+ case 35:
+ case 43:
+ case 49:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_READ_SHORT;
+ cmd->flag2=0x1300;
+ cmd->flag3=0x300;
+ cmd->flag4=0x04;
+ cmd->flag5=0x100;
+ break;
+
+ case 12:
+ case 41:
+ case 47:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_READ_SHORT;
+ cmd->flag2=0x1300;
+ cmd->flag3=0x300;
+ cmd->flag4=0x05;
+ cmd->flag5=0x100;
+ break;
+
+ case 13:
+ case 42:
+ case 48:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_WRITE_SHORT;
+ cmd->flag2=0x2300;
+ cmd->flag3=0x300;
+ cmd->flag4=0x05;
+ cmd->flag5=0x100;
+ break;
+
+ case 16:
+ case 45:
+ case 51:
+ case 56:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_READ_SHORT;
+ cmd->flag2=0x1200;
+ cmd->flag4=0x21;
+ cmd->flag5=0x100;
+ break;
+
+ case 17:
+ case 46:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_WRITE_SHORT;
+ cmd->flag2=0x2200;
+ cmd->flag4=0x21;
+ cmd->flag5=0x100;
+ break;
+
+ case 18:
+ case 52:
+ case 57:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x20;
+ cmd->flag3=0x8400;
+ cmd->flag4=0x1074;
+ cmd->flag5=0x4118;
+ break;
+
+ case 19:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x20;
+ cmd->flag3=0x8400;
+ cmd->flag4=0x74;
+ cmd->flag5=0x4110;
+ break;
+
+ case 20:
+ case 22:
+ case 24:
+ case 26:
+ case 28:
+ case 30:
+ case 32:
+ case 34:
+ case 53:
+ case 58:
+ cmd->flag1=0x600;
+ cmd->cmd=ECMD_READ_LONG;
+ cmd->flag2=0x21;
+ cmd->flag4=0x3;
+ break;
+
+ case 21:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x20;
+ cmd->flag3=0x8400;
+ cmd->flag4=0x78;
+ cmd->flag5=0x4110;
+ break;
+
+ case 23:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x20;
+ cmd->flag3=0x8400;
+ cmd->flag4=0x1078;
+ cmd->flag5=0x4118;
+ break;
+
+ case 25:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x20;
+ cmd->flag3=0x8400;
+ cmd->flag4=0x2078;
+ cmd->flag5=0x4120;
+ break;
+
+ case 27:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x20;
+ cmd->flag3=0x8400;
+ cmd->flag4=0x3078;
+ cmd->flag5=0x4128;
+ break;
+
+ case 29:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x20;
+ cmd->flag3=0x8400;
+ cmd->flag4=0x4078;
+ cmd->flag5=0x4130;
+ break;
+
+ case 31:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x20;
+ cmd->flag3=0x8400;
+ cmd->flag4=0x5078;
+ cmd->flag5=0x4138;
+ break;
+
+ case 33:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x20;
+ cmd->flag3=0x8400;
+ cmd->flag4=0x6078;
+ cmd->flag5=0x4140;
+ break;
+
+ case 39:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_READ_SHORT;
+ cmd->flag2=0x1300;
+ cmd->flag3=0x300;
+ cmd->flag5=0x100;
+ break;
+
+ case 40:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_WRITE_SHORT;
+ cmd->flag2=0x2300;
+ cmd->flag3=0x300;
+ cmd->flag5=0x100;
+ break;
+
+ case 54:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x8128;
+ cmd->flag3=0xC400;
+ cmd->flag4=0x5D0;
+ cmd->flag5=0xC0C0;
+ break;
+
+ case 55:
+ cmd->flag1=0x200;
+ cmd->cmd=ECMD_READ_SHORT;
+ cmd->flag2=0x1A00;
+ cmd->flag4=0xB0;
+ cmd->flag5=0x100;
+ break;
+
+ case 59:
+ cmd->cmd=ECMD_SETREG;
+ cmd->flag2=0x8128;
+ cmd->flag3=0xC400;
+ cmd->flag4=0x5B0;
+ cmd->flag5=0xC0C0;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void fill_init_cmd(struct et_cmd* cmd)
+{
+ char* p;
+
+ p=&cmd_buf[8];
+ memcpy(p,&cmd->flag1,2);
+ p+=6;
+ memcpy(p,&cmd->cmd,2);
+ p+=2;
+ memcpy(p,&cmd->flag2,2);
+ p+=2;
+ memcpy(p,&cmd->flag3,2);
+ p+=2;
+ memcpy(p,&cmd->flag4,2);
+ p+=2;
+ memcpy(p,&cmd->flag5,2);
+ p+=2;
+ memcpy(p,&cmd->flag6,2);
+ p+=2;
+}
+
+int et_write_init(struct fp_img_dev* dev,struct et_init* dinit,void* user_data)
+{
+ struct et_cmd ecmd;
+ static struct init_data adata;
+ int r;
+
+ adata.init=dinit;
+ adata.ssm=user_data;
+ build_init_cmd(&ecmd,dinit->stage);
+ fill_init_cmd(&ecmd);
+ //Send command to device
+ struct libusb_transfer* transfer=libusb_alloc_transfer(0);
+ if(!transfer) return -ENOMEM;
+ switch(dinit->stage)
+ {
+ case 3:
+ case 36:
+ ret_buf[0]=0x48;
+ goto _evi_w;
+ case 5:
+ case 7:
+ ret_buf[0]=0x0C;
+ goto _evi_w;
+ case 11:
+ case 40:
+ case 42:
+ case 48:
+ case 50:
+ goto _evi_w;
+ case 13:
+ ret_buf[0]=0x23;
+ goto _evi_w;
+ case 15:
+ case 44:
+ ret_buf[0]=0x4D;
+ goto _evi_w;
+ case 17:
+ ret_buf[0]=0x52;
+ goto _evi_w;
+ case 46:
+ ret_buf[0]=0x42;
+ _evi_w:
+ if(!dinit->rstage)
+ libusb_fill_bulk_transfer(transfer,dev->udev,EP_OUT,(char*)&cmd_buf,31,et_write_init_cb,&adata,BULK_TIMEOUT);
+ else
+ {
+ //fp_dbg("ret_buf: 0x%02hhX",ret_buf[0]);
+ libusb_fill_bulk_transfer(transfer,dev->udev,EP_OUT,(char*)&ret_buf,512,et_write_init_cb,&adata,BULK_TIMEOUT);
+ }
+ break;
+
+ default:
+ libusb_fill_bulk_transfer(transfer,dev->udev,EP_OUT,(char*)&cmd_buf,31,et_write_init_cb,&adata,BULK_TIMEOUT);
+ break;
+ }
+ //fp_dbg("->: %s",print_cmd_buf());
+ r=libusb_submit_transfer(transfer);
+ if(r<0)
+ {
+ libusb_free_transfer(transfer);
+ r=-EIO;
+ }
+ return r;
+}
+
+static void et_write_init_cb(struct libusb_transfer* transfer)
+{
+ struct init_data* adata=transfer->user_data;
+ if(transfer->status!=LIBUSB_TRANSFER_COMPLETED)
+ {
+ fpi_ssm_mark_aborted(adata->ssm,-EIO);
+ }
+ else if(transfer->length!=transfer->actual_length)
+ {
+ fpi_ssm_mark_aborted(adata->ssm,-EPROTO);
+ }
+ else
+ {
+ switch(adata->init->stage)
+ {
+ case 3:
+ case 5:
+ case 7:
+ case 11:
+ case 13:
+ case 15:
+ case 17:
+ case 36:
+ case 40:
+ case 42:
+ case 44:
+ case 46:
+ case 48:
+ case 50:
+ if(!adata->init->rstage)
+ {
+ //fp_dbg("(%02d) ->: %s",adata->init->stage,print_cmd_buf());
+ adata->init->rstage++;
+ fpi_ssm_jump_to_state(adata->ssm,adata->init->ssm_state);
+ goto _wicb;
+ }
+ else
+ {
+ adata->init->rstage=0;
+ //fp_dbg("(%02d) ->: RETURN BUF %d",adata->init->stage,transfer->actual_length);
+ goto _wicbn;
+ }
+ break;
+ }
+ //fp_dbg("(%02d) ->: %s",adata->init->stage,print_cmd_buf());
+ _wicbn:
+ fpi_ssm_next_state(adata->ssm);
+ }
+ _wicb:
+ libusb_free_transfer(transfer);
+}
+
+int et_read_answer(struct fp_img_dev* dev,struct et_init* dinit,void* user_data)
+{
+ int r;
+ static struct init_data adata;
+
+ adata.init=dinit;
+ adata.ssm=user_data;
+ struct libusb_transfer* transfer=libusb_alloc_transfer(0);
+ if(!transfer) return -ENOMEM;
+ libusb_fill_bulk_transfer(transfer,dev->udev,EP_IN,(char*)&ret_buf,8192,et_read_answer_cb,&adata,BULK_TIMEOUT);
+ r=libusb_submit_transfer(transfer);
+ if(r<0)
+ {
+ r=-EIO;
+ libusb_free_transfer(transfer);
+ }
+ return r;
+}
+
+char* print_cmd_buf(void)
+{
+ static char result[512];
+ char* p;
+
+ int i;
+ p=(char*)&result[0];
+ for(i=8;i<26;i++)
+ {
+ if(i!=8)
+ {
+ sprintf(p,",");
+ p++;
+ p[0]=0;
+ }
+ sprintf(p,"0x%02hhX",cmd_buf[i]);
+ p+=4;
+ p[0]=0;
+ }
+ return (char*)result;
+}
+
+char* print_buf(char* buf)
+{
+ static char result[512];
+ char* p;
+
+ int i;
+ p=(char*)&result[0];
+ for(i=0;i<13;i++)
+ {
+ if(i)
+ {
+ sprintf(p,",");
+ p++;
+ p[0]=0;
+ }
+ sprintf(p,"0x%02hhX",buf[i]);
+ p+=4;
+ p[0]=0;
+ }
+ return (char*)result;
+}
+
+
+static void et_read_answer_cb(struct libusb_transfer* transfer)
+{
+ int r;
+ int len;
+ int comb=0; //Combined buffer (answer+data) flag
+ char* result;
+
+
+ struct init_data* adata=transfer->user_data;
+ if(transfer->status!=LIBUSB_TRANSFER_COMPLETED)
+ {
+ fpi_ssm_mark_aborted(adata->ssm,-EIO);
+ }
+ else
+ {
+ if((transfer->actual_length%2) && transfer->actual_length!=13) comb=1;
+ if(comb)
+ {
+ len=transfer->actual_length-13;
+ //fp_dbg("<-: Read %d (combined)",transfer->actual_length-13);
+ }
+ else
+ {
+ len=transfer->actual_length;
+ //fp_dbg("<-: Read %d",transfer->actual_length);
+ }
+ if(!adata->init->rstage)
+ {
+ //Data buffer received
+ if(len!=13) r=et_verify_answer(adata->init,len);
+ else
+ {
+ //fp_dbg("Result: %s",print_buf(ret_buf));
+ r=et_verify_result(ret_buf);
+ if(r) goto _erv;
+ goto _ern;
+ }
+ //fp_dbg("verified");
+ if(r)
+ {
+ _erv:
+ fpi_ssm_mark_aborted(adata->ssm,r);
+ goto _eret;
+ }
+ adata->init->rstage++;
+ if(!comb && len!=13) fpi_ssm_jump_to_state(adata->ssm,adata->init->ssm_state); //Jump back, and receive result
+ else
+ {
+ //Result received at the end of data
+ result=(char*)&ret_buf[len];
+ r=et_verify_result(result);
+ if(r) goto _erv;
+ _ern:
+ adata->init->rstage=0;
+ adata->init->stage++;
+ fpi_ssm_next_state(adata->ssm);
+ }
+ }
+ else
+ {
+ //Result received
+ if(len!=13) { r=-EPROTO; goto _erv; }
+ r=et_verify_result(ret_buf);
+ if(r) goto _erv;
+ adata->init->stage++;
+ adata->init->rstage=0;
+ fpi_ssm_next_state(adata->ssm);
+ }
+ }
+ _eret:
+ libusb_free_transfer(transfer);
+}
+
+int et_verify_answer(struct et_init* dinit,int len)
+{
+ int rlen;
+
+ switch(dinit->stage)
+ {
+ case 1:
+ case 37:
+ case 38:
+ rlen=80;
+ if(len!=rlen) goto _eva;
+ //fp_dbg("verify: %d",dinit->ssm_state);
+ break;
+
+ case 2:
+ case 4:
+ case 6:
+ case 10:
+ case 12:
+ case 14:
+ case 16:
+ case 35:
+ case 39:
+ case 41:
+ case 43:
+ case 45:
+ case 47:
+ case 49:
+ case 51:
+ case 55:
+ case 56:
+ //fp_dbg("verify: len %d",len);
+ rlen=512;
+ if(len!=rlen) goto _eva;
+ break;
+
+ /*3,5,7,11,13,15,17,18,19,21,23,25,27,29,31,33,36,40,42,44,46,48,50,52,54,57,59 - only result
+ */
+
+ case 8:
+ case 9:
+ rlen=32;
+ if(len!=rlen) goto _eva;
+ break;
+
+ case 20:
+ case 22:
+ case 24:
+ case 26:
+ case 28:
+ case 30:
+ case 32:
+ case 34:
+ case 53:
+ case 58:
+ rlen=1536;
+ if(len!=rlen) goto _eva;
+ break;
+
+ }
+ return 0;
+
+ _eva:
+ fp_dbg("Invalid answer data length: %d received, must be %d\n",len,rlen);
+ return -EPROTO;
+}
+
+int et_verify_result(char* result)
+{
+ char vresult[]={0,0,0,0,0};
+ char ah[]={ET_ANS_HDR};
+ char pd[]={ET_BUF_PDATA};
+ char* v;
+
+ v=(char*)&result[0];
+ if(memcmp(v,ah,4)) goto _evr;
+ v=(char*)&result[4];
+ if(memcmp(v,pd,4)) goto _evr;
+ v=(char*)&result[8];
+ if(memcmp(v,vresult,5)) goto _evr;
+ return 0;
+
+ _evr:
+ fp_dbg("Invalid command result: %s",print_buf(result));
+ return -EPROTO;
+}
+
+static void activate_run_state(struct fpi_ssm *ssm)
+{
+ int r;
+ struct fp_img_dev *dev = ssm->priv;
+
+ /* Activation process of SS801U is not understandable at
+ the moment. Simply repeats captured protocol.
+ And, I don't know how to enter in initial state without device reset
+ */
+ switch (ssm->cur_state)
+ {
+ case 0:
+ //Reset device
+ libusb_release_interface(dev->udev,0);
+ r=libusb_reset_device(dev->udev);
+ if(r<0)
+ {
+ _eop:
+ fpi_ssm_mark_aborted(ssm,r);
+ return;
+ }
+ r=libusb_claim_interface(dev->udev,0);
+ if(r) goto _eop;
+ memset(&einit,0,sizeof(struct et_init));
+ einit.stage=1;
+ case 2:
+ case 4:
+ case 6:
+ case 8:
+ case 10:
+ case 12:
+ case 14:
+ case 16:
+ case 18:
+ case 20:
+ case 22:
+ case 24:
+ case 26:
+ case 28:
+ case 30:
+ case 32:
+ case 34:
+ case 36:
+ case 38:
+ case 40:
+ case 42:
+ case 44:
+ case 46:
+ case 48:
+ case 50:
+ case 52:
+ case 54:
+ case 56:
+ case 58:
+ case 60:
+ case 62:
+ case 64:
+ case 66:
+ case 68:
+ case 70:
+ case 72:
+ case 74:
+ case 76:
+ case 78:
+ case 80:
+ case 82:
+ case 84:
+ case 86:
+ case 88:
+ case 90:
+ case 92:
+ case 94:
+ case 96:
+ case 98:
+ case 100:
+ case 102:
+ case 104:
+ case 106:
+ case 108:
+ case 110:
+ case 112:
+ case 114:
+ case 116:
+ einit.ssm_state=ssm->cur_state;
+ r=et_write_init(dev,&einit,ssm);
+ if(r)
+ {
+ _mabort:
+ fpi_ssm_mark_aborted(ssm,r);
+ }
+ break;
+
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ case 9:
+ case 11:
+ case 13:
+ case 15:
+ case 17:
+ case 19:
+ case 21:
+ case 23:
+ case 25:
+ case 27:
+ case 29:
+ case 31:
+ case 33:
+ case 35:
+ case 37:
+ case 39:
+ case 41:
+ case 43:
+ case 45:
+ case 47:
+ case 49:
+ case 51:
+ case 53:
+ case 55:
+ case 57:
+ case 59:
+ case 61:
+ case 63:
+ case 65:
+ case 67:
+ case 69:
+ case 71:
+ case 73:
+ case 75:
+ case 77:
+ case 79:
+ case 81:
+ case 83:
+ case 85:
+ case 87:
+ case 89:
+ case 91:
+ case 93:
+ case 95:
+ case 97:
+ case 99:
+ case 101:
+ case 103:
+ case 105:
+ case 107:
+ case 109:
+ case 111:
+ case 113:
+ case 115:
+ case 117:
+ einit.ssm_state=ssm->cur_state;
+ r=et_read_answer(dev,&einit,ssm);
+ if(r) goto _mabort;
+ break;
+
+ }
+}
+
+/* jump to finger detection */
+static void activate_sm_complete(struct fpi_ssm *ssm)
+{
+ static struct poll_data adata;
+
+ struct fp_img_dev *dev = ssm->priv;
+ fp_dbg("status %d", ssm->error);
+ fpi_imgdev_activate_complete(dev, ssm->error);
+
+ if (!ssm->error)
+ memset(&einit,0,sizeof(struct et_init));
+ adata.dev=(struct fp_img_dev*)dev;
+ adata.init=&einit;
+ start_finger_detection(dev,&adata);
+ fpi_ssm_free(ssm);
+}
+
+static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
+{
+ struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,ET_ACTIVATE_STATES);
+ ssm->priv = dev;
+ fpi_ssm_start(ssm, activate_sm_complete);
+ return 0;
+}
+
+static void dev_deactivate(struct fp_img_dev *dev)
+{
+ struct etss801u_dev *etdev = dev->priv;
+ etdev->deactivating = TRUE;
+}
+
+static void complete_deactivation(struct fp_img_dev *dev)
+{
+ struct etss801u_dev *etdev = dev->priv;
+ fp_dbg("");
+ etdev->deactivating = FALSE;
+ fpi_imgdev_deactivate_complete(dev);
+}
+
+static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
+{
+ int r;
+
+ r = libusb_claim_interface(dev->udev, 0);
+ if (r < 0) {
+ fp_err("could not claim interface 0");
+ return r;
+ }
+
+ //dev->dev->nr_enroll_stages=3;
+
+ dev->priv = g_malloc0(sizeof(struct etss801u_dev));
+ fpi_imgdev_open_complete(dev, 0);
+ return 0;
+}
+
+static void dev_deinit(struct fp_img_dev *dev)
+{
+ g_free(dev->priv);
+ libusb_release_interface(dev->udev, 0);
+ fpi_imgdev_close_complete(dev);
+}
+
+static const struct usb_id id_table[] = {
+ { .vendor = 0x1c7a, .product = 0x0801 }, /* EgisTec SS801U */
+ { 0, 0, 0, },
+};
+
+struct fp_img_driver etss801u_driver = {
+ .driver = {
+ .id = 19, //I take first free number, but at final, developer's decision needed.
+ .name = FP_COMPONENT,
+ .full_name = "EgisTec SS801U",
+ .id_table = id_table,
+ .scan_type = FP_SCAN_TYPE_SWIPE,
+ },
+ .flags = 0,
+ //.img_height = 640,
+ .img_height = 160,
+ .img_width = 192,
+ //.img_width = 768, //Still in doubt, maybe 192
+ //.img_width = 192,
+ //.img_width = 384,
+
+ .bz3_threshold = 19,
+
+ .open = dev_init,
+ .close = dev_deinit,
+ .activate = dev_activate,
+ .deactivate = dev_deactivate,
+};
diff --git a/libfprint/drivers/etss801u.h b/libfprint/drivers/etss801u.h
new file mode 100644
index 0000000..73c8938
--- /dev/null
+++ b/libfprint/drivers/etss801u.h
@@ -0,0 +1,128 @@
+#ifndef __ESS801U_H_
+#define __ESS801U_H_
+
+//Answer buffer header
+#define ET_ANS_HDR 0x55,0x53,0x42,0x53
+//Command buffer header
+#define ET_CMD_HDR 0x55,0x53,0x42,0x43
+//Buffer permanent data (immediately after header on both command and answer)
+#define ET_BUF_PDATA 0x08,0x90,0xf1,0x81
+
+//Commands
+#define ECMD_GETIDENT 0x120C //Get device identification???
+#define ECMD_READ_SHORT 0xD20C //Request a short buffer (512 bytes length) with unknown data
+#define ECMD_WRITE_SHORT 0xDA0C //Writes back a short buffer received by ECMD_READ_SHORT (maybe changed first byte, but not always)
+#define ECMD_GETNSTRING 0xD30C //Get device name string???
+#define ECMD_SETREG 0xCF0A //Set register??? Purpose totally unknown, return buffer length always 13 (command result)
+#define ECMD_READ_LONG 0xCF06
+/*Request a long buffer (1536 bytes length) with unknown data or pre-enroll buffer (6144 bytes length)
+ or enroll buffer (61440 bytes length)*/
+#define ECMD_READ_LONG 0xCF06
+
+/*
+Structure of SS801U command: (As I see it, maybe wrong)
+1. Header 4 bytes (see above)
+2. Permanent data 4 bytes (see above)
+3. Flag1 2 bytes (Need to initialize)
+4. Empty data 4 bytes
+5. Command 2 bytes (Need to initialize)
+6. Flag2 2 bytes (Need to initialize)
+7. Flag3 2 bytes (Need to initialize)
+8. Flag4 2 bytes (Need to initialize)
+9. Flag5 2 bytes (Need to initialize)
+10. Flag6 2 bytes (Need to initialize)
+11. Empty data 5 bytes
+TOTAL: 31 bytes
+*/
+
+struct et_cmd
+{
+ unsigned short flag1; //Two bytes after header and permanent data
+ unsigned short cmd; //I think, this is command.
+ unsigned short flag2; //
+ unsigned short flag3; //
+ unsigned short flag4; //I don't know what is it...
+ unsigned short flag5; //
+ unsigned short flag6; //
+};
+
+
+struct et_init
+{
+ int ssm_state;
+ int stage; //Command stage (0 to 59)
+ int rstage; //Flag for buffer received and confirmed by 13 bytes answer buffer
+};
+
+
+struct init_data
+{
+ struct et_init* init;
+ struct fpi_ssm* ssm;
+};
+
+struct poll_data
+{
+ struct fp_img_dev* dev;
+ struct et_init* init;
+};
+
+/*Number of stages of initialization process before we can begin
+waiting for finger*/
+#define ET_ACTIVATE_STATES 118
+#define ET_CAPTURE_STATES 82
+
+//FOR DEBUG, MUST BE REMOVED!
+char* print_cmd_buf(void);
+char* print_buf(char* buf);
+
+static void start_capture(struct fp_img_dev *dev);
+static void complete_deactivation(struct fp_img_dev *dev);
+
+char* et_get_row(char* ibuf,int num);
+void build_init_cmd(struct et_cmd* cmd,int stage);
+void fill_init_cmd(struct et_cmd* cmd);
+void build_enroll_cmd(struct et_cmd* cmd,int stage);
+void build_poll_cmd(struct et_cmd* cmd);
+void free_img_buf(void);
+
+static void et_write_init_cb(struct libusb_transfer* transfer);
+static void et_read_answer_cb(struct libusb_transfer* transfer);
+static void et_write_poll_cb(struct libusb_transfer* transfer);
+static void et_read_poll_cb(struct libusb_transfer* transfer);
+static void et_write_enroll_cb(struct libusb_transfer* transfer);
+static void et_read_enroll_cb(struct libusb_transfer* transfer);
+
+/*
+Parameters:
+dev - device
+init - stage information
+user_data - init_data
+*/
+int et_write_init(struct fp_img_dev* dev,struct et_init* dinit,void* user_data);
+/*
+Parameters:
+dev - device
+init - stage information
+user_data - init_data
+*/
+int et_read_answer(struct fp_img_dev* dev,struct et_init* dinit,void* user_data);
+int et_write_poll(struct fp_img_dev* dev,struct poll_data* adata);
+int et_read_poll(struct fp_img_dev* dev,struct poll_data* adata);
+/*
+Parameters:
+dev - device
+init - stage information
+user_data - init_data
+*/
+int et_write_enroll_data(struct fp_img_dev* dev,struct et_init* dinit,void* user_data);
+int et_read_enroll_data(struct fp_img_dev* dev,struct et_init* dinit,void* user_data);
+/*Verifies answer buffer for validity (enroll)*/
+int et_verify_enroll_data(struct et_init* dinit,int len);
+/*Verifies answer buffer for validity (device init)*/
+int et_verify_answer(struct et_init* dinit,int len);
+/*Verifies transfer result*/
+int et_verify_result(char* result);
+
+static void start_finger_detection(struct fp_img_dev *dev,struct poll_data* adata);
+#endif /*__ESS801U_H_*/
diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h
index e309ea9..05759c5 100644
--- a/libfprint/fp_internal.h
+++ b/libfprint/fp_internal.h
@@ -305,6 +305,9 @@ extern struct fp_img_driver upektc_img_driver;
#ifdef ENABLE_ETES603
extern struct fp_img_driver etes603_driver;
#endif
+#ifdef ENABLE_ETSS801U
+extern struct fp_img_driver etss801u_driver;
+#endif
#ifdef ENABLE_VFS0050
extern struct fp_img_driver vfs0050_driver;
#endif
@jouyouyun
Copy link
Author

This patch base the commit d82847a6b4bbd2864388f2bf8e6a2b9d1aed05c4 (tag: V_0_7_0)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment