/* Exec loop sequential state machine */ static void m_loop_state(struct fpi_ssm *ssm) { struct fp_img_dev *dev = ssm->priv; vfs301_dev_t *vdev = dev->priv; switch (ssm->cur_state) { case M_REQUEST_PRINT: vfs301_proto_request_fingerprint(dev->udev, vdev); fpi_ssm_next_state(ssm); break; case M_WAIT_PRINT: /* Wait fingerprint scanning */ async_sleep(200, ssm); break; case M_CHECK_PRINT: if (!vfs301_proto_peek_event(dev->udev, vdev)) fpi_ssm_jump_to_state(ssm, M_WAIT_PRINT); else fpi_ssm_next_state(ssm); break; case M_READ_PRINT_START: fpi_imgdev_report_finger_status(dev, TRUE); vfs301_proto_process_event_start(dev->udev, vdev); fpi_ssm_next_state(ssm); break; case M_READ_PRINT_WAIT: /* Wait fingerprint scanning */ async_sleep(200, ssm); break; case M_READ_PRINT_POLL: { int rv = vfs301_proto_process_event_poll(dev->udev, vdev); assert(rv != VFS301_FAILURE); if (rv == VFS301_ONGOING) fpi_ssm_jump_to_state(ssm, M_READ_PRINT_WAIT); else fpi_ssm_next_state(ssm); } break; case M_SUBMIT_PRINT: if (submit_image(ssm)) { fpi_ssm_mark_completed(ssm); /* NOTE: finger off is expected only after submitting image... */ fpi_imgdev_report_finger_status(dev, FALSE); } else { fpi_ssm_jump_to_state(ssm, M_REQUEST_PRINT); } break; } }
static void state_init_cb(struct libusb_transfer *transfer) { struct fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = ssm->priv; struct vfs0050_dev *vfs_dev = dev->priv; //TODO: check for transfer errors in tranfer->status switch (ssm->cur_state) { case M_INIT_1_ONGOING: vfs_dev->init1_offset += transfer->actual_length; libusb_free_transfer(transfer); if (vfs_dev->init1_offset == sizeof(vfs0050_init1)) { //done transferring this initialization section fpi_ssm_next_state(ssm); break; } fpi_ssm_jump_to_state(ssm, M_INIT_1_ONGOING); break; case M_INIT_2_ONGOING: vfs_dev->init2_offset += transfer->actual_length; libusb_free_transfer(transfer); if (vfs_dev->init2_offset == sizeof(vfs0050_init2)) { //done transferring this initialization section fpi_ssm_next_state(ssm); break; } fpi_ssm_jump_to_state(ssm, M_INIT_2_ONGOING); break; case M_INIT_2_RECV_EP1_ONGOING: //we wait for a timeout here indicating no more data to receive. if (transfer->actual_length < 64) { fpi_ssm_next_state(ssm); break; } fpi_ssm_jump_to_state(ssm, M_INIT_2_RECV_EP1_ONGOING); break; case M_INIT_2_RECV_EP2_ONGOING: vfs_dev->calbuf_idx += transfer->actual_length; if (transfer->actual_length < 64) { fpi_ssm_next_state(ssm); break; } fpi_ssm_jump_to_state(ssm, M_INIT_2_RECV_EP2_ONGOING); break; default: libusb_free_transfer(transfer); fpi_ssm_next_state(ssm); break; } }
static void capture_cb(struct libusb_transfer *transfer) { struct fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = ssm->priv; struct v5s_dev *vdev = dev->priv; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { fpi_ssm_mark_aborted(ssm, -EIO); goto out; } if (++vdev->capture_iteration == NR_REQS) { struct fp_img *img = vdev->capture_img; /* must clear this early, otherwise the call chain takes us into * loopsm_complete where we would free it, when in fact we are * supposed to be handing off this image */ vdev->capture_img = NULL; fpi_imgdev_report_finger_status(dev, finger_is_present(img->data)); fpi_imgdev_image_captured(dev, img); fpi_ssm_next_state(ssm); } else { capture_iterate(ssm); } out: libusb_free_transfer(transfer); }
static void async_sleep_cb(void *data) { struct fpi_ssm *ssm = data; struct fp_img_dev *dev = ssm->priv; struct vfs0050_dev *vfs_dev = dev->priv; if (vfs_dev->is_active) { fpi_ssm_jump_to_state(ssm, M_ACTIVATE_START); } else { fpi_ssm_next_state(ssm); } }
static void capture_cmd_cb(struct libusb_transfer *transfer) { struct fpi_ssm *ssm = transfer->user_data; if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length)) { fpi_ssm_next_state(ssm); } else { fpi_ssm_mark_aborted(ssm, -EIO); } libusb_free_transfer(transfer); }
static void sm_write_reg_cb(struct libusb_transfer *transfer) { struct fpi_ssm *ssm = transfer->user_data; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) fpi_ssm_mark_aborted(ssm, -EIO); else fpi_ssm_next_state(ssm); g_free(transfer->buffer); libusb_free_transfer(transfer); }
static void finger_det_read_fd_data_cb(struct libusb_transfer *transfer) { struct fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = ssm->priv; struct aesX660_dev *aesdev = dev->priv; unsigned char *data = transfer->buffer; aesdev->fd_data_transfer = NULL; if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { fp_dbg("Cancelling transfer...\n"); fpi_ssm_next_state(ssm); goto out; } if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || (transfer->length != transfer->actual_length)) { fp_dbg("Failed to read FD data\n"); fpi_ssm_mark_aborted(ssm, -EIO); goto out; } if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE) { fp_dbg("Bogus FD response: %.2x\n", data[0]); fpi_ssm_mark_aborted(ssm, -EPROTO); goto out; } if (data[AESX660_FINGER_PRESENT_OFFSET] == AESX660_FINGER_PRESENT || aesdev->deactivating) { /* Finger present or we're deactivating... */ fpi_ssm_next_state(ssm); } else { fp_dbg("Wait for finger returned %.2x as result\n", data[AESX660_FINGER_PRESENT_OFFSET]); fpi_ssm_jump_to_state(ssm, FINGER_DET_SEND_FD_CMD); } out: g_free(data); libusb_free_transfer(transfer); }
static void capture_read_stripe_data_cb(struct libusb_transfer *transfer) { struct fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = ssm->priv; struct aesX660_dev *aesdev = dev->priv; unsigned char *data = transfer->buffer; int finger_missing = 0; size_t copied, actual_len = transfer->actual_length; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { fpi_ssm_mark_aborted(ssm, -EIO); goto out; } fp_dbg("Got %d bytes of data", actual_len); do { copied = min(aesdev->buffer_max - aesdev->buffer_size, actual_len); memcpy(aesdev->buffer + aesdev->buffer_size, data, copied); actual_len -= copied; data += copied; aesdev->buffer_size += copied; fp_dbg("Copied %.4x bytes into internal buffer", copied); if (aesdev->buffer_size == aesdev->buffer_max) { if (aesdev->buffer_max == AESX660_HEADER_SIZE) { aesdev->buffer_max = aesdev->buffer[AESX660_RESPONSE_SIZE_LSB_OFFSET] + (aesdev->buffer[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8) + AESX660_HEADER_SIZE; fp_dbg("Got frame, type %.2x size %.4x", aesdev->buffer[AESX660_RESPONSE_TYPE_OFFSET], aesdev->buffer_max); continue; } else { finger_missing |= process_stripe_data(ssm, aesdev->buffer); aesdev->buffer_max = AESX660_HEADER_SIZE; aesdev->buffer_size = 0; } } } while (actual_len); fp_dbg("finger %s\n", finger_missing ? "missing" : "present"); if (finger_missing) { fpi_ssm_next_state(ssm); } else { fpi_ssm_jump_to_state(ssm, CAPTURE_READ_STRIPE_DATA); } out: g_free(transfer->buffer); libusb_free_transfer(transfer); }
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); }
static void aesX660_send_cmd_cb(struct libusb_transfer *transfer) { struct fpi_ssm *ssm = transfer->user_data; if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length)) { fpi_ssm_next_state(ssm); } else { fp_dbg("tx transfer status: %d, actual_len: %.4x\n", transfer->status, transfer->actual_length); fpi_ssm_mark_aborted(ssm, -EIO); } libusb_free_transfer(transfer); }
static void activate_read_id_cb(struct libusb_transfer *transfer) { struct fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = ssm->priv; struct aesX660_dev *aesdev = dev->priv; unsigned char *data = transfer->buffer; if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || (transfer->length != transfer->actual_length)) { fp_dbg("read_id cmd failed\n"); fpi_ssm_mark_aborted(ssm, -EIO); goto out; } /* ID was read correctly */ if (data[0] == 0x07) { fp_dbg("Sensor device id: %.2x%2x, bcdDevice: %.2x.%.2x, init status: %.2x\n", data[4], data[3], data[5], data[6], data[7]); } else { fp_dbg("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]); fpi_ssm_mark_aborted(ssm, -EPROTO); goto out; } switch (aesdev->init_seq_idx) { case 0: aesdev->init_seq = aesdev->init_seqs[0]; aesdev->init_seq_len = aesdev->init_seqs_len[0]; aesdev->init_seq_idx = 1; aesdev->init_cmd_idx = 0; /* Do calibration only after 1st init sequence */ fpi_ssm_jump_to_state(ssm, ACTIVATE_SEND_INIT_CMD); break; case 1: aesdev->init_seq = aesdev->init_seqs[1]; aesdev->init_seq_len = aesdev->init_seqs_len[1]; aesdev->init_seq_idx = 2; aesdev->init_cmd_idx = 0; fpi_ssm_next_state(ssm); break; default: fp_dbg("Failed to init device! init status: %.2x\n", data[7]); fpi_ssm_mark_aborted(ssm, -EPROTO); break; } out: g_free(transfer->buffer); libusb_free_transfer(transfer); }
static void write_init_cb(struct libusb_transfer *transfer) { struct fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = ssm->priv; struct upektc_dev *upekdev = dev->priv; if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length)) { if (upekdev->setup_commands[upekdev->init_idx].response_len) fpi_ssm_next_state(ssm); else upektc_next_init_cmd(ssm); } else { fpi_ssm_mark_aborted(ssm, -EIO); } libusb_free_transfer(transfer); }
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); }
static void aesX660_read_calibrate_data_cb(struct libusb_transfer *transfer) { struct fpi_ssm *ssm = transfer->user_data; unsigned char *data = transfer->buffer; if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || (transfer->length != transfer->actual_length)) { fpi_ssm_mark_aborted(ssm, -EIO); goto out; } /* Calibrate response was read correctly? */ if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE) { fp_dbg("Bogus calibrate response: %.2x\n", data[0]); fpi_ssm_mark_aborted(ssm, -EPROTO); goto out; } fpi_ssm_next_state(ssm); out: g_free(transfer->buffer); libusb_free_transfer(transfer); }
/* Callback of asynchronous sleep */ static void async_sleep_cb(void *data) { struct fpi_ssm *ssm = data; fpi_ssm_next_state(ssm); }
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); }
static void state_init(struct fpi_ssm *ssm) { int transferred; int to_send; struct libusb_transfer *transfer; struct fp_img_dev *dev = ssm->priv; struct vfs0050_dev *vfs_dev = dev->priv; switch (ssm->cur_state) { case M_INIT_START: //couple of synchronous transfers here in the beginning, don't think this hurts much. vfs_dev->tmpbuf[0] = 0x1a; libusb_bulk_transfer(dev->udev, EP1_OUT, vfs_dev->tmpbuf, 1, &transferred, BULK_TIMEOUT); libusb_bulk_transfer(dev->udev, EP1_IN, vfs_dev->tmpbuf, 64, &transferred, BULK_TIMEOUT); fpi_ssm_next_state(ssm); break; case M_INIT_1_ONGOING: to_send = sizeof(vfs0050_init1) - vfs_dev->init1_offset; to_send = to_send >= 64 ? 64 : to_send; assert(to_send > 0); transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, dev->udev, EP1_OUT, vfs0050_init1 + vfs_dev->init1_offset, to_send, state_init_cb, ssm, BULK_TIMEOUT); libusb_submit_transfer(transfer); break; case M_INIT_1_STEP2: transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, dev->udev, EP1_IN, vfs_dev->tmpbuf, 64, state_init_cb, ssm, BULK_TIMEOUT); libusb_submit_transfer(transfer); break; case M_INIT_1_STEP3: vfs_dev->tmpbuf[0] = 0x01; transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, dev->udev, EP1_OUT, vfs_dev->tmpbuf, 1, state_init_cb, ssm, BULK_TIMEOUT); libusb_submit_transfer(transfer); break; case M_INIT_1_STEP4: transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, dev->udev, EP1_IN, vfs_dev->tmpbuf, 64, state_init_cb, ssm, BULK_TIMEOUT); libusb_submit_transfer(transfer); break; case M_INIT_2_ONGOING: to_send = sizeof(vfs0050_init2) - vfs_dev->init2_offset; to_send = to_send >= 64 ? 64 : to_send; assert(to_send > 0); transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, dev->udev, EP1_OUT, vfs0050_init2 + vfs_dev->init2_offset, to_send, state_init_cb, ssm, BULK_TIMEOUT); libusb_submit_transfer(transfer); break; case M_INIT_2_RECV_EP1_ONGOING: transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, dev->udev, EP1_IN, vfs_dev->tmpbuf, 64, state_init_cb, ssm, BULK_TIMEOUT); libusb_submit_transfer(transfer); break; case M_INIT_2_RECV_EP2_ONGOING: if (vfs_dev->calbuf_idx + 64 >= vfs_dev->calbuf_sz) { vfs_dev->calbuf_sz <<= 1; vfs_dev->calbuf = g_realloc(vfs_dev->calbuf, vfs_dev->calbuf_sz); } transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, dev->udev, EP2_IN, vfs_dev->calbuf + vfs_dev->calbuf_idx, 64, state_init_cb, ssm, BULK_TIMEOUT); libusb_submit_transfer(transfer); break; default: fpi_ssm_mark_completed(ssm); break; } }
static void state_activate_cb(struct libusb_transfer *transfer) { struct fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = ssm->priv; struct vfs0050_dev *vfs_dev = dev->priv; switch (ssm->cur_state) { case M_ACTIVATE_1_SINGLE_READ: //check bytes are 0x00 and 0x00 if (vfs_dev->tmpbuf[0] != 0x00 || vfs_dev->tmpbuf[1] != 0x00) { fp_dbg("unexpected bytes back from endpoint in M_ACTIVATE_1_SINGLE_READ"); libusb_free_transfer(transfer); fpi_ssm_jump_to_state(ssm, M_ACTIVATE_START); break; } libusb_free_transfer(transfer); fpi_ssm_next_state(ssm); break; case M_ACTIVATE_2_SEND: vfs_dev->activate_offset += transfer->actual_length; if (vfs_dev->activate_offset == sizeof(vfs0050_activate2)) { //finished sending this activation section fpi_ssm_next_state(ssm); break; } fpi_ssm_jump_to_state(ssm, M_ACTIVATE_2_SEND); break; case M_ACTIVATE_EP1_DRAIN: //just draining this data, not sure what it does yet. if (transfer->actual_length < 64) { libusb_free_transfer(transfer); fpi_ssm_next_state(ssm); break; } libusb_free_transfer(transfer); fpi_ssm_jump_to_state(ssm, M_ACTIVATE_EP1_DRAIN); break; case M_ACTIVATE_EP3_INT1: if (transfer->actual_length != 5) { fp_dbg("unexpected length for interrupt transfer in M_ACTIVATE_EP3_INT1"); //TODO: fail here, exit ssm } fpi_ssm_next_state(ssm); break; case M_ACTIVATE_AWAIT_FINGER: //if we got here, it's time to read fingerprint data. //interrupt data should be 02 00 0e 00 f0 if (vfs_dev->is_active) { if (transfer->actual_length != 5) { fp_dbg("unexpected length for interrupt transfer in M_ACTIVATE_AWAIT_FINGER"); //TODO: fail here, exit ssm. } if (memcmp(vfs_dev->tmpbuf, vfs0050_valid_interrupt, 5) != 0) { fp_dbg("invalid interrupt data in M_ACTIVATE_AWAIT_FINGER"); //TODO: fail here, exit ssm. } fpi_imgdev_report_finger_status(dev, TRUE); //report finger on to libfprint fpi_ssm_next_state(ssm); } else { fpi_ssm_mark_completed(ssm); //break fall through } break; case M_ACTIVATE_RECEIVE_FINGERPRINT: if (transfer->actual_length == 0) { libusb_free_transfer(transfer); fpi_ssm_next_state(ssm); break; } vfs_dev->scanbuf_idx += transfer->actual_length; libusb_free_transfer(transfer); fpi_ssm_jump_to_state(ssm, M_ACTIVATE_RECEIVE_FINGERPRINT); break; default: libusb_free_transfer(transfer); fpi_ssm_next_state(ssm); break; } }
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); }