/** \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; }
/** \ingroup img * Get a binarized form of a standardized scanned image. This is where the * fingerprint image has been "enhanced" and is a set of pure black ridges * on a pure white background. Internally, image processing happens on top * of the binarized image. * * The image must have been \ref img_std "standardized" otherwise this function * will fail. * * It is safe to binarize an image and free the original while continuing * to use the binarized version. * * You cannot binarize an image twice. * * \param img a standardized image * \returns a new image representing the binarized form of the original, or * NULL on error. Must be freed with fp_img_free() after use. */ API_EXPORTED struct fp_img *fp_img_binarize(struct fp_img *img) { struct fp_img *ret; int height = img->height; int width = img->width; int imgsize = height * width; if (img->flags & FP_IMG_BINARIZED_FORM) { fp_err("image already binarized"); return NULL; } if (!img->binarized) { int r = fpi_img_detect_minutiae(img); if (r < 0) return NULL; if (!img->binarized) { fp_err("no minutiae after successful detection?"); return NULL; } } ret = fpi_img_new(imgsize); ret->flags |= FP_IMG_BINARIZED_FORM; ret->width = width; ret->height = height; memcpy(ret->data, img->binarized, imgsize); return ret; }
/* check image properties and resize it if necessary. potentially returns a new * image after freeing the old one. */ static int sanitize_image(struct fp_img_dev *imgdev, struct fp_img **_img) { struct fp_driver *drv = imgdev->dev->drv; struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); struct fp_img *img = *_img; if (imgdrv->img_width > 0) { img->width = imgdrv->img_width; } else if (img->width <= 0) { fp_err("no image width assigned"); return -EINVAL; } if (imgdrv->img_height > 0) { img->height = imgdrv->img_height; } else if (img->height <= 0) { fp_err("no image height assigned"); return -EINVAL; } if (!fpi_img_is_sane(img)) { fp_err("image is not sane!"); return -EINVAL; } return 0; }
/* external interface for testing */ struct fp_img_dev *global_init(void) { int ret; struct fp_img_dev *dev; ret = libusb_init(&fpi_usb_ctx); if (ret != LIBUSB_SUCCESS) { fp_err("libusb_init failed %d", ret); goto cantclaim; } dev = malloc(sizeof(struct fp_img_dev)); if (dev == NULL) { fp_err("cannot allocate memory"); goto cantclaim; } dev->udev = libusb_open_device_with_vid_pid(fpi_usb_ctx, 0x1c7a, 0x0603); if (dev->udev == NULL) { fp_err("libusb_open_device_with_vid_pid failed"); free(dev); dev = NULL; goto cantclaim; } if (dev_init(dev, 0x0603)) dev = NULL; cantclaim: return dev; }
static int capture(struct fp_img_dev *dev, gboolean unconditional, struct fp_img **ret) { int i; int r; struct fp_img *img; unsigned char *data; unsigned char *ptr; r = aes_write_regv(dev, init_reqs, G_N_ELEMENTS(init_reqs)); if (r < 0) return r; img = fpi_img_new_for_imgdev(dev); data = g_malloc(DATA_BUFLEN); ptr = data; /* See the timeout explanation in the uru4000 driver for the reasoning * behind this silly loop. */ retry: r = usb_bulk_read(dev->udev, EP_IN, data, DATA_BUFLEN, 1000); if (r == -ETIMEDOUT) goto retry; if (r < 0) { fp_err("data read failed, error %d", r); goto err; } else if (r < DATA_BUFLEN) { fp_err("short data read (%d)", r); r = -EIO; goto err; } for (i = 0; i < NR_SUBARRAYS; i++) { fp_dbg("subarray header byte %02x", *ptr); ptr++; aes_assemble_image(ptr, 96, 16, img->data + (i * 96 * 16)); ptr += SUBARRAY_LEN; } img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED; *ret = img; g_free(data); return 0; err: g_free(data); fp_img_free(img); return r; }
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; }
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; }
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); } }
/** \ingroup print_data * Loads a previously stored print from disk. The print must have been saved * earlier using the fp_print_data_save() function. * * A return code of -ENOENT indicates that the fingerprint requested could not * be found. Other error codes (both positive and negative) are possible for * obscure error conditions (e.g. corruption). * * \param dev the device you are loading the print for * \param finger the finger of the file you are loading * \param data output location to put the corresponding stored print. Must be * freed with fp_print_data_free() after use. * \returns 0 on success, non-zero on error */ API_EXPORTED int fp_print_data_load(struct fp_dev *dev, enum fp_finger finger, struct fp_print_data **data) { gchar *path; struct fp_print_data *fdata; int r; if (!base_store) storage_setup(); path = get_path_to_print(dev, finger); r = load_from_file(path, &fdata); g_free(path); if (r) return r; if (!fp_dev_supports_print_data(dev, fdata)) { fp_err("print data is not compatible!"); fp_print_data_free(fdata); return -EINVAL; } *data = fdata; return 0; }
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; }
/** \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 int dev_open(struct fp_img_dev *dev, unsigned long driver_data) { vfs301_dev_t *vdev = NULL; int r; /* Claim usb interface */ r = libusb_claim_interface(dev->udev, 0); if (r < 0) { /* Interface not claimed, return error */ fp_err("could not claim interface 0"); return r; } /* Set enroll stage number */ dev->dev->nr_enroll_stages = 1; /* Initialize private structure */ vdev = g_malloc0(sizeof(vfs301_dev_t)); dev->priv = vdev; vdev->scanline_buf = malloc(0); vdev->scanline_count = 0; /* Notify open complete */ fpi_imgdev_open_complete(dev, 0); return 0; }
int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img, struct fp_print_data **ret) { struct fp_print_data *print; int r; if (!img->minutiae) { r = fpi_img_detect_minutiae(img); if (r < 0) return r; if (!img->minutiae) { fp_err("no minutiae after successful detection?"); return -ENOENT; } } /* FIXME: space is wasted if we dont hit the max minutiae count. would * be good to make this dynamic. */ print = fpi_print_data_new(imgdev->dev, sizeof(struct xyt_struct)); print->type = PRINT_DATA_NBIS_MINUTIAE; minutiae_to_xyt(img->minutiae, img->width, img->height, print->data); /* FIXME: the print buffer at this point is endian-specific, and will * only work when loaded onto machines with identical endianness. not good! * data format should be platform-independent. */ *ret = print; return 0; }
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) { /* TODO check that device has endpoints we're using */ int r; struct aesX660_dev *aesdev; r = libusb_claim_interface(dev->udev, 0); if (r < 0) { fp_err("could not claim interface 0"); return r; } dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev)); aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE); aesdev->init_seqs[0] = aes1660_init_1; aesdev->init_seqs_len[0] = array_n_elements(aes1660_init_1); aesdev->init_seqs[1] = aes1660_init_2; aesdev->init_seqs_len[1] = array_n_elements(aes1660_init_2); aesdev->start_imaging_cmd = (unsigned char *)aes1660_start_imaging_cmd; aesdev->start_imaging_cmd_len = sizeof(aes1660_start_imaging_cmd); aesdev->frame_width = FRAME_WIDTH; aesdev->extra_img_flags = FP_IMG_PARTIAL; fpi_imgdev_open_complete(dev, 0); return 0; }
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) { int r; struct aes3k_dev *aesdev; r = libusb_claim_interface(dev->udev, 0); if (r < 0) fp_err("could not claim interface 0"); aesdev = dev->priv = g_malloc0(sizeof(struct aes3k_dev)); if (!aesdev) return -ENOMEM; if (r == 0) aesdev->data_buflen = DATA_BUFLEN; aesdev->frame_width = FRAME_WIDTH; aesdev->frame_size = FRAME_SIZE; aesdev->frame_number = FRAME_NUMBER; aesdev->enlarge_factor = ENLARGE_FACTOR; aesdev->init_reqs = init_reqs; aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs); fpi_imgdev_open_complete(dev, 0); return 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 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); }
/** \ingroup print_data * Saves a stored print to disk, assigned to a specific finger. Even though * you are limited to storing only the 10 human fingers, this is a * per-device-type limit. For example, you can store the users right index * finger from a DigitalPersona scanner, and you can also save the right index * finger from a UPEK scanner. When you later come to load the print, the right * one will be automatically selected. * * This function will unconditionally overwrite a fingerprint previously * saved for the same finger and device type. The print is saved in a hidden * directory beneath the current user's home directory. * \param data the stored print to save to disk * \param finger the finger that this print corresponds to * \returns 0 on success, non-zero on error. */ API_EXPORTED int fp_print_data_save(struct fp_print_data *data, enum fp_finger finger) { GError *err = NULL; char *path; char *dirpath; unsigned char *buf; size_t len; int r; if (!base_store) storage_setup(); fp_dbg("save %s print from driver %04x", finger_num_to_str(finger), data->driver_id); len = fp_print_data_get_data(data, &buf); if (!len) return -ENOMEM; path = __get_path_to_print(data->driver_id, data->devtype, finger); dirpath = g_path_get_dirname(path); r = g_mkdir_with_parents(dirpath, DIR_PERMS); if (r < 0) { fp_err("couldn't create storage directory"); g_free(path); g_free(dirpath); return r; } fp_dbg("saving to %s", path); g_file_set_contents(path, buf, len, &err); free(buf); g_free(dirpath); g_free(path); if (err) { r = err->code; fp_err("save failed: %s", err->message); g_error_free(err); /* FIXME interpret error codes */ return r; } return 0; }
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) { int r; r = usb_claim_interface(dev->udev, 0); if (r < 0) { fp_err("could not claim interface 0"); return r; } return 0; }
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv) { switch (drv->type) { case DRIVER_PRIMITIVE: return PRINT_DATA_RAW; case DRIVER_IMAGING: return PRINT_DATA_NBIS_MINUTIAE; default: fp_err("unrecognised drv type %d", drv->type); return PRINT_DATA_RAW; } }
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) { /* TODO check that device has endpoints we're using */ int r; struct upektc_dev *upekdev; r = libusb_claim_interface(dev->udev, 0); if (r < 0) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } dev->priv = upekdev = g_malloc0(sizeof(struct upektc_dev)); switch (driver_data) { case UPEKTC_2015: upekdev->ep_in = UPEKTC_EP_IN; upekdev->ep_out = UPEKTC_EP_OUT; upekdev->setup_commands = upektc_setup_commands; upekdev->setup_commands_len = array_n_elements(upektc_setup_commands); upekdev->sum_threshold = UPEKTC_SUM_THRESHOLD; break; case UPEKTC_3001: upekdev->ep_in = UPEKET_EP_IN; upekdev->ep_out = UPEKET_EP_OUT; upekdev->setup_commands = upeket_setup_commands; upekdev->setup_commands_len = array_n_elements(upeket_setup_commands); upekdev->sum_threshold = UPEKET_SUM_THRESHOLD; break; default: fp_err("Device variant %d is not known\n", driver_data); g_free(upekdev); dev->priv = NULL; return -ENODEV; break; } fpi_imgdev_open_complete(dev, 0); return 0; }
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) { int r; dev->priv = g_malloc0(sizeof(struct v5s_dev)); r = libusb_claim_interface(dev->udev, 0); if (r < 0) fp_err("could not claim interface 0: %s", libusb_error_name(r)); if (r == 0) fpi_imgdev_open_complete(dev, 0); return r; }
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; } }
int fpi_img_compare_print_data(struct fp_print_data *enrolled_print, struct fp_print_data *new_print) { int score, max_score = 0, probe_len; struct xyt_struct *pstruct = NULL; struct xyt_struct *gstruct = NULL; struct fp_print_data_item *data_item; GSList *list_item; if (enrolled_print->type != PRINT_DATA_NBIS_MINUTIAE || new_print->type != PRINT_DATA_NBIS_MINUTIAE) { fp_err("invalid print format"); return -EINVAL; } if (g_slist_length(new_print->prints) != 1) { fp_err("new_print contains more than one sample, is it enrolled print?"); return -EINVAL; } data_item = new_print->prints->data; pstruct = (struct xyt_struct *)data_item->data; probe_len = bozorth_probe_init(pstruct); list_item = enrolled_print->prints; do { data_item = list_item->data; gstruct = (struct xyt_struct *)data_item->data; score = bozorth_to_gallery(probe_len, pstruct, gstruct); fp_dbg("score %d", score); max_score = max(score, max_score); list_item = g_slist_next(list_item); } while (list_item); return max_score; }
static int generic_acquire_start(struct fp_dev *dev, int action) { struct fp_img_dev *imgdev = dev->priv; int r; fp_dbg("action %d", action); imgdev->action = action; imgdev->action_state = IMG_ACQUIRE_STATE_ACTIVATING; r = dev_activate(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON); if (r < 0) fp_err("activation failed with error %d", r); return r; }
/* Submit asynchronous sleep */ static void async_sleep(unsigned int msec, struct fpi_ssm *ssm) { struct fp_img_dev *dev = ssm->priv; struct fpi_timeout *timeout; /* Add timeout */ timeout = fpi_timeout_add(msec, async_sleep_cb, ssm); if (timeout == NULL) { /* Failed to add timeout */ fp_err("failed to add timeout"); fpi_imgdev_session_error(dev, -ETIME); fpi_ssm_mark_aborted(ssm, -ETIME); } }
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) { int r; r = libusb_claim_interface(dev->udev, 0); if (r < 0) { fp_err("could not claim interface 0"); return r; } //dev->dev->nr_enroll_stages=3; dev->priv = g_malloc0(sizeof(struct etss801u_dev)); fpi_imgdev_open_complete(dev, 0); return 0; }
static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf, size_t buflen) { size_t total_data_len, item_len; struct fp_print_data *data; struct fp_print_data_item *item; struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf; unsigned char *raw_buf; struct fpi_print_data_item_fp2 *raw_item; total_data_len = buflen - sizeof(*raw); data = print_data_new(GUINT16_FROM_LE(raw->driver_id), GUINT32_FROM_LE(raw->devtype), raw->data_type); raw_buf = raw->data; while (total_data_len) { if (total_data_len < sizeof(*raw_item)) break; total_data_len -= sizeof(*raw_item); raw_item = (struct fpi_print_data_item_fp2 *)raw_buf; item_len = GUINT32_FROM_LE(raw_item->length); fp_dbg("item len %d, total_data_len %d", item_len, total_data_len); if (total_data_len < item_len) { fp_err("corrupted fingerprint data"); break; } total_data_len -= item_len; item = fpi_print_data_item_new(item_len); /* FIXME: fp_print_data->data content is not endianess agnostic */ memcpy(item->data, raw_item->data, item_len); data->prints = g_slist_prepend(data->prints, item); raw_buf += sizeof(*raw_item); raw_buf += item_len; } if (g_slist_length(data->prints) == 0) { fp_print_data_free(data); data = NULL; } return data; }
void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error) { fp_dbg("error %d", error); BUG_ON(error == 0); switch (imgdev->action) { case IMG_ACTION_ENROLL: fpi_drvcb_enroll_stage_completed(imgdev->dev, error, NULL, NULL); break; case IMG_ACTION_VERIFY: fpi_drvcb_report_verify_result(imgdev->dev, error, NULL); break; case IMG_ACTION_IDENTIFY: fpi_drvcb_report_identify_result(imgdev->dev, error, 0, NULL); break; default: fp_err("unhandled action %d", imgdev->action); break; } }
struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int factor) { Image *mimg; Image *resized; ExceptionInfo exception; MagickBooleanType ret; int new_width = img->width * factor; int new_height = img->height * factor; struct fp_img *newimg; /* It is possible to implement resizing using a simple algorithm, however * we use ImageMagick because it applies some kind of smoothing to the * result, which improves matching performances in my experiments. */ if (!IsMagickInstantiated()) InitializeMagick(NULL); GetExceptionInfo(&exception); mimg = ConstituteImage(img->width, img->height, "I", CharPixel, img->data, &exception); GetExceptionInfo(&exception); resized = ResizeImage(mimg, new_width, new_height, 0, 1.0, &exception); newimg = fpi_img_new(new_width * new_height); newimg->width = new_width; newimg->height = new_height; newimg->flags = img->flags; GetExceptionInfo(&exception); ret = ExportImagePixels(resized, 0, 0, new_width, new_height, "I", CharPixel, newimg->data, &exception); if (ret != MagickTrue) { fp_err("export failed"); return NULL; } DestroyImage(mimg); DestroyImage(resized); return newimg; }