From 4c1c0deb058ff8781362fb17fa3f5d5ac7c440d9 Mon Sep 17 00:00:00 2001 From: "(no author)" <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> Date: Thu, 10 Aug 2006 21:27:01 +0000 Subject: - add my ausb library code for async usb handling - separate opcd_test code from core openpcd usb protocol handling routines git-svn-id: https://svn.openpcd.org:2342/trunk@99 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- openpcd/opcd_test/Makefile | 10 +- openpcd/opcd_test/ausb/Makefile | 21 +++ openpcd/opcd_test/ausb/ausb.c | 331 +++++++++++++++++++++++++++++++++++++ openpcd/opcd_test/ausb/ausb.h | 68 ++++++++ openpcd/opcd_test/ausb/ausb_test.c | 95 +++++++++++ openpcd/opcd_test/ausb/usb.c | 86 ++++++++++ openpcd/opcd_test/ausb/usb.h | 8 + openpcd/opcd_test/opcd_test.c | 147 ++-------------- openpcd/opcd_test/opcd_usb.c | 185 +++++++++++++++++++++ openpcd/opcd_test/opcd_usb.h | 23 +++ 10 files changed, 838 insertions(+), 136 deletions(-) create mode 100644 openpcd/opcd_test/ausb/Makefile create mode 100644 openpcd/opcd_test/ausb/ausb.c create mode 100644 openpcd/opcd_test/ausb/ausb.h create mode 100644 openpcd/opcd_test/ausb/ausb_test.c create mode 100644 openpcd/opcd_test/ausb/usb.c create mode 100644 openpcd/opcd_test/ausb/usb.h create mode 100644 openpcd/opcd_test/opcd_usb.c create mode 100644 openpcd/opcd_test/opcd_usb.h diff --git a/openpcd/opcd_test/Makefile b/openpcd/opcd_test/Makefile index 580e3a9..edae90f 100644 --- a/openpcd/opcd_test/Makefile +++ b/openpcd/opcd_test/Makefile @@ -5,11 +5,15 @@ all: opcd_test clean: -rm -f *.o opcd_test + $(MAKE) -C ausb clean -opcd_test: opcd_test.o - $(CC) $(LDFLAGS) -o $@ $< +ausb/libausb.a: + $(MAKE) -C ausb libausb.a -opcd_test.o: opcd_test.c +opcd_test: opcd_test.o opcd_usb.o ausb/libausb.a + $(CC) $(LDFLAGS) -o $@ $^ + +%.o: %.c $(CC) $(CFLAGS) -o $@ -c $< .PHONEY: all clean diff --git a/openpcd/opcd_test/ausb/Makefile b/openpcd/opcd_test/ausb/Makefile new file mode 100644 index 0000000..6269739 --- /dev/null +++ b/openpcd/opcd_test/ausb/Makefile @@ -0,0 +1,21 @@ +#include ../../makevars + +OBJS=ausb.o usb.o +CFLAGS+=-fPIC + +all: libausb.a libausb.so + +libausb.a: $(OBJS) + $(AR) r $@ $^ + +libausb.so: $(OBJS) + $(LD) -x --shared -o $@ $^ + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $^ + +ausb_test: ausb_test.o ausb.o + $(CC) $(CFLAGS) -lusb -o $@ $^ + +clean: + @rm -f *.o ausb_test libusb.a libausb.a libausb.so diff --git a/openpcd/opcd_test/ausb/ausb.c b/openpcd/opcd_test/ausb/ausb.c new file mode 100644 index 0000000..8b0117f --- /dev/null +++ b/openpcd/opcd_test/ausb/ausb.c @@ -0,0 +1,331 @@ +/* Wrapper/Extension code to libusb-0.1 to support asynchronous requests + * on Linux platforns + * + * (C) 2004-2005 by Harald Welte + * + * Distributed and licensed under the terms of GNU LGPL, Version 2.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ausb.h" +#include "usb.h" + +#ifdef DEBUG_AUSB +#define DEBUGP(x, args...) fprintf(stderr, "%s:%s():%u " x, __FILE__, \ + __FUNCTION__, __LINE__, ## args) +#else +#define DEBUGP(x, args...); +#endif + +#define SIGAUSB (SIGRTMIN+1) + +static int ausb_get_fd(ausb_dev_handle *ah) +{ + return *((int *)ah->uh); +} + + +static int kernel_2_5; + +/* FIXME: this has to go */ +static struct ausb_dev_handle *last_handle = NULL; + +static int is_kernel_2_5() +{ + struct utsname uts; + int ret; + + uname(&uts); + + ret = (strncmp(uts.release, "2.5.", 4) == 0) || + (strncmp(uts.release, "2.6.", 4) == 0); + + return ret; +} + +void ausb_dump_urb(struct usbdevfs_urb *uurb) +{ + DEBUGP("urb(%p): type=%u, endpoint=0x%x, status=%d, flags=0x%x, number_of_packets=%d, error_count=%d\n", uurb, uurb->type, uurb->endpoint, uurb->status, uurb->flags, uurb->number_of_packets, uurb->error_count); +} + +void ausb_fill_int_urb(struct usbdevfs_urb *uurb, unsigned char endpoint, + void *buffer, int buffer_length) + +{ + uurb->type = kernel_2_5 ? USBDEVFS_URB_TYPE_INTERRUPT : USBDEVFS_URB_TYPE_BULK; + uurb->endpoint = endpoint; /* | USB_DIR_IN; */ + uurb->flags = kernel_2_5 ? 0 : 1 ; /* USBDEVFS_URB_QUEUE_BULK; */ + uurb->buffer = buffer; + uurb->buffer_length = buffer_length; + uurb->signr = SIGAUSB; + uurb->start_frame = -1; +} + +int ausb_submit_urb(ausb_dev_handle *ah, struct usbdevfs_urb *uurb) +{ + int ret; + + DEBUGP("ah=%p\n", ah); + ausb_dump_urb(uurb); + + /* save ausb_dev_handle in opaque usercontext field */ + uurb->usercontext = ah; + + do { + ret = ioctl(ausb_get_fd(ah), USBDEVFS_SUBMITURB, uurb); + } while (ret < 0 && errno == EINTR); + + return ret; +} + +int ausb_discard_urb(ausb_dev_handle *ah, struct usbdevfs_urb *uurb) +{ + int ret; + + DEBUGP("ah=%p, uurb=%p\n"); + ausb_dump_urb(uurb); + + do { + ret = ioctl(ausb_get_fd(ah), USBDEVFS_DISCARDURB, uurb); + } while (ret < 0 && errno == EINTR); + + return ret; +} + +struct usbdevfs_urb *ausb_get_urb(ausb_dev_handle *ah) +{ + int ret; + struct usbdevfs_urb *uurb; + + DEBUGP("entering\n"); + + do { + ret = ioctl(ausb_get_fd(ah), USBDEVFS_REAPURBNDELAY, &uurb); + } while (ret < 0 && errno == EINTR); + + if (ret < 0 && errno == EAGAIN) { + DEBUGP("ioctl returned %d (errno=%s)\n", ret, + strerror(errno)); + return NULL; + } + + DEBUGP("returning %p\n", uurb); + return uurb; +} + +static void handle_urb(struct usbdevfs_urb *uurb) +{ + struct ausb_dev_handle *ah = uurb->usercontext; + + DEBUGP("called, ah=%p\n", ah); + + if (uurb->type >= AUSB_USBDEVFS_URB_TYPES) { + DEBUGP("unknown uurb type %u\n", uurb->type); + return; + } + + if (!ah) { + DEBUGP("cant't call handler because missing ah ptr\n"); + return; + } + + if (!ah->cb[uurb->type].handler) { + DEBUGP("received URB type %u, but no handler\n", uurb->type); + return; + } + ah->cb[uurb->type].handler(uurb, ah->cb[uurb->type].userdata); +} + +static void sigact_rtmin(int sig, siginfo_t *siginfo, void *v) +{ + int count; + struct usbdevfs_urb *urb; + + if (sig != SIGAUSB) + return; + + //DEBUGP("errno=%d, si_addr=%p\n", siginfo->errno, siginfo->si_addr); + + DEBUGP("last_handle=%p\n", last_handle); + + if (!last_handle) + return; + + for (count = 0; ; count++) { + urb = ausb_get_urb(last_handle); + + if (urb == NULL) { + DEBUGP("ausb_get_urb() returned urb==NULL\n"); + break; + } + + DEBUGP("calling handle_urb(%p)\n", urb); + handle_urb(urb); + } +} + + +int ausb_init(void) +{ + struct sigaction act; + + DEBUGP("entering\n"); + + memset(&act, 0, sizeof(act)); + act.sa_sigaction = sigact_rtmin; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + + sigaction(SIGAUSB, &act, NULL); + + kernel_2_5 = is_kernel_2_5(); + + DEBUGP("kernel 2.5+ = %d\n", kernel_2_5); + + usb_init(); + usb_find_busses(); + usb_find_devices(); + return 1; +} + +ausb_dev_handle *ausb_open(struct usb_device *dev) +{ + ausb_dev_handle *dh = malloc(sizeof *dh); + + DEBUGP("entering, dh=%p\n", dh); + + memset(dh, 0, sizeof(*dh)); + + dh->uh = usb_open(dev); + + if (!dh->uh) { + DEBUGP("usb_open() failed\n"); + free(dh); + return NULL; + } + + last_handle = dh; + DEBUGP("last_handle = %p\n", last_handle); + + return dh; +} + +int ausb_register_callback(ausb_dev_handle *ah, unsigned char type, + void (*callback)(struct usbdevfs_urb *uurb, + void *userdata), + void *userdata) +{ + DEBUGP("registering callback for type %u:%p\n", type, callback); + + if (type >= AUSB_USBDEVFS_URB_TYPES) { + errno = EINVAL; + return -1; + } + + if (!kernel_2_5 && type == USBDEVFS_URB_TYPE_INTERRUPT) + type = USBDEVFS_URB_TYPE_BULK; + + ah->cb[type].handler = callback; + ah->cb[type].userdata = userdata; + + return 0; +} + +int ausb_claim_interface(ausb_dev_handle *ah, int interface) +{ + DEBUGP("entering\n"); + return usb_claim_interface(ah->uh, interface); +} + +int ausb_release_interface(ausb_dev_handle *ah, int interface) +{ + DEBUGP("entering\n"); + /* what the hell? */ + if (ah == last_handle) + last_handle = NULL; + return usb_release_interface(ah->uh, interface); +} + +int ausb_set_configuration(ausb_dev_handle *ah, int configuration) +{ + DEBUGP("entering\n"); + return usb_set_configuration(ah->uh, configuration); +} + +int ausb_bulk_write(ausb_dev_handle *ah, int ep, char *bytes, int size, int timeout) +{ + DEBUGP("entering (ah=%p, ep=0x%x, bytes=%p, size=%d, timeout=%d\n", + ah, ep, bytes, size, timeout); + return __usb_bulk_write(ah->uh, ep, bytes, size, timeout); +} + +int ausb_bulk_read(ausb_dev_handle *ah, int ep, char *bytes, int size, int timeout) +{ + DEBUGP("entering (ah=%p, ep=0x%x, bytes=%p, size=%d, timeout=%d\n", + ah, ep, bytes, size, timeout); + return __usb_bulk_read(ah->uh, ep, bytes, size, timeout); +} + +int ausb_clear_halt(ausb_dev_handle *ah, unsigned int ep) +{ + DEBUGP("entering (ah=%p, ep=0x%x)\n", ah, ep); + return usb_clear_halt(ah->uh, ep); +} + +int ausb_reset(ausb_dev_handle *ah) +{ + DEBUGP("entering (ah=%p)\n", ah); + return usb_reset(ah->uh); +} + +int ausb_resetep(ausb_dev_handle *ah, int ep) +{ + DEBUGP("entering (ah=%pm ep=0x%x)\n", ah, ep); + return usb_resetep(ah->uh, ep); +} + +#ifdef LIBUSB_HAS_GET_DRIVER_NP +int ausb_get_driver_np(ausb_dev_handle *ah, int interface, char *name, + unsigned int namelen) +{ + DEBUGP("entering\n"); + return usb_get_driver_np(ah->uh, interface, name, namelen); +} +#endif + +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP +int ausb_detach_kernel_driver_np(ausb_dev_handle *ah, int interface) +{ + DEBUGP("entering\n"); + return usb_detach_kernel_driver_np(ah->uh, interface); +} +int ausb_reattach_kernel_driver_np(ausb_dev_handle *ah, int interface) +{ + DEBUGP("entering\n"); + return __usb_reattach_kernel_driver_np(ah->uh, interface); +} +#endif + +int ausb_close(struct ausb_dev_handle *ah) +{ + DEBUGP("entering\n"); + + if (ah == last_handle) + last_handle = NULL; + + return usb_close(ah->uh); +} + +void ausb_fini(void) +{ + DEBUGP("entering\n"); + sigaction(SIGAUSB, NULL, NULL); +} diff --git a/openpcd/opcd_test/ausb/ausb.h b/openpcd/opcd_test/ausb/ausb.h new file mode 100644 index 0000000..4d62cac --- /dev/null +++ b/openpcd/opcd_test/ausb/ausb.h @@ -0,0 +1,68 @@ +#ifndef _AUSB_H +#define _AUSB_H + +/* Wrapper/Extension code to libusb-0.1 to support asynchronous requests + * on Linux platforns + * + * (C) 2004 by Harald Welte + * + * Distributed under the terms of GNU LGPL, Version 2.1 + */ + + +#include +#include + +#define AUSB_USBDEVFS_URB_TYPES 4 + +/* structures */ +struct ausb_callback { + void (*handler)(struct usbdevfs_urb *uurb, void *userdata); + void *userdata; +}; + +struct ausb_dev_handle { + usb_dev_handle *uh; + struct ausb_callback cb[AUSB_USBDEVFS_URB_TYPES]; +}; + +typedef struct ausb_dev_handle ausb_dev_handle; + +/* intitialization */ +int ausb_init(void); +ausb_dev_handle *ausb_open(struct usb_device *dev); +int ausb_close(ausb_dev_handle *ah); +int ausb_register_callback(ausb_dev_handle *ah, unsigned char type, + void (*callback)(struct usbdevfs_urb *uurb, + void *userdata), + void *userdata); + +/* asynchronous URB related functions */ +void ausb_dump_urb(struct usbdevfs_urb *uurb); +void ausb_fill_int_urb(struct usbdevfs_urb *uurb, unsigned char endpoint, + void *buffer, int buffer_length); +int ausb_submit_urb(ausb_dev_handle *ah, struct usbdevfs_urb *uurb); +int ausb_discard_urb(ausb_dev_handle *ah, struct usbdevfs_urb *uurb); +struct usbdevfs_urb *ausb_get_urb(ausb_dev_handle *ah); + +/* synchronous functions, mostly wrappers for libusb */ +int ausb_claim_interface(ausb_dev_handle *ah, int interface); +int ausb_release_interface(ausb_dev_handle *ah, int interface); +int ausb_set_configuration(ausb_dev_handle *dev, int configuration); +int ausb_clear_halt(ausb_dev_handle *dev, unsigned int ep); +int ausb_reset(ausb_dev_handle *dev); +int ausb_resetep(ausb_dev_handle *dev, int ep); +int ausb_bulk_write(ausb_dev_handle *ah, int ep, char *bytes, int size, + int timeout); +int ausb_bulk_read(ausb_dev_handle *ah, int ep, char *bytes, int size, + int timeout); +#ifdef LIBUSB_HAS_GET_DRIVER_NP +int ausb_get_driver_np(ausb_dev_handle *ah, int interface, char *name, + unsigned int namelen); +#endif +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP +int ausb_detach_kernel_driver_np(ausb_dev_handle *dev, int interface); +int ausb_reattach_kernel_driver_np(ausb_dev_handle *dev, int interface); +#endif + +#endif /* _AUSB_H */ diff --git a/openpcd/opcd_test/ausb/ausb_test.c b/openpcd/opcd_test/ausb/ausb_test.c new file mode 100644 index 0000000..f7bfdee --- /dev/null +++ b/openpcd/opcd_test/ausb/ausb_test.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +#include "ausb.h" + +#define CJPPA_USB_VENDOR_ID 0x0c4b +#define CJPPA_USB_DEVICE_ID 0x0100 + +static struct usb_device *find_cj_usbdev(int num) +{ + struct usb_bus *busses, *bus; + struct usb_device *dev; + int found = 0; + + busses = usb_get_busses(); + + for (bus = busses; bus; bus = bus->next) { + for (dev = bus->devices; dev; dev = dev->next) { + if (dev->descriptor.idVendor == CJPPA_USB_VENDOR_ID && + dev->descriptor.idProduct == CJPPA_USB_DEVICE_ID) { + found++; + if (found == num) + return dev; + } + } + } + return NULL; +} + +static void int_cb(struct usbdevfs_urb *uurb) +{ + struct ausb_dev_handle *ah = uurb->usercontext; + + fprintf(stdout, __FUNCTION__ " called, "); + + ausb_dump_urb(uurb); + + if (ausb_submit_urb(ah, uurb)) + fprintf(stderr, "unable to resubmit urb\n"); +} + +int main(int argc, char **argv) +{ + struct usb_device *dev; + struct ausb_dev_handle *ah; + struct usbdevfs_urb *uurb; + char buffer[280]; + ausb_init(); + + uurb = malloc(sizeof(*uurb)); + + dev = find_cj_usbdev(1); + + if (!dev) { + fprintf(stderr, "unable to find matching usb device\n"); + exit(1); + } + + ah = ausb_open(dev); + if (!ah) { + fprintf(stderr, "error while opening usb device\n"); + exit(1); + } + + if (ausb_claim_interface(ah, 0)) { + fprintf(stderr, "unable to claim interface\n"); + ausb_close(ah); + exit(1); + } + + if (usb_set_configuration(ah->uh, 1)) { + fprintf(stderr, "unable to set configuration 1\n"); + ausb_close(ah); + exit(1); + } + +#if 1 + ausb_fill_int_urb(uurb, 0x81, buffer, sizeof(buffer)); + if (ausb_submit_urb(ah, uurb)) { + fprintf(stderr, "unable to submit urb\n"); + ausb_close(ah); + exit(1); + } + + while (1) { + sleep(10); + } +#endif + + ausb_close(ah); + + exit(0); +} diff --git a/openpcd/opcd_test/ausb/usb.c b/openpcd/opcd_test/ausb/usb.c new file mode 100644 index 0000000..1f1078d --- /dev/null +++ b/openpcd/opcd_test/ausb/usb.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include +#include + +#define MAX_READ_WRITE 4096 + +#define USB_ERROR_STR(ret, x, args...) return ret + +static int usb_get_fd(usb_dev_handle *uh) +{ + return *((int *)uh); +} + +int __usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int length, + int timeout) +{ + struct usbdevfs_bulktransfer bulk; + int ret, sent = 0; + + /* Ensure the endpoint address is correct */ + ep &= ~USB_ENDPOINT_IN; + + do { + bulk.ep = ep; + bulk.len = length - sent; + if (bulk.len > MAX_READ_WRITE) + bulk.len = MAX_READ_WRITE; + bulk.timeout = timeout; + bulk.data = (unsigned char *)bytes + sent; + + ret = ioctl(usb_get_fd(dev), USBDEVFS_BULK, &bulk); + if (ret < 0) + USB_ERROR_STR(ret, + "error writing to bulk endpoint %d: %s", + ep, strerror(errno)); + + sent += ret; + } while (ret > 0 && sent < length); + + return sent; +} + +int __usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + struct usbdevfs_bulktransfer bulk; + int ret, retrieved = 0, requested; + + /* Ensure the endpoint address is correct */ + ep |= USB_ENDPOINT_IN; + + do { + bulk.ep = ep; + requested = size - retrieved; + if (requested > MAX_READ_WRITE) + requested = MAX_READ_WRITE; + bulk.len = requested; + bulk.timeout = timeout; + bulk.data = (unsigned char *)bytes + retrieved; + + ret = ioctl(usb_get_fd(dev), USBDEVFS_BULK, &bulk); + if (ret < 0) + USB_ERROR_STR(ret, + "error reading from bulk endpoint 0x%x: %s", + ep, strerror(errno)); + + retrieved += ret; + } while (ret > 0 && retrieved < size && ret == requested); + + return retrieved; +} + +int __usb_reattach_kernel_driver_np(usb_dev_handle *dev, int interface) +{ + struct usbdevfs_ioctl command; + + command.ifno = interface; + command.ioctl_code = USBDEVFS_CONNECT; + command.data = NULL; + + return ioctl(usb_get_fd(dev), USBDEVFS_IOCTL, &command); +} diff --git a/openpcd/opcd_test/ausb/usb.h b/openpcd/opcd_test/ausb/usb.h new file mode 100644 index 0000000..66be0ee --- /dev/null +++ b/openpcd/opcd_test/ausb/usb.h @@ -0,0 +1,8 @@ +#ifndef _AUSB_USB_H +#define _AUSB_USB_H +int __usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int length, + int timeout); +int __usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int length, + int timeout); +int __usb_reattach_kernel_driver_np(usb_dev_handle *dev, int interface); +#endif diff --git a/openpcd/opcd_test/opcd_test.c b/openpcd/opcd_test/opcd_test.c index 6b99792..c9faa92 100644 --- a/openpcd/opcd_test/opcd_test.c +++ b/openpcd/opcd_test/opcd_test.c @@ -31,109 +31,8 @@ #include #include "openpcd.h" +#include "opcd_usb.h" -const char * -hexdump(const void *data, unsigned int len) -{ - static char string[65535]; - unsigned char *d = (unsigned char *) data; - unsigned int i, left, ofs; - - string[0] = '\0'; - ofs = snprintf(string, sizeof(string)-1, "(%u): ", len); - - left = sizeof(string) - ofs; - for (i = 0; len--; i += 3) { - if (i >= sizeof(string) -4) - break; - snprintf(string+ofs+i, 4, " %02x", *d++); - } - string[sizeof(string)-1] = '\0'; - return string; -} - -#define OPCD_VENDOR_ID 0x2342 -#define OPCD_PRODUCT_ID 0x0001 -#define OPCD_OUT_EP 0x01 -#define OPCD_IN_EP 0x82 - -static struct usb_dev_handle *hdl; -static struct usb_device *find_opcd_device(void) -{ - struct usb_bus *bus; - - for (bus = usb_busses; bus; bus = bus->next) { - struct usb_device *dev; - for (dev = bus->devices; dev; dev = dev->next) { - if (dev->descriptor.idVendor == OPCD_VENDOR_ID - && dev->descriptor.idProduct == OPCD_PRODUCT_ID - && dev->descriptor.iManufacturer == 0 - && dev->descriptor.iProduct == 0 - && dev->descriptor.bNumConfigurations == 1 - && dev->config->bNumInterfaces == 1 - && dev->config->iConfiguration == 0) - return dev; - } - } - return NULL; -} - -static int opcd_recv_reply(void) -{ - char buf[8192]; - int ret, i; - - memset(buf, 0, sizeof(buf)); - - ret = usb_bulk_read(hdl, OPCD_IN_EP, buf, sizeof(buf), 1000); - - if (ret < 0) { - fprintf(stderr, "bulk_read returns %d(%s)\n", ret, - usb_strerror()); - return ret; - } - - printf("RX: %s\n", hexdump(buf, ret)); - - return ret; -} - - -static int opcd_send_command(u_int8_t cmd, u_int8_t reg, u_int8_t val, u_int16_t len, - const unsigned char *data) -{ - unsigned char buf[8192]; - struct openpcd_hdr *ohdr = (struct openpcd_hdr *)buf; - int cur = 0; - int ret; - - memset(buf, 0, sizeof(buf)); - - ohdr->cmd = cmd; - ohdr->reg = reg; - ohdr->val = val; - ohdr->len = len; - if (data && len) - memcpy(ohdr->data, data, len); - - cur = sizeof(*ohdr) + len; - - printf("TX: %s\n", hexdump(buf, cur)); - - ret = usb_bulk_write(hdl, OPCD_OUT_EP, buf, cur, 0); - if (ret < 0) { - fprintf(stderr, "bulk_write returns %d(%s)\n", ret, - usb_strerror()); - return ret; - } - - /* this usleep is required in order to make the process work. - * apparently some race condition in the bootloader if we feed - * data too fast */ - usleep(5000); - - //return ezx_blob_recv_reply(); -} static int get_number(const char *optarg, unsigned int min, unsigned int max, unsigned int *num) { @@ -166,6 +65,7 @@ static void print_help(void) "\t-c\t--clear-bits\treg\tmask\n"); } + static struct option opts[] = { { "led-set", 1, 0, 'l' }, { "reg-write", 1, 0, 'w' }, @@ -179,33 +79,14 @@ static struct option opts[] = { int main(int argc, char **argv) { - struct usb_device *dev; + struct opcd_handle *od; int c; + static char buf[8192]; + int buf_len = sizeof(buf); print_welcome(); - usb_init(); - if (!usb_find_busses()) - exit(1); - if (!usb_find_devices()) - exit(1); - - dev = find_opcd_device(); - if (!dev) { - printf("Cannot find OpenPCD device. Are you sure it is connected?\n"); - exit(1); - } - - hdl = usb_open(dev); - if (!hdl) { - printf("Unable to open usb device: %s\n", usb_strerror()); - exit(1); - } - - if (usb_claim_interface(hdl, 0) < 0) { - printf("Unable to claim usb interface 1 of device: %s\n", usb_strerror()); - exit(1); - } + od = opcd_init(); while (1) { int option_index = 0; @@ -224,14 +105,14 @@ int main(int argc, char **argv) if (get_number(argv[optind], 0, 1, &j) < 0) exit(2); printf("setting LED %d to %s\n", i, j ? "on" : "off"); - opcd_send_command(OPENPCD_CMD_SET_LED, i, j, 0, NULL); + opcd_send_command(od, OPENPCD_CMD_SET_LED, i, j, 0, NULL); break; case 'r': if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) exit(2); printf("reading register 0x%02x: "); - opcd_send_command(OPENPCD_CMD_READ_REG, i, 0, 0, NULL); - opcd_recv_reply(); + opcd_send_command(od, OPENPCD_CMD_READ_REG, i, 0, 0, NULL); + opcd_recv_reply(od, buf, buf_len); break; case 'w': if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) { @@ -243,13 +124,13 @@ int main(int argc, char **argv) exit(2); } fprintf(stdout, "setting register 0x%02x to 0x%02x\n", i, j); - opcd_send_command(OPENPCD_CMD_WRITE_REG, i, j, 0, NULL); + opcd_send_command(od, OPENPCD_CMD_WRITE_REG, i, j, 0, NULL); break; case 'R': if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) exit(2); - opcd_send_command(OPENPCD_CMD_READ_FIFO, 0, i, 0, NULL); - opcd_recv_reply(); + opcd_send_command(od, OPENPCD_CMD_READ_FIFO, 0, i, 0, NULL); + opcd_recv_reply(od, buf, buf_len); break; case 'W': fprintf(stderr, "FIFO write not implemented yet\n"); @@ -259,14 +140,14 @@ int main(int argc, char **argv) exit(2); if (get_number(argv[optind], 0x00, 0xff, &j) < 0) exit(2); - opcd_send_command(OPENPCD_CMD_REG_BITS_SET, i, j, 0, NULL); + opcd_send_command(od, OPENPCD_CMD_REG_BITS_SET, i, j, 0, NULL); break; case 'c': if (get_number(optarg, 0x00, OPENPCD_REG_MAX, &i) < 0) exit(2); if (get_number(argv[optind], 0x00, 0xff, &j) < 0) exit(2); - opcd_send_command(OPENPCD_CMD_REG_BITS_CLEAR, i, j, 0, NULL); + opcd_send_command(od, OPENPCD_CMD_REG_BITS_CLEAR, i, j, 0, NULL); break; case 'h': case '?': diff --git a/openpcd/opcd_test/opcd_usb.c b/openpcd/opcd_test/opcd_usb.c new file mode 100644 index 0000000..70b40a0 --- /dev/null +++ b/openpcd/opcd_test/opcd_usb.c @@ -0,0 +1,185 @@ +#include +#include +#include +#include + +#include + +#include "ausb/ausb.h" +#include "openpcd.h" + +#include "opcd_usb.h" + +const char * +opcd_hexdump(const void *data, unsigned int len) +{ + static char string[65535]; + unsigned char *d = (unsigned char *) data; + unsigned int i, left, ofs; + + string[0] = '\0'; + ofs = snprintf(string, sizeof(string)-1, "(%u): ", len); + + left = sizeof(string) - ofs; + for (i = 0; len--; i += 3) { + if (i >= sizeof(string) -4) + break; + snprintf(string+ofs+i, 4, " %02x", *d++); + } + string[sizeof(string)-1] = '\0'; + return string; +} + +#define OPCD_VENDOR_ID 0x2342 +#define OPCD_PRODUCT_ID 0x0001 +#define OPCD_OUT_EP 0x01 +#define OPCD_IN_EP 0x82 +#define OPCD_INT_EP 0x83 + +static struct usb_device *find_opcd_handle(void) +{ + struct usb_bus *bus; + + for (bus = usb_busses; bus; bus = bus->next) { + struct usb_device *dev; + for (dev = bus->devices; dev; dev = dev->next) { + if (dev->descriptor.idVendor == OPCD_VENDOR_ID + && dev->descriptor.idProduct == OPCD_PRODUCT_ID + && dev->descriptor.iManufacturer == 0 + && dev->descriptor.iProduct == 0 + && dev->descriptor.bNumConfigurations == 1 + && dev->config->bNumInterfaces == 1 + && dev->config->iConfiguration == 0) + return dev; + } + } + return NULL; +} + +static void opcd_dump_hdr(struct openpcd_hdr *hdr) +{ + printf("IRQ: cmd=0x%02x, flags=0x%02x, reg=0x%02x, val=0x%02x " + "len=%d, res=%d\n", hdr->cmd, hdr->flags, hdr->reg, + hdr->val, hdr->len); +} + +static void handle_interrupt(struct usbdevfs_urb *uurb, void *userdata) +{ + struct opcd_handle *od = userdata; + ausb_dev_handle *ah; + struct openpcd_hdr *opcdh; + + if (!uurb) { + fprintf(stderr, "interrupt with no URB?!?\n"); + return; + } + + ah = uurb->usercontext; + + opcdh = (struct openpcd_hdr *)uurb->buffer; + opcd_dump_hdr(opcdh); + + if (ausb_submit_urb(ah, uurb)) + fprintf(stderr, "unable to resubmit interupt urb\n"); +} + +struct opcd_handle *opcd_init(void) +{ + struct opcd_handle *oh; + struct usb_device *dev; + + oh = malloc(sizeof(*oh)); + if (!oh) + return NULL; + + memset(oh, 0, sizeof(*oh)); + + ausb_init(); + + dev = find_opcd_handle(); + if (!dev) { + fprintf(stderr, "Cannot find OpenPCD device. " + "Are you sure it is connected?\n"); + exit(1); + } + + oh->hdl = ausb_open(dev); + if (!oh->hdl) { + fprintf(stderr, "Unable to open usb device: %s\n", + usb_strerror()); + exit(1); + } + + if (ausb_claim_interface(oh->hdl, 0) < 0) { + fprintf(stderr, "Unable to claim usb interface " + "1 of device: %s\n", usb_strerror()); + exit(1); + } + + ausb_fill_int_urb(&oh->int_urb, OPCD_INT_EP, oh->int_buf, + sizeof(oh->int_buf)); + if (ausb_register_callback(oh->hdl, USBDEVFS_URB_TYPE_INTERRUPT, + handle_interrupt, oh)) { + fprintf(stderr, "unable to submit interrupt urb"); + exit(1); + } + + return oh; +} + +void opcd_fini(struct opcd_handle *od) +{ + ausb_discard_urb(od->hdl, &od->int_urb); + ausb_close(od->hdl); +} + +int opcd_recv_reply(struct opcd_handle *od, char *buf, int len) +{ + int ret, i; + + memset(buf, 0, sizeof(buf)); + + ret = ausb_bulk_read(od->hdl, OPCD_IN_EP, buf, len, 1000); + + if (ret < 0) { + fprintf(stderr, "bulk_read returns %d(%s)\n", ret, + usb_strerror()); + return ret; + } + + printf("RX: %s\n", opcd_hexdump(buf, ret)); + opcd_dump_hdr((struct openpcd_hdr *)buf); + + return ret; +} + + +int opcd_send_command(struct opcd_handle *od, u_int8_t cmd, + u_int8_t reg, u_int8_t val, u_int16_t len, + const unsigned char *data) +{ + unsigned char buf[128]; + struct openpcd_hdr *ohdr = (struct openpcd_hdr *)buf; + int cur = 0; + int ret; + + memset(buf, 0, sizeof(buf)); + + ohdr->cmd = cmd; + ohdr->reg = reg; + ohdr->val = val; + ohdr->len = len; + if (data && len) + memcpy(ohdr->data, data, len); + + cur = sizeof(*ohdr) + len; + + printf("TX: %s\n", opcd_hexdump(buf, cur)); + + ret = ausb_bulk_write(od->hdl, OPCD_OUT_EP, buf, cur, 0); + if (ret < 0) { + fprintf(stderr, "bulk_write returns %d(%s)\n", ret, + usb_strerror()); + return ret; + } +} diff --git a/openpcd/opcd_test/opcd_usb.h b/openpcd/opcd_test/opcd_usb.h new file mode 100644 index 0000000..953f983 --- /dev/null +++ b/openpcd/opcd_test/opcd_usb.h @@ -0,0 +1,23 @@ +#ifndef _OPCD_USB_H +#define _OPCD_USB_H + +#include "ausb/ausb.h" + +#define OPCD_INTBUF_SIZE 64 +struct opcd_handle { + struct ausb_dev_handle *hdl; + struct usbdevfs_urb int_urb; + u_int8_t int_buf[OPCD_INTBUF_SIZE]; +}; + +extern const char *opcd_hexdump(const void *data, unsigned int len); + +extern struct opcd_handle *opcd_init(void); +extern void opcd_fini(struct opcd_handle *od); + +extern int opcd_recv_reply(struct opcd_handle *od, char *buf, int len); +extern int opcd_send_command(struct opcd_handle *od, u_int8_t cmd, + u_int8_t reg, u_int8_t val, u_int16_t len, + const unsigned char *data); + +#endif -- cgit v1.2.3