diff options
author | Daniel Drake <dsd@gentoo.org> | 2007-11-28 13:48:45 +0000 |
---|---|---|
committer | Daniel Drake <dsd@gentoo.org> | 2007-12-02 22:54:59 +0000 |
commit | 852bba4754ec57679c823f33e8feba6e4a564cbe (patch) | |
tree | cd0a73c5437d1e05799b7bbef047854afdc9939a /examples | |
download | libusb-852bba4754ec57679c823f33e8feba6e4a564cbe.tar.gz |
Initial commit
Basic library structure which supports enumerating detected USB devices
Diffstat (limited to 'examples')
-rw-r--r-- | examples/Makefile.am | 9 | ||||
-rw-r--r-- | examples/dpfp.c | 556 | ||||
-rw-r--r-- | examples/lsusb.c | 46 |
3 files changed, 611 insertions, 0 deletions
diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000..8aa3cc2 --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,9 @@ +INCLUDES = -I$(top_srcdir) +noinst_PROGRAMS = lsusb dpfp + +lsusb_SOURCES = lsusb.c +lsusb_LDADD = ../libfpusb/libfpusb.la -lfpusb + +dpfp_SOURCES = dpfp.c +dpfp_LDADD = ../libfpusb/libfpusb.la -lfpusb + diff --git a/examples/dpfp.c b/examples/dpfp.c new file mode 100644 index 0000000..e5aed9f --- /dev/null +++ b/examples/dpfp.c @@ -0,0 +1,556 @@ +/* + * fpusb example program to manipulate U.are.U 4000B fingerprint scanner. + * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> + * + * Basic image capture program only, does not consider the powerup quirks or + * the fact that image encryption may be enabled. Not expected to work + * flawlessly all of the time. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <signal.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#include <libfpusb/fpusb.h> + +#define EP_INTR (1 | USB_ENDPOINT_IN) +#define EP_DATA (2 | USB_ENDPOINT_IN) +#define CTRL_IN (USB_TYPE_VENDOR | USB_ENDPOINT_IN) +#define CTRL_OUT (USB_TYPE_VENDOR | USB_ENDPOINT_OUT) +#define USB_RQ 0x04 +#define INTR_LENGTH 64 + +enum { + MODE_INIT = 0x00, + MODE_AWAIT_FINGER_ON = 0x10, + MODE_AWAIT_FINGER_OFF = 0x12, + MODE_CAPTURE = 0x20, + MODE_SHUT_UP = 0x30, + MODE_READY = 0x80, +}; + +static int next_state(void); +static int submit_irq_urb(void); +static int submit_img_urb(void); + +enum { + STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1, + STATE_AWAIT_IRQ_FINGER_DETECTED, + STATE_AWAIT_MODE_CHANGE_CAPTURE, + STATE_AWAIT_IMAGE, + STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF, + STATE_AWAIT_IRQ_FINGER_REMOVED, +}; + +static int state = 0; +static struct fpusb_dev_handle *devh = NULL; +static unsigned char imgbuf[0x1b340]; +static unsigned char irqbuf[INTR_LENGTH]; +static fpusb_urb_handle *img_urbh = NULL; +static fpusb_urb_handle *irq_urbh = NULL; +static int img_idx = 0; +static int do_exit = 0; + +static struct fpusb_bulk_msg imgmsg = { + .endpoint = EP_DATA, + .data = imgbuf, + .length = sizeof(imgbuf), +}; + +static struct fpusb_bulk_msg irqmsg = { + .endpoint = EP_INTR, + .data = irqbuf, + .length = sizeof(irqbuf), +}; + +static struct fpusb_dev *find_dpfp_device(void) +{ + struct fpusb_dev *dev; + + fpusb_find_devices(); + + for (dev = fpusb_get_devices(); dev; dev = fpusb_dev_next(dev)) { + struct usb_dev_descriptor *desc = fpusb_dev_get_descriptor(dev); + if (desc->idVendor == 0x05ba && desc->idProduct == 0x000a) + return dev; + } + + return NULL; +} + +static int print_f0_data(void) +{ + unsigned char data[0x10]; + struct fpusb_ctrl_msg msg = { + .requesttype = CTRL_IN, + .request = USB_RQ, + .value = 0xf0, + .index = 0, + .length = sizeof(data), + .data = data, + }; + int r; + unsigned int i; + + r = fpusb_ctrl_msg(devh, &msg, 0); + if (r < 0) { + fprintf(stderr, "F0 error %d\n", r); + return r; + } + if ((unsigned int) r < sizeof(data)) { + fprintf(stderr, "short read (%d)\n", r); + return -1; + } + + printf("F0 data:"); + for (i = 0; i < sizeof(data); i++) + printf("%02x ", data[i]); + printf("\n"); + return 0; +} + +static int get_hwstat(unsigned char *status) +{ + struct fpusb_ctrl_msg msg = { + .requesttype = CTRL_IN, + .request = USB_RQ, + .value = 0x07, + .index = 0, + .length = 1, + .data = status, + }; + int r; + + r = fpusb_ctrl_msg(devh, &msg, 0); + if (r < 0) { + fprintf(stderr, "read hwstat error %d\n", r); + return r; + } + if ((unsigned int) r < 1) { + fprintf(stderr, "short read (%d)\n", r); + return -1; + } + + printf("hwstat reads %02x\n", *status); + return 0; +} + +static int set_hwstat(unsigned char data) +{ + int r; + struct fpusb_ctrl_msg msg = { + .requesttype = CTRL_OUT, + .request = USB_RQ, + .value = 0x07, + .index = 0, + .length = 1, + .data = &data, + }; + + printf("set hwstat to %02x\n", data); + + r = fpusb_ctrl_msg(devh, &msg, 0); + if (r < 0) { + fprintf(stderr, "set hwstat error %d\n", r); + return r; + } + if ((unsigned int) r < 1) { + fprintf(stderr, "short write (%d)", r); + return -1; + } + + return 0; +} + +static int set_mode(unsigned char data) +{ + int r; + struct fpusb_ctrl_msg msg = { + .requesttype = CTRL_OUT, + .request = USB_RQ, + .value = 0x4e, + .index = 0, + .length = 1, + .data = &data, + }; + + printf("set mode %02x\n", data); + + r = fpusb_ctrl_msg(devh, &msg, 0); + if (r < 0) { + fprintf(stderr, "set mode error %d\n", r); + return r; + } + if ((unsigned int) r < 1) { + fprintf(stderr, "short write (%d)", r); + return -1; + } + + return 0; +} + +static void cb_mode_changed(struct fpusb_dev_handle *_devh, + struct fpusb_urb_handle *urbh, struct fpusb_ctrl_msg *msg, + enum fp_urb_cb_status status, unsigned char *data, int actual_length, + void *user_data) +{ + if (status != FP_URB_COMPLETED) { + fprintf(stderr, "mode change URB not completed!\n"); + do_exit = 2; + } + + printf("async cb_mode_changed\n"); + if (next_state() < 0) + do_exit = 2; +} + +static int set_mode_async(unsigned char data) +{ + fpusb_urb_handle *urbh; + struct fpusb_ctrl_msg msg = { + .requesttype = CTRL_OUT, + .request = USB_RQ, + .value = 0x4e, + .index = 0, + .length = 1, + .data = &data, + }; + + printf("async set mode %02x\n", data); + + urbh = fpusb_submit_ctrl_msg(devh, &msg, cb_mode_changed, NULL, 1000); + if (!urbh) { + fprintf(stderr, "set mode submit error\n"); + return -1; + } + + return 0; +} + +static int do_sync_intr(unsigned char *data) +{ + struct fpusb_bulk_msg msg = { + .endpoint = EP_INTR, + .data = data, + .length = INTR_LENGTH, + }; + int r; + int transferred; + + r = fpusb_intr_msg(devh, &msg, &transferred, 1000); + if (r < 0) { + fprintf(stderr, "intr error %d\n", r); + return r; + } + if (transferred < INTR_LENGTH) { + fprintf(stderr, "short read (%d)\n", r); + return -1; + } + + printf("recv interrupt %04x\n", *((uint16_t *) data)); + return 0; +} + +static int sync_intr(unsigned char type) +{ + int r; + unsigned char data[INTR_LENGTH]; + + while (1) { + r = do_sync_intr(data); + if (r < 0) + return r; + if (data[0] == type) + return 0; + } +} + +static int save_to_file(unsigned char *data) +{ + FILE *fd; + char filename[64]; + + sprintf(filename, "finger%d.pgm", img_idx++); + fd = fopen(filename, "w"); + if (!fd) + return -1; + + fputs("P5 384 289 255 ", fd); + fwrite(data + 64, 1, 384*289, fd); + fclose(fd); + printf("saved image to %s\n", filename); + return 0; +} + +static int next_state(void) +{ + int r = 0; + printf("old state: %d\n", state); + switch (state) { + case STATE_AWAIT_IRQ_FINGER_REMOVED: + state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON; + r = set_mode_async(MODE_AWAIT_FINGER_ON); + break; + case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON: + state = STATE_AWAIT_IRQ_FINGER_DETECTED; + break; + case STATE_AWAIT_IRQ_FINGER_DETECTED: + state = STATE_AWAIT_MODE_CHANGE_CAPTURE; + r = set_mode_async(MODE_CAPTURE); + break; + case STATE_AWAIT_MODE_CHANGE_CAPTURE: + state = STATE_AWAIT_IMAGE; + break; + case STATE_AWAIT_IMAGE: + state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF; + r = set_mode_async(MODE_AWAIT_FINGER_OFF); + break; + case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF: + state = STATE_AWAIT_IRQ_FINGER_REMOVED; + break; + default: + printf("unrecognised state %d\n", state); + } + if (r < 0) { + fprintf(stderr, "error detected changing state"); + return r; + } + + printf("new state: %d\n", state); + return 0; +} + +static void cb_irq(fpusb_dev_handle *_devh, fpusb_urb_handle *urbh, + struct fpusb_bulk_msg *msg, enum fp_urb_cb_status status, + int actual_length, void *user_data) +{ + unsigned char irqtype = msg->data[0]; + + if (status != FP_URB_COMPLETED) { + fprintf(stderr, "irq URB status %d?\n", status); + do_exit = 2; + return; + } + + printf("IRQ callback %02x\n", irqtype); + switch (state) { + case STATE_AWAIT_IRQ_FINGER_DETECTED: + if (irqtype == 0x01) { + if (next_state() < 0) { + do_exit = 2; + return; + } + } else { + printf("finger-on-sensor detected in wrong state!\n"); + } + break; + case STATE_AWAIT_IRQ_FINGER_REMOVED: + if (irqtype == 0x02) { + if (next_state() < 0) { + do_exit = 2; + return; + } + } else { + printf("finger-on-sensor detected in wrong state!\n"); + } + break; + } + if (submit_irq_urb() < 0) + do_exit = 2; +} + +static void cb_img(fpusb_dev_handle *_devh, fpusb_urb_handle *urbh, + struct fpusb_bulk_msg *msg, enum fp_urb_cb_status status, + int actual_length, void *user_data) +{ + if (status != FP_URB_COMPLETED) { + fprintf(stderr, "img URB status %d?\n", status); + do_exit = 2; + return; + } + + printf("Image callback\n"); + save_to_file(imgbuf); + if (next_state() < 0) { + do_exit = 2; + return; + } + if (submit_img_urb() < 0) + do_exit = 2; +} + +static int submit_irq_urb(void) +{ + fpusb_urb_handle_free(irq_urbh); + irq_urbh = fpusb_submit_intr_msg(devh, &irqmsg, cb_irq, NULL, 0); + return irq_urbh != NULL; +} + +static int submit_img_urb(void) +{ + fpusb_urb_handle_free(img_urbh); + img_urbh = fpusb_submit_bulk_msg(devh, &imgmsg, cb_img, NULL, 0); + return img_urbh != NULL; +} + +static int init_capture(void) +{ + int r; + + r = submit_irq_urb(); + if (r < 0) + return r; + + r = submit_img_urb(); + if (r < 0) { + fpusb_urb_handle_cancel_sync(devh, img_urbh); + return r; + } + + /* start state machine */ + state = STATE_AWAIT_IRQ_FINGER_REMOVED; + return next_state(); +} + +static int do_init(void) +{ + unsigned char status; + int r; + + r = get_hwstat(&status); + if (r < 0) + return r; + + if (!(status & 0x80)) { + r = set_hwstat(status | 0x80); + if (r < 0) + return r; + r = get_hwstat(&status); + if (r < 0) + return r; + } + + status &= ~0x80; + r = set_hwstat(status); + if (r < 0) + return r; + + r = get_hwstat(&status); + if (r < 0) + return r; + + r = sync_intr(0x56); + if (r < 0) + return r; + + return 0; +} + +static void sighandler(int signum) +{ + do_exit = 1; +} + +int main(void) +{ + struct fpusb_dev *dev; + struct sigaction sigact; + int r = 1; + + r = fpusb_init(0); + if (r < 0) { + fprintf(stderr, "failed to initialise fpusb\n"); + exit(1); + } + + dev = find_dpfp_device(); + if (!dev) { + fprintf(stderr, "No device found\n"); + goto out; + } + printf("found device\n"); + + devh = fpusb_dev_open(dev); + if (!devh) { + fprintf(stderr, "Could not open device\n"); + goto out; + } + printf("opened device\n"); + + r = fpusb_dev_claim_intf(devh, 0); + if (r < 0) { + fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r)); + goto out; + } + printf("claimed interface\n"); + + r = print_f0_data(); + if (r < 0) + goto out_release; + + r = do_init(); + if (r < 0) + goto out_deinit; + + /* async from here onwards */ + + r = init_capture(); + if (r < 0) + goto out_deinit; + + sigact.sa_handler = sighandler; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + sigaction(SIGQUIT, &sigact, NULL); + + while (!do_exit) { + r = fpusb_poll(); + if (r < 0) + goto out_deinit; + } + + printf("shutting down...\n"); + + r = fpusb_urb_handle_cancel_sync(devh, irq_urbh); + if (r < 0) + goto out_deinit; + + r = fpusb_urb_handle_cancel_sync(devh, img_urbh); + if (r < 0) + goto out_deinit; + + if (do_exit == 1) + r = 0; + else + r = 1; + +out_deinit: + fpusb_urb_handle_free(img_urbh); + fpusb_urb_handle_free(irq_urbh); + set_mode(0); + set_hwstat(0x80); +out_release: + fpusb_dev_release_intf(devh, 0); +out: + fpusb_dev_close(devh); + fpusb_exit(); + return r >= 0 ? r : -r; +} + diff --git a/examples/lsusb.c b/examples/lsusb.c new file mode 100644 index 0000000..00fb178 --- /dev/null +++ b/examples/lsusb.c @@ -0,0 +1,46 @@ +/* + * fpusb example program to list devices on the bus + * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> + +#include <libfpusb/fpusb.h> + +void print_devs(fpusb_dev *devs) +{ + fpusb_dev *dev; + + for (dev = devs; dev; dev = fpusb_dev_next(dev)) { + struct usb_dev_descriptor *desc = fpusb_dev_get_descriptor(dev); + printf("%04x:%04x\n", desc->idVendor, desc->idProduct); + } +} + +int main(void) +{ + fpusb_dev *devs; + fpusb_init(0); + fpusb_find_devices(); + devs = fpusb_get_devices(); + + print_devs(devs); + + fpusb_exit(); + return 0; +} + |