1bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/* 2bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * libusb example program to manipulate U.are.U 4000B fingerprint scanner. 3bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> 4bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 5bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Basic image capture program only, does not consider the powerup quirks or 6bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * the fact that image encryption may be enabled. Not expected to work 7bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * flawlessly all of the time. 8bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 9bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * This library is free software; you can redistribute it and/or 10bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * modify it under the terms of the GNU Lesser General Public 11bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * License as published by the Free Software Foundation; either 12bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * version 2.1 of the License, or (at your option) any later version. 13bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 14bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * This library is distributed in the hope that it will be useful, 15bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * but WITHOUT ANY WARRANTY; without even the implied warranty of 16bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Lesser General Public License for more details. 18bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 19bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * You should have received a copy of the GNU Lesser General Public 20bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * License along with this library; if not, write to the Free Software 21bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev */ 23bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 24bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <errno.h> 25bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <pthread.h> 26bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <signal.h> 27bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <string.h> 28bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <stdio.h> 29bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <stdlib.h> 30bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 31bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <libusb/libusb.h> 32bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 33bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#define EP_INTR (1 | LIBUSB_ENDPOINT_IN) 34bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#define EP_DATA (2 | LIBUSB_ENDPOINT_IN) 35bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) 36bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT) 37bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#define USB_RQ 0x04 38bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#define INTR_LENGTH 64 39bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 40bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevenum { 41bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev MODE_INIT = 0x00, 42bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev MODE_AWAIT_FINGER_ON = 0x10, 43bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev MODE_AWAIT_FINGER_OFF = 0x12, 44bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev MODE_CAPTURE = 0x20, 45bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev MODE_SHUT_UP = 0x30, 46bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev MODE_READY = 0x80, 47bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev}; 48bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 49bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int next_state(void); 50bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 51bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevenum { 52bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1, 53bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev STATE_AWAIT_IRQ_FINGER_DETECTED, 54bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev STATE_AWAIT_MODE_CHANGE_CAPTURE, 55bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev STATE_AWAIT_IMAGE, 56bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF, 57bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev STATE_AWAIT_IRQ_FINGER_REMOVED, 58bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev}; 59bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 60bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int state = 0; 61bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic struct libusb_device_handle *devh = NULL; 62bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic unsigned char imgbuf[0x1b340]; 63bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic unsigned char irqbuf[INTR_LENGTH]; 64bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic struct libusb_transfer *img_transfer = NULL; 65bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic struct libusb_transfer *irq_transfer = NULL; 66bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int img_idx = 0; 67bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int do_exit = 0; 68bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 69bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic pthread_t poll_thread; 70bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER; 71bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic pthread_mutex_t exit_cond_lock = PTHREAD_MUTEX_INITIALIZER; 72bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 73bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void request_exit(int code) 74bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 75bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev do_exit = code; 76bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_cond_signal(&exit_cond); 77bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 78bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 79bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void *poll_thread_main(void *arg) 80bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 81bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r = 0; 82bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("poll thread running\n"); 83bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 84bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while (!do_exit) { 85bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct timeval tv = { 1, 0 }; 86bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_handle_events_timeout(NULL, &tv); 87bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 88bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(2); 89bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 90bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 91bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 92bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 93bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("poll thread shutting down\n"); 94bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_exit(NULL); 95bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 96bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 97bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int find_dpfp_device(void) 98bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 99bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a); 100bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return devh ? 0 : -EIO; 101bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 102bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 103bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int print_f0_data(void) 104bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 105bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char data[0x10]; 106bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 107bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned int i; 108bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 109bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data, 110bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sizeof(data), 0); 111bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 112bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "F0 error %d\n", r); 113bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 114bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 115bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if ((unsigned int) r < sizeof(data)) { 116bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "short read (%d)\n", r); 117bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -1; 118bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 119bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 120bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("F0 data:"); 121bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0; i < sizeof(data); i++) 122bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("%02x ", data[i]); 123bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("\n"); 124bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 125bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 126bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 127bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int get_hwstat(unsigned char *status) 128bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 129bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 130bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 131bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0); 132bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 133bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "read hwstat error %d\n", r); 134bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 135bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 136bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if ((unsigned int) r < 1) { 137bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "short read (%d)\n", r); 138bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -1; 139bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 140bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 141bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("hwstat reads %02x\n", *status); 142bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 143bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 144bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 145bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int set_hwstat(unsigned char data) 146bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 147bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 148bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 149bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("set hwstat to %02x\n", data); 150bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0); 151bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 152bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "set hwstat error %d\n", r); 153bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 154bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 155bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if ((unsigned int) r < 1) { 156bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "short write (%d)", r); 157bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -1; 158bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 159bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 160bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 161bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 162bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 163bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int set_mode(unsigned char data) 164bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 165bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 166bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("set mode %02x\n", data); 167bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 168bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0); 169bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 170bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "set mode error %d\n", r); 171bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 172bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 173bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if ((unsigned int) r < 1) { 174bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "short write (%d)", r); 175bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -1; 176bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 177bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 178bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 179bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 180bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 181bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void cb_mode_changed(struct libusb_transfer *transfer) 182bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 183bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { 184bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "mode change transfer not completed!\n"); 185bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(2); 186bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 187bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 188bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("async cb_mode_changed length=%d actual_length=%d\n", 189bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev transfer->length, transfer->actual_length); 190bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (next_state() < 0) 191bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(2); 192bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 193bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 194bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int set_mode_async(unsigned char data) 195bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 196bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); 197bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_transfer *transfer; 198bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 199bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!buf) 200bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -ENOMEM; 201bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 202bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev transfer = libusb_alloc_transfer(0); 203bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!transfer) { 204bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free(buf); 205bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -ENOMEM; 206bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 207bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 208bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("async set mode %02x\n", data); 209bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1); 210bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev buf[LIBUSB_CONTROL_SETUP_SIZE] = data; 211bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL, 212bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1000); 213bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 214bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK 215bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev | LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; 216bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return libusb_submit_transfer(transfer); 217bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 218bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 219bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int do_sync_intr(unsigned char *data) 220bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 221bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 222bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int transferred; 223bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 224bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH, 225bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev &transferred, 1000); 226bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 227bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "intr error %d\n", r); 228bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 229bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 230bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (transferred < INTR_LENGTH) { 231bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "short read (%d)\n", r); 232bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -1; 233bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 234bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 235bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("recv interrupt %04x\n", *((uint16_t *) data)); 236bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 237bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 238bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 239bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int sync_intr(unsigned char type) 240bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 241bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 242bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char data[INTR_LENGTH]; 243bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 244bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while (1) { 245bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = do_sync_intr(data); 246bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 247bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 248bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (data[0] == type) 249bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 250bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 251bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 252bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 253bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int save_to_file(unsigned char *data) 254bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 255bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev FILE *fd; 256bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev char filename[64]; 257bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 258bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sprintf(filename, "finger%d.pgm", img_idx++); 259bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fd = fopen(filename, "w"); 260bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!fd) 261bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -1; 262bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 263bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fputs("P5 384 289 255 ", fd); 264bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fwrite(data + 64, 1, 384*289, fd); 265bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fclose(fd); 266bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("saved image to %s\n", filename); 267bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 268bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 269bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 270bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int next_state(void) 271bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 272bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r = 0; 273bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("old state: %d\n", state); 274bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev switch (state) { 275bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case STATE_AWAIT_IRQ_FINGER_REMOVED: 276bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON; 277bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = set_mode_async(MODE_AWAIT_FINGER_ON); 278bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 279bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON: 280bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev state = STATE_AWAIT_IRQ_FINGER_DETECTED; 281bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 282bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case STATE_AWAIT_IRQ_FINGER_DETECTED: 283bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev state = STATE_AWAIT_MODE_CHANGE_CAPTURE; 284bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = set_mode_async(MODE_CAPTURE); 285bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 286bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case STATE_AWAIT_MODE_CHANGE_CAPTURE: 287bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev state = STATE_AWAIT_IMAGE; 288bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 289bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case STATE_AWAIT_IMAGE: 290bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF; 291bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = set_mode_async(MODE_AWAIT_FINGER_OFF); 292bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 293bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF: 294bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev state = STATE_AWAIT_IRQ_FINGER_REMOVED; 295bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 296bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev default: 297bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("unrecognised state %d\n", state); 298bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 299bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 300bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "error detected changing state\n"); 301bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 302bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 303bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 304bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("new state: %d\n", state); 305bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 306bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 307bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 308bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void cb_irq(struct libusb_transfer *transfer) 309bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 310bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char irqtype = transfer->buffer[0]; 311bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 312bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { 313bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "irq transfer status %d?\n", transfer->status); 314bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev irq_transfer = NULL; 315bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(2); 316bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return; 317bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 318bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 319bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("IRQ callback %02x\n", irqtype); 320bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev switch (state) { 321bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case STATE_AWAIT_IRQ_FINGER_DETECTED: 322bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (irqtype == 0x01) { 323bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (next_state() < 0) { 324bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(2); 325bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return; 326bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 327bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } else { 328bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("finger-on-sensor detected in wrong state!\n"); 329bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 330bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 331bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case STATE_AWAIT_IRQ_FINGER_REMOVED: 332bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (irqtype == 0x02) { 333bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (next_state() < 0) { 334bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(2); 335bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return; 336bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 337bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } else { 338bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("finger-on-sensor detected in wrong state!\n"); 339bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 340bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 341bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 342bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (libusb_submit_transfer(irq_transfer) < 0) 343bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(2); 344bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 345bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 346bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void cb_img(struct libusb_transfer *transfer) 347bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 348bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { 349bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "img transfer status %d?\n", transfer->status); 350bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev img_transfer = NULL; 351bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(2); 352bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return; 353bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 354bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 355bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("Image callback\n"); 356bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev save_to_file(imgbuf); 357bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (next_state() < 0) { 358bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(2); 359bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return; 360bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 361bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (libusb_submit_transfer(img_transfer) < 0) 362bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(2); 363bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 364bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 365bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int init_capture(void) 366bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 367bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 368bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 369bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_submit_transfer(irq_transfer); 370bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 371bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 372bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 373bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_submit_transfer(img_transfer); 374bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 375bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_cancel_transfer(irq_transfer); 376bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while (irq_transfer) 377bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (libusb_handle_events(NULL) < 0) 378bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 379bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 380bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 381bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 382bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* start state machine */ 383bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev state = STATE_AWAIT_IRQ_FINGER_REMOVED; 384bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return next_state(); 385bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 386bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 387bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int do_init(void) 388bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 389bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char status; 390bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 391bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 392bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = get_hwstat(&status); 393bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 394bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 395bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 396bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!(status & 0x80)) { 397bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = set_hwstat(status | 0x80); 398bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 399bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 400bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = get_hwstat(&status); 401bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 402bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 403bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 404bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 405bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev status &= ~0x80; 406bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = set_hwstat(status); 407bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 408bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 409bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 410bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = get_hwstat(&status); 411bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 412bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 413bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 414bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = sync_intr(0x56); 415bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 416bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 417bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 418bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 419bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 420bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 421bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int alloc_transfers(void) 422bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 423bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev img_transfer = libusb_alloc_transfer(0); 424bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!img_transfer) 425bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -ENOMEM; 426bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 427bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev irq_transfer = libusb_alloc_transfer(0); 428bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!irq_transfer) 429bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -ENOMEM; 430bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 431bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf, 432bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sizeof(imgbuf), cb_img, NULL, 0); 433bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf, 434bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sizeof(irqbuf), cb_irq, NULL, 0); 435bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 436bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 437bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 438bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 439bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void sighandler(int signum) 440bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 441bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(1); 442bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 443bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 444bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevint main(void) 445bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 446bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct sigaction sigact; 447bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r = 1; 448bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 449bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_init(NULL); 450bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 451bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "failed to initialise libusb\n"); 452bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev exit(1); 453bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 454bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 455bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = find_dpfp_device(); 456bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 457bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "Could not find/open device\n"); 458bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto out; 459bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 460bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 461bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_claim_interface(devh, 0); 462bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 463bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r)); 464bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto out; 465bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 466bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("claimed interface\n"); 467bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 468bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = print_f0_data(); 469bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 470bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto out_release; 471bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 472bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = do_init(); 473bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 474bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto out_deinit; 475bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 476bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* async from here onwards */ 477bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 478bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sigact.sa_handler = sighandler; 479bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sigemptyset(&sigact.sa_mask); 480bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sigact.sa_flags = 0; 481bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sigaction(SIGINT, &sigact, NULL); 482bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sigaction(SIGTERM, &sigact, NULL); 483bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sigaction(SIGQUIT, &sigact, NULL); 484bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 485bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = pthread_create(&poll_thread, NULL, poll_thread_main, NULL); 486bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r) 487bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto out_deinit; 488bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 489bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = alloc_transfers(); 490bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 491bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(1); 492bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_join(poll_thread, NULL); 493bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto out_deinit; 494bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 495bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 496bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = init_capture(); 497bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 498bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(1); 499bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_join(poll_thread, NULL); 500bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto out_deinit; 501bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 502bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 503bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while (!do_exit) { 504bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_mutex_lock(&exit_cond_lock); 505bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_cond_wait(&exit_cond, &exit_cond_lock); 506bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_mutex_unlock(&exit_cond_lock); 507bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 508bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 509bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev printf("shutting down...\n"); 510bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_join(poll_thread, NULL); 511bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 512bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_cancel_transfer(irq_transfer); 513bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 514bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(1); 515bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto out_deinit; 516bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 517bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 518bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_cancel_transfer(img_transfer); 519bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 520bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request_exit(1); 521bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto out_deinit; 522bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 523bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 524bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while (img_transfer || irq_transfer) 525bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (libusb_handle_events(NULL) < 0) 526bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 527bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 528bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (do_exit == 1) 529bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = 0; 530bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev else 531bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = 1; 532bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 533bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevout_deinit: 534bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_free_transfer(img_transfer); 535bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_free_transfer(irq_transfer); 536bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev set_mode(0); 537bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev set_hwstat(0x80); 538bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevout_release: 539bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_release_interface(devh, 0); 540bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevout: 541bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_close(devh); 542bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_exit(NULL); 543bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r >= 0 ? r : -r; 544bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 545bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 546