/* 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 int submit_image(struct fpi_ssm *ssm) { struct fp_img_dev *dev = ssm->priv; vfs301_dev_t *vdev = dev->priv; int height; struct fp_img *img; #if 0 /* XXX: This is probably handled by libfprint automagically? */ if (vdev->scanline_count < 20) { fpi_ssm_jump_to_state(ssm, M_REQUEST_PRINT); return 0; } #endif img = fpi_img_new(VFS301_FP_OUTPUT_WIDTH * vdev->scanline_count); if (img == NULL) return 0; vfs301_extract_image(vdev, img->data, &height); /* TODO: how to detect flip? should the resulting image be * oriented so that it is equal e.g. to a fingerprint on a paper, * or to the finger when I look at it?) */ img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED; img->width = VFS301_FP_OUTPUT_WIDTH; img->height = height; img = fpi_img_resize(img, img->height * img->width); fpi_imgdev_image_captured(dev, img); return 1; }
static void loop_run_state(struct fpi_ssm *ssm) { struct fp_img_dev *dev = ssm->priv; struct v5s_dev *vdev = dev->priv; switch (ssm->cur_state) { case LOOP_SET_CONTRAST: sm_write_reg(ssm, REG_CONTRAST, 0x01); break; case LOOP_SET_GAIN: sm_write_reg(ssm, REG_GAIN, 0x29); break; case LOOP_CMD_SCAN: if (vdev->deactivating) { fp_dbg("deactivating, marking completed"); fpi_ssm_mark_completed(ssm); } else sm_exec_cmd(ssm, CMD_SCAN, 0x00); break; case LOOP_CAPTURE: sm_do_capture(ssm); break; case LOOP_CAPTURE_DONE: fpi_ssm_jump_to_state(ssm, LOOP_CMD_SCAN); break; } }
static void upektc_next_init_cmd(struct fpi_ssm *ssm) { struct fp_img_dev *dev = ssm->priv; struct upektc_dev *upekdev = dev->priv; upekdev->init_idx += 1; if (upekdev->init_idx == upekdev->setup_commands_len) fpi_ssm_mark_completed(ssm); else fpi_ssm_jump_to_state(ssm, WRITE_INIT); }
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_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 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 activate_read_init_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; fp_dbg("read_init_cb\n"); if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || (transfer->length != transfer->actual_length)) { fp_dbg("read_init transfer status: %d, actual_len: %d\n", transfer->status, transfer->actual_length); fpi_ssm_mark_aborted(ssm, -EIO); goto out; } /* ID was read correctly */ if (data[0] != 0x42 || data[3] != 0x01) { fp_dbg("Bogus read init response: %.2x %.2x\n", data[0], data[3]); fpi_ssm_mark_aborted(ssm, -EPROTO); goto out; } aesdev->init_cmd_idx++; if (aesdev->init_cmd_idx == aesdev->init_seq_len) { if (aesdev->init_seq_idx < 2) fpi_ssm_jump_to_state(ssm, ACTIVATE_SEND_READ_ID_CMD); else fpi_ssm_mark_completed(ssm); goto out; } fpi_ssm_jump_to_state(ssm, ACTIVATE_SEND_INIT_CMD); out: 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 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 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); }