12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226 |
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <pthread.h>
- #include <sys/prctl.h>
- #include "auth.h"
- #include "driver.h"
- #include "protocol.h"
- #include "udf_crc.h"
- #include "uinputux.h"
- /**************************************************
- * *
- * This file contents functions, which provide *
- * interact with fingerprint scanner. *
- * *
- **************************************************/
- /*********************
- * UTILS *
- *********************/
- static void printHex( const unsigned char* data, int length ){
-
- int i = 0;
- int k = 0;
-
- for( i = 0; i < length; i++ ){
- printf( "0x%02x ", data[i] );
-
- if( k == 7 ) printf( " ");
- else if( k == 15 ){
- printf( "\n" );
- k = 0;
- continue;
- }
- k++;
- }
-
- if( k ) printf( "\n" );
- }
- static void printReceivedPacket( struct driverInstance* this ){
- printf( "******************************* PACKET DUMP *******************************\n" );
- printf( " Request counter: 0x%02x, packet type 0x%02x, message body length: %i, data:\n",
- (this->requestCounter & 0x0f), this->rcvPacketType, this->rcvPacketMessageLength );
- printHex( this->packetMessage, this->rcvPacketMessageLength );
- printf( "******************************* DUMP END *******************************\n" );
- }
- static inline unsigned char bindataCompare( const unsigned char* data1, const unsigned char* data2, int length ){
- for( int i = 0; i < length; i++ ) if( data1[i] != data2[i] )return 1;
- return 0;
- }
- /*********************
- * CONTROL *
- *********************/
- static inline int deviceControlRead( struct driverInstance* this ){
- int res = libusb_control_transfer( this->deviceHandle, 0xc0, 4, 0, 0, this->controlStatus, 8, RQ_TIMEOUT );
- return res == 8 ? 0 : res;
- }
- //0x0400 reset and init
- //0x0601 wake up
- //0x0602 go to idle
- static inline int deviceControlWrite( struct driverInstance* this, uint16_t cmd ){
- unsigned char zero[1] = { 0x00 };
- int res = libusb_control_transfer( this->deviceHandle, 0x40, 12, 0x0100, cmd, zero, 1, RQ_TIMEOUT );
- return res == 1 ? 0 : res;
- }
- /*********************
- * PACKET *
- *********************/
- /************************************************
- func packetPrepareAndSend
- Send packet to fingerptint scanner
- Caller must prepare
- sendPacketType
- sendPacketMessageLength
- packetMessage(optionaly)
- input
- Pointer to main driver struct
- return
- negative on error
- 0 on success
- *************************************************/
- static int packetPrepareAndSend( struct driverInstance* this ){
-
- int err;
- int needTransfer;
- int alreadyTransferred;
- int transferred;
- int bulkLength;
- uint16_t crc;
-
- //prefix
- memcpy( this->_packetData, "Ciao", 4 );
-
- //type
- this->_packetData[4] = this->sendPacketType;
-
- //<COUNTER> + length MSB
- this->_packetData[5] = this->sendPacketType ? 0 : ( this->requestCounter << 4 ) | ( (this->sendPacketMessageLength >> 8) & 0x0f );
-
- //length LSB
- this->_packetData[6] = ( this->sendPacketMessageLength & 0xff );
-
-
- //if( this->packetDataLength ){}
-
- //CRC
- crc = udf_crc ( (this->_packetData+4), (this->sendPacketMessageLength+3) );
- this->_packetData[ (this->sendPacketMessageLength+7) ] = ( crc & 0xff );
- this->_packetData[ (this->sendPacketMessageLength+8) ] = ( crc >> 8 );
-
- needTransfer = this->sendPacketMessageLength + 9;
- alreadyTransferred = 0;
-
- do{
- bulkLength = needTransfer - alreadyTransferred;
- if( bulkLength > 64 ) bulkLength = 64;
-
- err = libusb_bulk_transfer( this->deviceHandle, BULK_EP_OUT, &this->_packetData[alreadyTransferred], bulkLength, &transferred, RQ_TIMEOUT );
- if( err ){
- printf( "bulk send err: %i\n", err );
- return err;
- }
-
- if( transferred != bulkLength ){
- printf( "bulk send len err\n" );
- return -1;
- }
- alreadyTransferred += transferred;
-
- }while( needTransfer > alreadyTransferred );
-
- return 0;
- }
- static int packetReceiveAndParse( struct driverInstance* this ){
-
- char stuckDetect;
- int err;
- int transferred;
-
- int needReceive;
- int alreadyReceived;
- int bulkLength;
-
- uint16_t crc;
-
- stuckDetect = 0;
-
- l_receiveNext:
- err = libusb_bulk_transfer( this->deviceHandle, BULK_EP_IN, this->_packetData, 64, &transferred, RQ_TIMEOUT );
- if( err ){
- printf( "bulk rcv err1: %i\n", err );
- return err;
- }
-
- //minimum possible length is 9: ciao(4) + header(3) + crc(2)
- if( transferred < 9 ){
- printf( "received data too short: %i\n", transferred );
- return -1;
- }
-
- //prefix check
- if( strncmp( "Ciao", (const char*)this->_packetData, 4 ) ){
- printf( "Ciao prefix mismatch\n" );
- return -2;
- }
-
- //parse header
- this->rcvPacketType = this->_packetData[4];
- this->rcvPacketMessageLength = ( (this->_packetData[5] & 0x0f) << 8 ) | this->_packetData[6] ;
-
- //If the packet size exceeds 64 bytes, then it is split into several reception sessions.
- //the code below checks the length and gets the rest of the packet as needed
- //9 means prefix ciao(4) + header(3) + crc(2)
- if( (this->rcvPacketMessageLength+9) > 64 ){
- alreadyReceived = transferred;
- needReceive = this->rcvPacketMessageLength + 9;
-
- do{
- bulkLength = needReceive - alreadyReceived;
- if( bulkLength > 64 ) bulkLength = 64;
-
- if( (alreadyReceived + bulkLength) > BUFLEN_PACKETDATA ){
- printf( "ERROR: Receiving packet too big.\n");
- return -11;
- }
-
- err = libusb_bulk_transfer( this->deviceHandle, BULK_EP_IN, &this->_packetData[alreadyReceived], bulkLength, &transferred, RQ_TIMEOUT );
-
- if( err ){
- printf( "bulk rcv err2: %i\n", err );
- return err;
- }
-
- if( bulkLength != transferred ){
- printf( "bulk rcv err: bulk length != received\n" );
- return -1;
- }
-
- alreadyReceived += transferred;
-
- }while( alreadyReceived < needReceive );
-
- if( alreadyReceived > needReceive ){
- printf( "rcv err: alreadyReceived(%i) > needReceive(%i)\n", alreadyReceived, needReceive );
- return -3;
- }
- }
-
- //CRC check
- crc = udf_crc( &this->_packetData[4], (this->rcvPacketMessageLength+3) );
- if( this->_packetData[ (this->rcvPacketMessageLength+7) ] != ( crc & 0xff )
- || this->_packetData[ (this->rcvPacketMessageLength+8) ] != ( crc >> 8 ) ){
- printf( "rcv packet err: crc mismatch\n" );
- return -4;
- }
-
- //answer the type 08
- if( this->rcvPacketType == 0x08 && !this->rcvPacketMessageLength ){
-
- if( stuckDetect > 10 ){
- //TODO: scanner reset on stuck
- printf( "WARNING: Fingerprint scanner seems has been hung up!\n" );
- return -5;
- }
-
- this->sendPacketType = 0x09;
- this->sendPacketMessageLength = 0;
- err = packetPrepareAndSend( this );
- if( err ){
- printf( "rcv packet 08 answer send err: %i\n", err );
- return err;
- }
-
- stuckDetect++;
- goto l_receiveNext;
- }
-
- //Check counter if it is not a request from the device
- if( !this->rcvPacketType ){
- if( ( this->_packetData[5] >> 4 ) == (this->requestCounter & 0x0f) ){
- this->requestCounter++;
- }else{
- printf( "Reseived packet counter mismatch.\n" );
- return -66;
- }
- }
-
- return 0;
- }
- /**********************
- * PROCESSING *
- **********************/
- static int packetSequenceMapProcessor( struct driverInstance* this, const struct packet_sequence_map* sequence, const char* mapname ){
-
- int err;
-
- printf( "Processing packet sequence map [%s]...\n", mapname );
-
- for( int i = 0; sequence[i].action; i++ ){
-
- if( sequence[i].action & ACTION_READ ){//read packet
- err = packetReceiveAndParse( this );
- if( err ){
- printf( "Receive packet error: %i, sequence: %i\n", err, i );
- return err;
- }
-
- if( this->rcvPacketType != sequence[i].type ) err |= 1;
- if( this->rcvPacketMessageLength != sequence[i].messageLength ) err |= ( 1<< 1 );
- if( bindataCompare( this->packetMessage, sequence[i].data, this->rcvPacketMessageLength ) ) err |= ( 1 << 2 );
-
- if( err ){
- printf( "\nPacket signature mismatch. flags: [%c%c%c], sequence: %i\n",
- err & 1 ? 't' : '.', //type mismatch
- err & (1<<1) ? 'l' : '.', //length mismatch
- err & (1<<2) ? 'd' : '.', //data mismatch
- i
- );
- printReceivedPacket( this );
- if( sequence[i].action & ACT_ERR_IGN ){
- printf( "This mismatch ignored\n" );
- err = 0;
- } else return err;
- }
-
- } else {//send packet
- this->sendPacketType = sequence[i].type;
- this->sendPacketMessageLength = sequence[i].messageLength;
- if( this->sendPacketMessageLength ) memcpy( this->packetMessage, sequence[i].data, this->sendPacketMessageLength );
- err = packetPrepareAndSend( this );
- if( err ){
- printf( "Send packet error: %i, sequence: %i\n", err, i );
- return err;
- }
- }
- }//for()
-
- printf( "Packet sequence map [%s] processing done(%i).\n", mapname, err );
- return 0;
- }
- /****************************************************************
- func commandExecute
- send command to scanner using packet type 0
- input
- this - pointer to driverInstance
- cmd - pointer to message data
- cmdlen - length of message
- action - ACTION_READ if need receive and parse packet, else 0
- return
- 0 on success
- not 0 on error
- *****************************************************************/
- static int commandExecute( struct driverInstance* this, const unsigned char* cmd, int cmdLen, unsigned char action ){
-
- int err;
-
- this->sendPacketType = 0;
- this->sendPacketMessageLength = cmdLen;
- memcpy( this->packetMessage, cmd, cmdLen );
- err = packetPrepareAndSend( this );
- if( err ){
- printf( "Failed send command to execute. code %i\n", err );
- return err;
- }
-
- if( action & ACTION_READ ){
-
- err = packetReceiveAndParse( this );
- if( err ){
- printf( "Failed receive command execute result. code: %i\n", err );
- return err;
- }
- }
-
- return 0;
- }
- /**********************
- * MESSAGE *
- **********************/
- static int messageReceiveRestData( struct driverInstance* this ){
-
- int err;
- unsigned char confirm[1] = { 0x30 };
-
- do{
- err = commandExecute( this, confirm, 1, ACTION_READ );
- if( err ){
- printf( "(%s) Command execute error: %i\n", __FUNCTION__, err );
- return err;
- }
-
- if( this->rcvPacketType ||
- !this->rcvPacketMessageLength ||
- (this->packetMessage[0] != 0x24 && this->packetMessage[0] != 0x20)
- ){
- printf( "(%s) Wrong packet\n", __FUNCTION__ );
- printReceivedPacket( this );
- return -EPROTO;
- }
-
- if( (this->dataLength + this->rcvPacketMessageLength - 1) > BUFLEN_DATA ){
- printf( "Data too big (%i > %i)\n", (this->dataLength + this->rcvPacketMessageLength - 1), BUFLEN_DATA );
- return -EMSGSIZE;
- }
-
- memcpy( &this->data[this->dataLength], &this->packetMessage[1], (this->rcvPacketMessageLength - 1) );
- this->dataLength += this->rcvPacketMessageLength -1;
- }while( this->packetMessage[0] == 0x24 );
-
- return 0;
- }
- /**************************
- * FLASH MEMORY ACCESS *
- **************************/
- static int flashWriteRegion( struct driverInstance* this, unsigned char region ){
-
- int err;
-
- int dataRemain;
- int dataSending;
- int dataSent;
-
- //write request template flag lsb msb reg lsb msb
- unsigned char request[15] = { 0x28, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0xfc, 0x58, 0xc4, 0x63, 0x00, 0x00, 0x00, 0x00 };
- const unsigned char response[7] = { 0x28, 0x04, 0x00, 0x00, 0x00, 0x01, 0x14 };
-
- if( region != 0xfb && region != 0xfc ){
- printf( "!!!ATTEMPT TO WRITE WRONG MEMORY REGION 0x%02x!!!\n", region );
- return -EINVAL;
- }
-
- dataSent = 0;
- dataRemain = this->dataLength;
-
- //message and command header
- request[12] = ( this->dataLength >> 8 ) & 0xff;//msb
- request[11] = this->dataLength & 0xff;//lsb
- request[7] = region;
- request[2] = ( (this->dataLength+12) >> 8 ) & 0xff;//msb
- request[1] = (this->dataLength+12) & 0xff;//lsb
-
- //decide size of sending data
- if( dataRemain > 2028 ){
- request[0] = 0x2c;
- dataSending = 2028;//2043 - 15
- } else {
- request[0] = 0x28;
- dataSending = this->dataLength;
- }
-
- //copy data
- this->sendPacketMessageLength = dataSending + 15;
- memcpy( this->packetMessage, request, 15 );
- if( dataSending ) memcpy( &this->packetMessage[15], this->data, dataSending );
-
- l_sendData:
-
- dataRemain -= dataSending;
-
- this->sendPacketType = 0x00;
- err = packetPrepareAndSend( this );
- if( !err ) err = packetReceiveAndParse( this );
-
- if( err ){
- printf( "Memory write error: %i\n", err );
- return err;
- }
-
- //if all data sent
- if( !dataRemain ){
-
- //check the answer
- if( this->rcvPacketType || this->rcvPacketMessageLength != 7 || bindataCompare(this->packetMessage, response, 7) ){
- printf( "Memory write error: all data sent, but get wrong packet\n" );
- printReceivedPacket( this );
- return -EPROTO;
- }
- return 0;
- }
-
- //if there is data left to send
- if( this->rcvPacketType || this->rcvPacketMessageLength != 1 || this->packetMessage[0] != 0x30 ){
- printf( "Memory write error: data left, but get wrong packet\n" );
- printReceivedPacket( this );
- return -EPROTO;
- }
-
- dataSent += dataSending;
-
- //decide size of sending data
- if( dataRemain > 2042 ){
- this->packetMessage[0] = 0x24;
- dataSending = 2042;
- } else {
- this->packetMessage[0] = 0x20;
- dataSending = dataRemain;
- }
-
- //copy next data
- this->sendPacketMessageLength = dataSending + 1;
- memcpy( &this->packetMessage[1], &this->data[dataSent], dataSending );
-
- goto l_sendData;
- }
- static int flashReadRegion( struct driverInstance* this, unsigned char region ){
-
- int err;
- int dataLength;
-
- //request template 0xfc
- unsigned char request[11] = { 0x28, 0x08, 0x00, 0x00, 0x00, 0x02, 0x04, 0xfb, 0x58, 0xc4, 0x63 };
-
- if( region != 0xfb && region != 0xfc ){
- printf( "!!!ATTEMPT TO READ WRONG MEMORY REGION: 0x%02X!!!\n", region );
- return -EINVAL;
- }
-
- this->dataLength = 0;
- request[7] = region;
- err = commandExecute( this, request, 11, ACTION_READ );
- if( err ){
- printf( "Error executing command to read memory: %i\n", err );
- return err;
- }
-
- if( this->rcvPacketType != 0 ||
- this->rcvPacketMessageLength < 7 ||
- bindataCompare(&this->packetMessage[3], &request[3], 3) ||
- this->packetMessage[6] != 0x14
- ){
- printf( "Error reading memory: wrong packet.\n");
- printReceivedPacket( this );
- return -EPROTO;
- }
-
- dataLength = this->packetMessage[7] | (this->packetMessage[8] << 8);
- memcpy( this->data, &this->packetMessage[11], (this->rcvPacketMessageLength - 11) );
- this->dataLength = this->rcvPacketMessageLength - 11;
-
- if( this->packetMessage[0] == 0x2c ){
- err = messageReceiveRestData( this );
- if( err ){
- printf( "Memory read error: messageReceiveRestData failed: %i\n", err );
- return err;
- }
- }
-
- if( this->dataLength != dataLength ){
- printf( "ERROR: memory read length mismatch %i != %i.\n", dataLength, this->dataLength );
- return -EPROTO;
- }
-
- return 0;
- }
- /*********************
- * RAM *
- *********************/
- static int ramWrite( struct driverInstance* this, unsigned char flag ){
-
- int err;
-
- //set flag
- this->ramData[94] = flag;
-
- //prepare data
- this->sendPacketType = 0x00;
- this->sendPacketMessageLength = 111;
- memcpy( this->packetMessage, ramWriteRequest, 15 );
- memcpy( &this->packetMessage[15], this->ramData, BUFLEN_RAMDATA );
-
- //send data
- err = packetPrepareAndSend( this );
- if( !err ) err = packetReceiveAndParse( this );
- if( err ){
- printf( "Ram write error: %i\n", err );
- return err;
- }
-
- if( this->rcvPacketMessageLength != 7 || bindataCompare(ramWriteResponse, this->packetMessage, 7) ){
- printf( "Ram write error: got unexpeced packet.\n" );
- printReceivedPacket( this );
- return -EPROTO;
- }
-
- return err;
- }
- static int ramRead( struct driverInstance* this ){
-
- int err;
-
- err = commandExecute( this, ramReadRequest, 11, ACTION_READ );
- if( err ){
- printf( "Ram read: command execution error: %i\n", err );
- return err;
- }
-
- if( this->rcvPacketMessageLength != 107 || bindataCompare(ramReadResponse, this->packetMessage, 11) ){
- printf( "Ram read error: got unexpecet packet.\n" );
- printReceivedPacket( this );
- return -EPROTO;
- }
-
- memcpy( this->ramData, &this->packetMessage[11], BUFLEN_RAMDATA );
-
- return 0;
- }
- /*********************
- * OPERATIONS *
- *********************/
- static int deviceInit( struct driverInstance* this ){
-
- int err;
-
- //write control to init and check it
- err = deviceControlWrite( this, CONTROL_INIT );
- if( !err ) err = deviceControlRead( this );
- if( !err ) err = bindataCompare( &this->controlStatus[4], state_40_a8_00_30, 4 );
- printf( "[init] Control %s.\n", err ? "error" : "success" );
- if( err ) return err;
-
- //command sequence to init device
- err = packetSequenceMapProcessor( this, init_map, "device init" );
- if( err ) return err;
-
- //ram config
- err = ramRead( this );
- if( !err ) err = ramWrite( this, RAMFLAG_DEFAULT );
- printf( "[init] Ram config %s.\n", err ? "error" : "success" );
-
- return err;
- }
- static int touchpadMode( struct driverInstance* this ){
-
- int err;
- int ufd;//uinput file descriptor
-
- void ( *uinputEventHandler )( int, short* );
-
- //select uinput event handler
- if( this->touchpadMode == MODE_TOUCHPAD_MOUSE ) uinputEventHandler = uinputEventMouse;
- else if( this->touchpadMode == MODE_TOUCHPAD_WHEELS ) uinputEventHandler = uinputEventWheels;
- else if( this->touchpadMode == MODE_TOUCHPAD_ARROWS ) uinputEventHandler = uinputEventArrows;
- else{
- printf( "[touchpad] unknown touchpad mode: 0x%02x\n", this->touchpadMode );
- return -EINVAL;
- }
-
- //open uinput device
- ufd = uinputOpen();
- if( ufd < 0 ){
- printf( "[touchpad] WARNING: Cannot open uinput.\n" );
- printf( "[touchpad] Going into idle mode.\n" );
- this->modeSwitcher = MODE_IDLE;
- return 0;
- }
-
- //switch scanner into touchpad mode
- err = commandExecute( this, touchpad_mode_request, 11, 0 );
-
- l_receiveNextPacket:
- if( !err ) err = packetReceiveAndParse( this );
- if( err ){
- printf( "[touchpad] Communicate error: %i\n", err );
- goto l_modeExit;
- }
-
- //if touchpad protocol packet
- if( this->rcvPacketType == 0x0b && this->rcvPacketMessageLength == 6 ) {
-
- uinputEventHandler( ufd, (short*)this->packetMessage );
-
- this->sendPacketType = 0x0b;
- this->sendPacketMessageLength = 1;
- this->packetMessage[0] = 0x01;
-
- //change mode or uinput event handler
- if( this->modeSwitcher != MODE_TOUCHPAD ){
- if( this->modeSwitcher == MODE_TOUCHPAD_MOUSE ) uinputEventHandler = uinputEventMouse;
- else if( this->modeSwitcher == MODE_TOUCHPAD_WHEELS ) uinputEventHandler = uinputEventWheels;
- else if( this->modeSwitcher == MODE_TOUCHPAD_ARROWS ) uinputEventHandler = uinputEventArrows;
- else{
- this->packetMessage[0] = 0x00;//set continue flag to false for exit touchpad mode
- goto l_sendNextPacket;
- }
-
- this->touchpadMode = this->modeSwitcher;
- this->modeSwitcher = MODE_TOUCHPAD;
- sem_post( &this->semaphoreIpc );//notify ipcd about touchpad mode change
- }
-
- l_sendNextPacket:
- err = packetPrepareAndSend( this );
- goto l_receiveNextPacket;
- }
-
- //if not touchpad response, then protocol error
- if( this->rcvPacketMessageLength != 7 || bindataCompare(touchpad_mode_response, this->packetMessage, 7) ) {
- printf( "[touchpad] Received wrong packet\n" );
- printReceivedPacket( this );
- err = -EPROTO;
- goto l_modeExit;
- }
-
- err = 0;
- sem_post( &this->semaphoreIpc );//notify ipcd about mode exit
-
- l_modeExit:
- uinputClose( ufd );
- return err;
- }
- /*
- //I don't know what's going on here. The Windows driver does
- //this after capturing an image from the scanner, but not always.
- static int uncnownAction1( struct driverInstance* this ){
-
- int err;
-
- err = commandExecute( this, unknown_action1_request, 15, ACTION_READ );
- if( err ){
- printf( "UA1) request error: %i\n", err );
- return err;
- }
-
- if( !bindataCompare( unknown_action1_success, this->packetMessage, 7 ) && this->rcvPacketMessageLength == 7 ) printf( "UA1) success\n" );
- else if( !bindataCompare( unknown_action1_failure, this->packetMessage, 7 ) && this->rcvPacketMessageLength == 7 ) printf( "UA1) fail\n" );
- else{
- printf( "UA1) received unknown packet\n" );
- printReceivedPacket( this );
- return -EPROTO;
- }
-
- return 0;
- }
- */
- //I think it has something to do with image quality. When I very quickly run
- //my finger over the scanner, values below 100% often appear here.
- static int requestPictureQuality( struct driverInstance* this ){
-
- int err;
- err = commandExecute( this, image_quality_request, 7, ACTION_READ );
- if( err ){
- printf( "Image quality request error: %i\n", err );
- return err;
- }
-
- if(
- this->rcvPacketMessageLength == 11 &&
- !bindataCompare( image_quality_responce, this->packetMessage, 7 ) &&
- !bindataCompare( &image_quality_responce[8], &this->packetMessage[8], 3 )
- ){
- //0x28 0x08 0x00 0x00 0x00 0x15 0x12 0x00 0x00 0x00 0x00
- // ----
- // this byte
- this->scanQuality = this->packetMessage[7];
- return 0;
- }
-
- printf( "wrong [image quality] paket\n" );
- printReceivedPacket( this );
- return -EPROTO;
- }
- /*
- static void pictureSaveFile( struct driverInstance* this ){
-
- FILE* imgFile;
- imgFile = fopen( "fimg", "w" );
- if( imgFile ){
- fwrite( "P5 144 270 255\n", 1, 15, imgFile );
- fwrite( this->data, 1, this->dataLength, imgFile );
- fclose( imgFile );
- }
- }
- */
- /**************
- scanResuilt
- 0 - all ok
- -EIO - on driver error
- -ETIMEDOUT - on scanning timeout
- -ECANCELED - on cancel scanning
-
- 0x07 - User slid their finger too far to the left
- 0x08 - User slid their finger too far to the right
- 0x0b - The quality of the fingerprint is poor
- 0x0f - User swiped the scanner incorrectly
- 0x1c - User swiped the scanner too quickly
- 0x1d - The finger slid strongly horizontally
- 0x1e - User swiped the scanner too short
- **************/
- static int fingerScanPolling( struct driverInstance* this ){
-
- int err;
-
- unsigned char scan_request[14] = { 0x28, 0x0b, 0x00, 0x00, 0x00, 0x0e, 0x02, 0xc0, 0xd4, 0x01, 0x00, 0x02, 0x01, 0x00 };
- unsigned char scan_poll[8] = { 0x28, 0x05, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01 };// ----
- // ----
-
- l_scanAgain:
-
- scan_poll[7] = 0x01;//cancel flag
- //scan_request[12] = 0x01;//fail detection
-
- err = commandExecute( this, scan_request, 14, ACTION_READ );
-
- l_poll:
- if( err ){
- printf( "[scan] finger scan request err: %i\n", err );
- goto l_error;
- }
-
- //poll response
- if( this->rcvPacketMessageLength == 20 &&
- !bindataCompare( this->packetMessage, _finger_scan_poll_response, 11 ) &&
- !bindataCompare( &this->packetMessage[12], &_finger_scan_poll_response[12], 8 )
- ){
-
- switch( this->packetMessage[11] ){
- case 0x00: //get ready, next response will be with picture
- case 0x0c: //not ready
- break;
-
- case 0x07: //Finger shifted to the left
- case 0x08: //Finger shifted to the right
- case 0x0b: //Bad quality
- case 0x0f: //Wrong swipe
- case 0x1c: //Swiped too fast
- case 0x1d: //Finger shifted
- case 0x1e: //Swiped too short
- this->scanResult = this->packetMessage[11];
- this->driverState = STATE_WAIT_IPC;
- sem_post( &this->semaphoreIpc );
- sem_wait( &this->semaphoreScan );
- this->driverState = STATE_RUNNING;
- break;
-
- default:
- printf( "[scan] Warning: unknown poll code 0x%02x\n", this->packetMessage[11] );
- }
-
- if( this->modeSwitcher != MODE_SCANNING ) scan_poll[7] = 0x00;
- err = commandExecute( this, scan_poll, 8, ACTION_READ );
- goto l_poll;
- }
-
- if( this->rcvPacketMessageLength == 7 ){
- if( !bindataCompare(this->packetMessage, finger_scan_response_canceled, 7) ){
- this->scanResult = -ECANCELED;
- goto l_scanFinish;
- }
-
- if( !bindataCompare(this->packetMessage, finger_scan_response_timeout, 7) ){
- this->scanResult = -ETIMEDOUT;
- goto l_scanFinish;
- }
- }
-
- //answer with picture?
- if( this->rcvPacketMessageLength == 2043 && !bindataCompare(this->packetMessage, finger_scan_response_picture, 11) ){
-
- //2043 - 11 = 2032
- memcpy( this->data, &this->packetMessage[11], 2032 );
- this->dataLength = 2032;
-
- err = messageReceiveRestData( this );
- if( !err ) err = requestPictureQuality( this );
-
- if( err ){
- printf( "[scan] picture receive or quality request error: %i\n", err );
- goto l_error;
- }
-
- if( this->dataLength != 38880 ){
- printf( "[scan] Error: Unexpected image size: %i.\n", this->dataLength );
- err = -EPROTO;
- goto l_error;
- }
-
- printf( "[scan] Received image quality %i%%\n", this->scanQuality );
-
- this->scanResult = 0;
- goto l_scanFinish;
- }
-
- printf( "[scan] Unknown packet received:\n" );
- printReceivedPacket( this );
- err = -EPROTO; //unknown packet
-
- l_error:
- this->scanResult = -EIO;
- this->driverState = STATE_WAIT_IPC;
- sem_post( &this->semaphoreIpc );
- sem_wait( &this->semaphoreScan );
- this->driverState = STATE_RUNNING;
- return err;
-
- l_scanFinish:
- this->driverState = STATE_WAIT_IPC;
- sem_post( &this->semaphoreIpc );
- sem_wait( &this->semaphoreScan );
- this->driverState = STATE_RUNNING;
- if( this->modeSwitcher == MODE_SCANNING ){
- printf( "[scan] Scanning again\n" );
- goto l_scanAgain;
- }
- return 0;
- }
- static int idlingMode( struct driverInstance* this ){
-
- int err;
- struct timespec timeToWaitSemaphore;
-
- l_go_to_idle:
- //send command to idle
- err = commandExecute( this, cmd_to_idle, 14, 0 );
- if( err ){
- printf( "[idle] command to idle error: %i\n", err );
- return err;
- }
-
- //set control to idle
- err = deviceControlWrite( this, CONTROL_TO_IDLE );
- if( err ){
- printf( "[idle] control to idle error: %i\n", err );
- return err;
- }
-
- //request interrupt and wait semaphore
- if( this->interruptStatus ) sem_post( &this->semaphoreInterrupt );
- l_waitSemaphore:
- sem_wait( &this->semaphoreIdle );
-
- //passive auth mode switch
- if( this->passiveAuthModeSwitcher != this->passiveAuthModeIndicator ){
- this->passiveAuthModeIndicator = this->passiveAuthModeSwitcher;
- this->driverState = STATE_WAIT_IPC;
- sem_post( &this->semaphoreIpc );
- sem_wait( &this->semaphoreScan );
- this->driverState = STATE_RUNNING;
- goto l_waitSemaphore;
- }
-
- //check error in interrupt thread
- if( this->interruptStatus < 0 ){
- printf( "[idle] interrupt thread return error: %i\n", this->interruptStatus );
- return this->interruptStatus;
- }
-
- //set control to wake up
- err = deviceControlWrite( this, CONTROL_WAKE_UP );
- if( err ){
- printf( "[idle] device control wake up error: %i\n", err );
- return err;
- }
-
- //read "to idle" comand response
- err = packetReceiveAndParse( this );
- if( err ){
- printf( "[idle] read 'to idle' command response error: %i\n", err );
- return err;
- }
-
- //check received packet type
- if( this->rcvPacketType ){
- printf( "[idle] received unexpected packet:\n" );
- printReceivedPacket( this );
- return -EPROTO;
- }
-
- //maybe this is failed finger scan?
- if( this->rcvPacketMessageLength == 7 ){
- //This occurs when poorly or accidentally touching the fingerprint scanner.
- if( !bindataCompare(this->packetMessage, idle_answer_error1, 7) ) goto l_go_to_idle;
- if( !bindataCompare(this->packetMessage, idle_answer_error2, 7) ) goto l_go_to_idle;
- }
-
- //maybe this is fingerprint image?
- if( this->rcvPacketMessageLength == 2043 && !bindataCompare(this->packetMessage, idle_answer_picture, 19) ){
-
- memcpy( this->data, &this->packetMessage[19], (this->rcvPacketMessageLength - 19) );
- this->dataLength = this->rcvPacketMessageLength - 19;
- err = messageReceiveRestData( this );
- if( err ){
- printf( "[idle] receive picture error: %i\n", err );
- return err;
- }
-
- if( this->dataLength != 38880 ){
- printf( "[idle] Error: Unexpected image size: %i.\n", this->dataLength );
- return -EPROTO;
- }
-
- err = requestPictureQuality( this );
- if( err ){
- printf( "[idle] PictureQuality request error: %i\n", err );
- return err;
- }
-
- printf( "[idle] Received image quality %i%%\n", this->scanQuality );
-
- authFingerTrigger( this );
- //pictureSaveFile( this );
- goto l_go_to_idle;
- }
-
- //if this is not a correct awakening, then something is wrong
- if( this->rcvPacketMessageLength != 15 || bindataCompare(this->packetMessage, idle_answer, 15) ){
- printf( "[idle] received unexpected packet:\n" );
- printReceivedPacket( this );
- return -EPROTO;
- }
-
- //if current mode is idle, then go to idle
- if( this->modeSwitcher == MODE_IDLE ){
- printf( "[idle] WARNING: Wake up without action.\n" );
- printf( "[idle] Last data in control status: " );
- printHex( this->controlStatus, 4 );
- printf( "[idle] Going to idle.\n" );
- goto l_go_to_idle;
- }
-
- //get current time and add 5 sec
- err = clock_gettime( CLOCK_REALTIME, &timeToWaitSemaphore );
- if( err ){
- perror( "[idle] clock" );
- return err;
- }
- timeToWaitSemaphore.tv_sec += 5;
-
- //waiting for an interruption that come in the process of awakening
- err = sem_timedwait( &this->semaphoreIdle, &timeToWaitSemaphore );
- if( err && errno == ETIMEDOUT ){
- printf( "[idle] WARNING: After wake up interrupt not got.\n" );
- printf( "[idle] Last data in control register: ");
- printHex( this->controlStatus, 4 );
- }
-
- sem_post( &this->semaphoreIpc ); //notifi ipcd about mode exiting
- return 0;
- }
- /****************************
- * INTERRUPT HANDLER *
- ****************************/
- //this function works in a separate thread
- static void* deviceInterruptHandler( void* arg ){
-
- struct driverInstance* this = arg;
- int err;
- int transferred;
-
- prctl( PR_SET_NAME, "IRQ", 0, 0, 0 );
-
- l_waitSemaphore:
- this->interruptStatus = 1;
- sem_wait( &this->semaphoreInterrupt );
- this->interruptStatus = 0;
-
- l_waitInterrupt:
- err = libusb_interrupt_transfer( this->deviceHandle, INT_EP_IN, this->controlStatus, 4, &transferred, 0 );
- if( err ){
- printf( "[interrupt] ERROR: Transfer return code %i\n", err );
- this->interruptStatus = err;
- goto l_error;
- }
-
- if( transferred != 4 ){
- printf( "[interrupt] ERROR: Transferred != 4\n" );
- this->interruptStatus = -1;
- goto l_error;
- }
-
- //ignore these interrupts
- if( !bindataCompare(this->controlStatus, state_00_80_00_30, 4) ) goto l_waitInterrupt;
- if( !bindataCompare(this->controlStatus, state_00_80_02_30, 4) ) goto l_waitInterrupt;
- if( !bindataCompare(this->controlStatus, state_00_80_03_30, 4) ) goto l_waitInterrupt;
- if( !bindataCompare(this->controlStatus, state_00_c0_03_30, 4) ) goto l_waitInterrupt;
- if( !bindataCompare(this->controlStatus, state_38_b0_00_30, 4) ) goto l_waitInterrupt;
-
- //these interrupts come in the process of awakening
- if( !bindataCompare(this->controlStatus, state_40_a8_00_30, 4) ) goto l_sem_post;
- if( !bindataCompare(this->controlStatus, state_40_b0_00_30, 4) ) goto l_sem_post;
-
- //user touch fingerprint scanner
- if( !bindataCompare(this->controlStatus, state_40_a8_02_30, 4) ) goto l_sem_post;
-
- printf( "[interrupt] WARNING: Unknown state: " );
- printHex( this->controlStatus, 4 );
-
- l_sem_post:
- sem_post( &this->semaphoreIdle );
- goto l_waitSemaphore;
-
- l_error:
- sem_post( &this->semaphoreIdle );
- return NULL;
- }
- /***************************************************************
- semaphoreIpc up rules
- notification about entering mode sends by driverModeSwitcher
- notification about exiting mode sends by a mode handler
- ***************************************************************/
- static int driverModeSwitcher( struct driverInstance* this ){
-
- int err;
-
- //just in case
- this->modeIndicator = MODE_IDLE;
- this->modeSwitcher = MODE_IDLE;
-
- //do not semaphoreIpc up on driver starts
- goto l_startIdle;
-
- l_switchMode:
-
- if( this->modeSwitcher == MODE_IDLE ){
- this->modeIndicator = MODE_IDLE;
- sem_post( &this->semaphoreIpc );//notify ipc about mode change
- l_startIdle:
- printf( "[switch] Entering into idle mode...\n" );
- err = idlingMode( this );
- if( err ){
- printf( "[switch] Idling mode exited with code: %i\n", err );
- return err;
- }
- goto l_switchMode;
- }
-
- if( this->modeSwitcher == MODE_TOUCHPAD ){
- this->modeIndicator = MODE_TOUCHPAD;
- printf( "[switch] Entering into touchpad mode...\n" );
- sem_post( &this->semaphoreIpc );//notify ipc about mode change
- err = touchpadMode( this );
- if( err ){
- printf( "[switch] touchpadMode returns error: %i\n", err );
- return err;
- }
-
- goto l_switchMode;
- }
-
- if( this->modeSwitcher == MODE_SCANNING ){
- this->modeIndicator = MODE_SCANNING;
- err = ramWrite( this, RAMFLAG_SCAN );
- if( !err ){
- printf( "[switch] Entering into scanning mode...\n" );
- sem_post( &this->semaphoreIpc );//notify ipc about mode change
- err = fingerScanPolling( this );
- }
- if( !err ) err = ramWrite( this, RAMFLAG_DEFAULT );
-
- if( err ){
- printf( "[switch] fingerScanPolling error: %i\n", err );
- return err;
- }
-
- goto l_switchMode;
- }
-
- printf( "[switch] WARNING! Unknown mode switch 0x%02x.\n", this->modeSwitcher );
- return -EINVAL;
- }
- /********************
- * ENTRY *
- ********************/
- void* ipcdEntryPoint( void* arg );
- int daemonEntryPoint( libusb_device_handle* deviceHandle, int launcherdSocket ){
-
- int err;
- pthread_t threadIpcd;
- pthread_t threadInterrupt;
-
- struct driverInstance this;
-
- //init some struct fields
- this.deviceHandle = deviceHandle;
- this.launcherdSocket = launcherdSocket;
- this.packetMessage = &this._packetData[7];
- this.requestCounter = 0x00;
- this.interruptStatus = 1;
- this.modeIndicator = MODE_IDLE;
- this.modeSwitcher = MODE_IDLE;
- this.driverState = STATE_RUNNING;
- this.passiveAuthUsername = NULL;
- this.passiveAuthModeSwitcher = PA_STOP;
- this.passiveAuthModeIndicator = PA_STOP;
-
-
- sem_init( &this.semaphoreIpc, 0, 0 );
- sem_init( &this.semaphoreIdle, 0, 0 );
- sem_init( &this.semaphoreScan, 0, 0 );
- sem_init( &this.semaphoreInterrupt, 0, 0 );
-
- err = deviceInit( &this );//init device
-
- if( !err ) err = pthread_create( &threadInterrupt, NULL, deviceInterruptHandler, &this );
- if( !err ) err = pthread_create( &threadIpcd, NULL, ipcdEntryPoint, &this );
- if( !err ) err = driverModeSwitcher( &this );//go to main loop
-
- //
- //
- //TODO: correct threads stop
- //
- //
-
- //cleanup
- sem_destroy( &this.semaphoreIpc );
- sem_destroy( &this.semaphoreIdle );
- sem_destroy( &this.semaphoreScan );
- sem_destroy( &this.semaphoreInterrupt );
-
- return err;
- }
- //do not notice about unused functions
- void shutUp( void ){
- flashReadRegion( NULL, 0 );
- flashWriteRegion( NULL, 0 );
- }
|