/* Returns number of processed bytes */ static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data) { struct fpi_frame *stripe; unsigned char *stripdata; struct fp_img_dev *dev = ssm->priv; struct aesX660_dev *aesdev = dev->priv; stripe = g_malloc(aesdev->assembling_ctx->frame_width * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bpp */ stripdata = stripe->data; fp_dbg("Processing frame %.2x %.2x", data[AESX660_IMAGE_OK_OFFSET], data[AESX660_LAST_FRAME_OFFSET]); stripe->delta_x = (int8_t)data[AESX660_FRAME_DELTA_X_OFFSET]; stripe->delta_y = -(int8_t)data[AESX660_FRAME_DELTA_Y_OFFSET]; fp_dbg("Offset to previous frame: %d %d", stripe->delta_x, stripe->delta_y); if (data[AESX660_IMAGE_OK_OFFSET] == AESX660_IMAGE_OK) { memcpy(stripdata, data + AESX660_IMAGE_OFFSET, aesdev->assembling_ctx->frame_width * FRAME_HEIGHT / 2); aesdev->strips = g_slist_prepend(aesdev->strips, stripe); aesdev->strips_len++; return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT); } else { return 0; } }
static void capture_read_data_cb(struct libusb_transfer *transfer) { struct fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = ssm->priv; unsigned char *data = transfer->buffer; struct fp_img *img; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { fp_dbg("request is not completed, %d", transfer->status); fpi_ssm_mark_aborted(ssm, -EIO); goto out; } else if (transfer->length != transfer->actual_length) { fp_dbg("expected %d, sent %d bytes", transfer->length, transfer->actual_length); fpi_ssm_mark_aborted(ssm, -EPROTO); goto out; } img = fpi_img_new(IMAGE_SIZE); memcpy(img->data, data, IMAGE_SIZE); fpi_imgdev_image_captured(dev, img); fpi_imgdev_report_finger_status(dev, FALSE); fpi_ssm_mark_completed(ssm); out: g_free(transfer->buffer); libusb_free_transfer(transfer); }
static void finger_det_data_cb(struct libusb_transfer *transfer) { struct fp_img_dev *dev = transfer->user_data; struct upektc_dev *upekdev = dev->priv; unsigned char *data = transfer->buffer; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { fp_dbg("data transfer status %d\n", transfer->status); fpi_imgdev_session_error(dev, -EIO); goto out; } else if (transfer->length != transfer->actual_length) { fp_dbg("expected %d, got %d bytes", transfer->length, transfer->actual_length); fpi_imgdev_session_error(dev, -EPROTO); } if (finger_present(data, IMAGE_SIZE, upekdev->sum_threshold)) { /* finger present, start capturing */ fpi_imgdev_report_finger_status(dev, TRUE); start_capture(dev); } else { /* no finger, poll for a new histogram */ start_finger_detection(dev); } out: g_free(data); libusb_free_transfer(transfer); }
/** \ingroup img * A quick convenience function to save an image to a file in * <a href="http://netpbm.sourceforge.net/doc/pgm.html">PGM format</a>. * \param img the image to save * \param path the path to save the image. Existing files will be overwritten. * \returns 0 on success, non-zero on error. */ API_EXPORTED int fp_img_save_to_file(struct fp_img *img, char *path) { FILE *fd = fopen(path, "w"); size_t write_size = img->width * img->height; int r; if (!fd) { fp_dbg("could not open '%s' for writing: %d", path, errno); return -errno; } r = fprintf(fd, "P5 %d %d 255\n", img->width, img->height); if (r < 0) { fp_err("pgm header write failed, error %d", r); return r; } r = fwrite(img->data, 1, write_size, fd); if (r < write_size) { fp_err("short write (%d)", r); return -EIO; } fclose(fd); fp_dbg("written to '%s'", path); return 0; }
void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img) { struct fp_print_data *print; int r; fp_dbg(""); if (imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_IMAGE) { fp_dbg("ignoring due to current state %d", imgdev->action_state); return; } if (imgdev->action_result) { fp_dbg("not overwriting existing action result"); return; } r = sanitize_image(imgdev, &img); if (r < 0) { imgdev->action_result = r; fp_img_free(img); goto next_state; } fp_img_standardize(img); imgdev->acquire_img = img; r = fpi_img_to_print_data(imgdev, img, &print); if (r < 0) { fp_dbg("image to print data conversion error: %d", r); imgdev->action_result = FP_ENROLL_RETRY; goto next_state; } else if (img->minutiae->num < MIN_ACCEPTABLE_MINUTIAE) { fp_dbg("not enough minutiae, %d/%d", img->minutiae->num, MIN_ACCEPTABLE_MINUTIAE); fp_print_data_free(print); /* depends on FP_ENROLL_RETRY == FP_VERIFY_RETRY */ imgdev->action_result = FP_ENROLL_RETRY; goto next_state; } imgdev->acquire_data = print; switch (imgdev->action) { case IMG_ACTION_ENROLL: imgdev->action_result = FP_ENROLL_COMPLETE; break; case IMG_ACTION_VERIFY: verify_process_img(imgdev); break; case IMG_ACTION_IDENTIFY: identify_process_img(imgdev); break; default: BUG(); break; } next_state: imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF; dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF); }
static void et_read_poll_cb(struct libusb_transfer* transfer) { int len; char* br; int r; struct poll_data* adata=transfer->user_data; struct fpi_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); }
/** \ingroup dscv_print * Removes a discovered print from disk. After successful return of this * function, functions such as fp_dscv_print_get_finger() will continue to * operate as before, however calling fp_print_data_from_dscv_print() will * fail for obvious reasons. * \param print the discovered print to remove from disk * \returns 0 on success, negative on error */ API_EXPORTED int fp_dscv_print_delete(struct fp_dscv_print *print) { int r; fp_dbg("remove at %s", print->path); r = g_unlink(print->path); if (r < 0) fp_dbg("unlink failed with error %d", r); /* FIXME: cleanup empty directory */ return r; }
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 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); }
void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev, gboolean present) { int r = imgdev->action_result; struct fp_print_data *data = imgdev->acquire_data; struct fp_img *img = imgdev->acquire_img; fp_dbg(present ? "finger on sensor" : "finger removed"); if (present && imgdev->action_state == IMG_ACQUIRE_STATE_AWAIT_FINGER_ON) { dev_change_state(imgdev, IMGDEV_STATE_CAPTURE); imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_IMAGE; return; } else if (present || imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF) { fp_dbg("ignoring status report"); return; } /* clear these before reporting results to avoid complications with * call cascading in and out of the library */ imgdev->acquire_img = NULL; imgdev->acquire_data = NULL; /* finger removed, report results */ switch (imgdev->action) { case IMG_ACTION_ENROLL: fp_dbg("reporting enroll result"); fpi_drvcb_enroll_stage_completed(imgdev->dev, r, data, img); if (r > 0 && r != FP_ENROLL_COMPLETE && r != FP_ENROLL_FAIL) { imgdev->action_result = 0; imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON; dev_change_state(imgdev, IMG_ACQUIRE_STATE_AWAIT_FINGER_ON); } break; case IMG_ACTION_VERIFY: fpi_drvcb_report_verify_result(imgdev->dev, r, img); fp_print_data_free(data); break; case IMG_ACTION_IDENTIFY: fpi_drvcb_report_identify_result(imgdev->dev, r, imgdev->identify_match_offset, img); fp_print_data_free(data); break; default: fp_err("unhandled action %d", imgdev->action); break; } }
/** \ingroup print_data * Removes a stored print from disk previously saved with fp_print_data_save(). * \param dev the device that the print belongs to * \param finger the finger of the file you are deleting * \returns 0 on success, negative on error */ API_EXPORTED int fp_print_data_delete(struct fp_dev *dev, enum fp_finger finger) { int r; gchar *path = get_path_to_print(dev, finger); fp_dbg("remove finger %d at %s", finger, path); r = g_unlink(path); g_free(path); if (r < 0) fp_dbg("unlink failed with error %d", r); /* FIXME: cleanup empty directory */ return r; }
static void aesX660_read_response(struct fpi_ssm *ssm, size_t buf_len, libusb_transfer_cb_fn callback) { struct fp_img_dev *dev = ssm->priv; struct libusb_transfer *transfer = libusb_alloc_transfer(0); unsigned char *data; int r; if (!transfer) { fpi_ssm_mark_aborted(ssm, -ENOMEM); return; } data = g_malloc(buf_len); libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, buf_len, callback, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { fp_dbg("Failed to submit rx transfer: %d\n", r); g_free(data); libusb_free_transfer(transfer); fpi_ssm_mark_aborted(ssm, r); } }
static int dev_open(struct fp_img_dev *dev, unsigned long driver_data) { struct fpi_ssm *init_ssm; struct vfs0050_dev *vdev = NULL; int r; fp_dbg("dev_open called"); //TODO: this is probably frowned upon :/ but right now a reset is the only // way for me to know I'm working with a clean slate and the rest of this will work. // Will be trying to reverse engineer more of the protocol so I can avoid resetting // the device each time it's opened. libusb_reset_device(dev->udev); r = libusb_claim_interface(dev->udev, 0); if (r < 0) { fp_err("could not claim interface 0"); return r; } libusb_control_transfer(dev->udev, 0x00, 0x09, 0x0001, 0, NULL, 0, 100); vdev = g_malloc0(sizeof(struct vfs0050_dev)); vdev->scanbuf = g_malloc0(VFS0050_INITIAL_SCANBUF_SIZE); vdev->scanbuf_sz = VFS0050_INITIAL_SCANBUF_SIZE; vdev->calbuf = g_malloc0(VFS0050_INITIAL_SCANBUF_SIZE); vdev->calbuf_sz = VFS0050_INITIAL_SCANBUF_SIZE; dev->priv = vdev; init_ssm = fpi_ssm_new(dev->dev, state_init, M_INIT_NUMSTATES); init_ssm->priv = dev; fpi_ssm_start(init_ssm, state_init_complete); return 0; }
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 void sm_write_reg(struct fpi_ssm *ssm, unsigned char reg, unsigned char value) { struct fp_img_dev *dev = ssm->priv; struct libusb_transfer *transfer = libusb_alloc_transfer(0); unsigned char *data; int r; if (!transfer) { fpi_ssm_mark_aborted(ssm, -ENOMEM); return; } fp_dbg("set %02x=%02x", reg, value); data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_setup(data, CTRL_OUT, reg, value, 0, 0); libusb_fill_control_transfer(transfer, dev->udev, data, sm_write_reg_cb, ssm, CTRL_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { g_free(data); libusb_free_transfer(transfer); fpi_ssm_mark_aborted(ssm, r); } }
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 sm_exec_cmd(struct fpi_ssm *ssm, unsigned char cmd, unsigned char param) { struct fp_img_dev *dev = ssm->priv; struct libusb_transfer *transfer = libusb_alloc_transfer(0); unsigned char *data; int r; if (!transfer) { fpi_ssm_mark_aborted(ssm, -ENOMEM); return; } fp_dbg("cmd %02x param %02x", cmd, param); data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_setup(data, CTRL_IN, cmd, param, 0, 0); libusb_fill_control_transfer(transfer, dev->udev, data, sm_exec_cmd_cb, ssm, CTRL_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { g_free(data); libusb_free_transfer(transfer); fpi_ssm_mark_aborted(ssm, r); } }
struct fp_img *fpi_img_new(size_t length) { struct fp_img *img = g_malloc0(sizeof(*img) + length); fp_dbg("length=%zd", length); img->length = length; return img; }
void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status) { fp_dbg("status %d", status); switch (imgdev->action) { case IMG_ACTION_ENROLL: fpi_drvcb_enroll_started(imgdev->dev, status); break; case IMG_ACTION_VERIFY: fpi_drvcb_verify_started(imgdev->dev, status); break; case IMG_ACTION_IDENTIFY: fpi_drvcb_identify_started(imgdev->dev, status); break; case IMG_ACTION_CAPTURE: fpi_drvcb_capture_started(imgdev->dev, status); break; default: fp_err("unhandled action %d", imgdev->action); return; } if (status == 0) { imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON; dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON); } }
static void capture_run_state(struct fpi_ssm *ssm) { struct fp_img_dev *dev = ssm->priv; struct aesX660_dev *aesdev = dev->priv; switch (ssm->cur_state) { case CAPTURE_SEND_LED_CMD: aesX660_send_cmd(ssm, led_solid_cmd, sizeof(led_solid_cmd), aesX660_send_cmd_cb); break; case CAPTURE_SEND_CAPTURE_CMD: aesdev->buffer_size = 0; aesdev->buffer_max = AESX660_HEADER_SIZE; aesX660_send_cmd(ssm, aesdev->start_imaging_cmd, aesdev->start_imaging_cmd_len, aesX660_send_cmd_cb); break; case CAPTURE_READ_STRIPE_DATA: aesX660_read_response(ssm, AESX660_BULK_TRANSFER_SIZE, capture_read_stripe_data_cb); break; case CAPTURE_SET_IDLE: fp_dbg("Got %d frames\n", aesdev->strips_len); aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd), capture_set_idle_cmd_cb); break; } }
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev) { fp_dbg(""); switch (imgdev->action) { case IMG_ACTION_ENROLL: fpi_drvcb_enroll_stopped(imgdev->dev); break; case IMG_ACTION_VERIFY: fpi_drvcb_verify_stopped(imgdev->dev); break; case IMG_ACTION_IDENTIFY: fpi_drvcb_identify_stopped(imgdev->dev); break; case IMG_ACTION_CAPTURE: fpi_drvcb_capture_stopped(imgdev->dev); break; default: fp_err("unhandled action %d", imgdev->action); break; } imgdev->action = IMG_ACTION_NONE; imgdev->action_state = 0; }
static int load_from_file(char *path, struct fp_print_data **data) { gsize length; gchar *contents; GError *err = NULL; struct fp_print_data *fdata; fp_dbg("from %s", path); g_file_get_contents(path, &contents, &length, &err); if (err) { int r = err->code; fp_err("%s load failed: %s", path, err->message); g_error_free(err); /* FIXME interpret more error codes */ if (r == G_FILE_ERROR_NOENT) return -ENOENT; else return r; } fdata = fp_print_data_from_data(contents, length); g_free(contents); if (!fdata) return -EIO; *data = fdata; return 0; }
static void sync_open_cb(struct fp_dev *dev, int status, void *user_data) { struct sync_open_data *odata = user_data; fp_dbg("status %d", status); odata->dev = dev; odata->status = status; }
/** \ingroup dev * Performs an enroll stage. See \ref enrolling for an explanation of enroll * stages. * * If no enrollment is in process, this kicks of the process and runs the * first stage. If an enrollment is already in progress, calling this * function runs the next stage, which may well be the last. * * A negative error code may be returned from any stage. When this occurs, * further calls to the enroll function will start a new enrollment process, * i.e. a negative error code indicates that the enrollment process has been * aborted. These error codes only ever indicate unexpected internal errors * or I/O problems. * * The RETRY codes from #fp_enroll_result may be returned from any enroll * stage. These codes indicate that the scan was not succesful in that the * user did not position their finger correctly or similar. When a RETRY code * is returned, the enrollment stage is <b>not</b> advanced, so the next call * into this function will retry the current stage again. The current stage may * need to be retried several times. * * The fp_enroll_result#FP_ENROLL_FAIL code may be returned from any enroll * stage. This code indicates that even though the scans themselves have been * acceptable, data processing applied to these scans produces incomprehensible * results. In other words, the user may have been scanning a different finger * for each stage or something like that. Like negative error codes, this * return code indicates that the enrollment process has been aborted. * * The fp_enroll_result#FP_ENROLL_PASS code will only ever be returned for * non-final stages. This return code indicates that the scan was acceptable * and the next call into this function will advance onto the next enroll * stage. * * The fp_enroll_result#FP_ENROLL_COMPLETE code will only ever be returned * from the final enroll stage. It indicates that enrollment completed * successfully, and that print_data has been assigned to point to the * resultant enrollment data. The print_data parameter will not be modified * during any other enrollment stages, hence it is actually legal to pass NULL * as this argument for all but the final stage. * * If the device is an imaging device, it can also return the image from * the scan, even when the enroll fails with a RETRY or FAIL code. It is legal * to call this function even on non-imaging devices, just don't expect them to * provide images. * * \param dev the device * \param print_data a location to return the resultant enrollment data from * the final stage. Must be freed with fp_print_data_free() after use. * \param img location to store the scan image. accepts NULL for no image * storage. If an image is returned, it must be freed with fp_img_free() after * use. * \return negative code on error, otherwise a code from #fp_enroll_result */ API_EXPORTED int fp_enroll_finger_img(struct fp_dev *dev, struct fp_print_data **print_data, struct fp_img **img) { struct fp_driver *drv = dev->drv; int stage = dev->__enroll_stage; gboolean final = FALSE; gboolean stopped = FALSE; struct sync_enroll_data *edata = NULL; int r; fp_dbg(""); /* FIXME __enroll_stage is ugly, can we replace it by some function that * says whether we're enrolling or not, and then put __enroll_stage into * edata? */ if (stage == -1) { edata = g_malloc0(sizeof(struct sync_enroll_data)); r = fp_async_enroll_start(dev, sync_enroll_cb, edata); if (r < 0) { g_free(edata); return r; } dev->__enroll_stage = ++stage; } else if (stage >= dev->nr_enroll_stages) { fp_err("exceeding number of enroll stages for device claimed by " "driver %s (%d stages)", drv->name, dev->nr_enroll_stages); dev->__enroll_stage = -1; r = -EINVAL; final = TRUE;
static void start_finger_detection(struct fp_img_dev *dev) { int r; struct upektc_dev *upekdev = dev->priv; struct libusb_transfer *transfer; fp_dbg(""); if (upekdev->deactivating) { complete_deactivation(dev); return; } transfer = libusb_alloc_transfer(0); if (!transfer) { fpi_imgdev_session_error(dev, -ENOMEM); return; } libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_out, (unsigned char *)scan_cmd, UPEKTC_CMD_LEN, finger_det_cmd_cb, dev, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { libusb_free_transfer(transfer); fpi_imgdev_session_error(dev, r); } }
int fpi_img_detect_minutiae(struct fp_img *img) { struct fp_minutiae *minutiae; int r; int *direction_map, *low_contrast_map, *low_flow_map; int *high_curve_map, *quality_map; int map_w, map_h; unsigned char *bdata; int bw, bh, bd; GTimer *timer; if (img->flags & FP_IMG_STANDARDIZATION_FLAGS) { fp_err("cant detect minutiae for non-standardized image"); return -EINVAL; } /* Remove convex hull points from partial image */ if (img->flags & FP_IMG_PARTIAL) g_lfsparms_V2.remove_convex_hull_pts = TRUE; else g_lfsparms_V2.remove_convex_hull_pts = FALSE; /* 25.4 mm per inch */ timer = g_timer_new(); r = get_minutiae(&minutiae, &quality_map, &direction_map, &low_contrast_map, &low_flow_map, &high_curve_map, &map_w, &map_h, &bdata, &bw, &bh, &bd, img->data, img->width, img->height, 8, DEFAULT_PPI / (double)25.4, &g_lfsparms_V2); g_timer_stop(timer); fp_dbg("minutiae scan completed in %f secs", g_timer_elapsed(timer, NULL)); g_timer_destroy(timer); if (r) { fp_err("get minutiae failed, code %d", r); return r; } fp_dbg("detected %d minutiae", minutiae->num); img->minutiae = minutiae; img->binarized = bdata; free(quality_map); free(direction_map); free(low_contrast_map); free(low_flow_map); free(high_curve_map); return minutiae->num; }
static void complete_deactivation(struct fp_img_dev *dev) { struct upektc_dev *upekdev = dev->priv; fp_dbg(""); upekdev->deactivating = FALSE; fpi_imgdev_deactivate_complete(dev); }
static void activate_run_state(struct fpi_ssm *ssm) { struct fp_img_dev *dev = ssm->priv; struct aesX660_dev *aesdev = dev->priv; switch (ssm->cur_state) { case ACTIVATE_SET_IDLE: aesdev->init_seq_idx = 0; fp_dbg("Activate: set idle\n"); aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd), aesX660_send_cmd_cb); break; case ACTIVATE_SEND_READ_ID_CMD: fp_dbg("Activate: read ID\n"); aesX660_send_cmd(ssm, read_id_cmd, sizeof(read_id_cmd), aesX660_send_cmd_cb); break; case ACTIVATE_READ_ID: /* Should return 8-byte response */ aesX660_read_response(ssm, 8, activate_read_id_cb); break; case ACTIVATE_SEND_INIT_CMD: fp_dbg("Activate: send init seq #%d cmd #%d\n", aesdev->init_seq_idx, aesdev->init_cmd_idx); aesX660_send_cmd(ssm, aesdev->init_seq[aesdev->init_cmd_idx].cmd, aesdev->init_seq[aesdev->init_cmd_idx].len, aesX660_send_cmd_cb); break; case ACTIVATE_READ_INIT_RESPONSE: fp_dbg("Activate: read init response\n"); /* Should return 4-byte response */ aesX660_read_response(ssm, 4, activate_read_init_cb); break; case ACTIVATE_SEND_CALIBRATE_CMD: aesX660_send_cmd(ssm, calibrate_cmd, sizeof(calibrate_cmd), aesX660_send_cmd_cb); break; case ACTIVATE_READ_CALIBRATE_DATA: /* Should return 4-byte response */ aesX660_read_response(ssm, 4, aesX660_read_calibrate_data_cb); break; } }
static void register_driver(struct fp_driver *drv) { if (drv->id == 0) { fp_err("not registering driver %s: driver ID is 0", drv->name); return; } registered_drivers = g_slist_prepend(registered_drivers, (gpointer) drv); fp_dbg("registered driver %s", drv->name); }
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { fp_dbg("dev_activate called"); struct fpi_ssm *activate_ssm; activate_ssm = fpi_ssm_new(dev->dev, state_activate, M_ACTIVATE_NUMSTATES); activate_ssm->priv = dev; fpi_ssm_start(activate_ssm, state_activate_complete); return 0; }