diff options
author | laforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2006-09-12 17:37:00 +0000 |
---|---|---|
committer | laforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2006-09-12 17:37:00 +0000 |
commit | 8bd3d51b23e328e91c209dbebe8cfe002b0b0042 (patch) | |
tree | 5145facfb2f864519fd9e4914929f5da6d8be1fa /host/ausb | |
parent | 5fdccde69e5288b147c7c3ed81c412c18c5d5d54 (diff) |
move to new directory
git-svn-id: https://svn.openpcd.org:2342/trunk@193 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'host/ausb')
-rw-r--r-- | host/ausb/Makefile | 21 | ||||
-rw-r--r-- | host/ausb/ausb.c | 331 | ||||
-rw-r--r-- | host/ausb/ausb.h | 68 | ||||
-rw-r--r-- | host/ausb/ausb_test.c | 95 | ||||
-rw-r--r-- | host/ausb/usb.c | 86 | ||||
-rw-r--r-- | host/ausb/usb.h | 8 |
6 files changed, 609 insertions, 0 deletions
diff --git a/host/ausb/Makefile b/host/ausb/Makefile new file mode 100644 index 0000000..6269739 --- /dev/null +++ b/host/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/host/ausb/ausb.c b/host/ausb/ausb.c new file mode 100644 index 0000000..8b0117f --- /dev/null +++ b/host/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 <laforge@gnumonks.org> + * + * Distributed and licensed under the terms of GNU LGPL, Version 2.1 + */ + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <signal.h> +#include <errno.h> +#include <sys/utsname.h> +#include <sys/ioctl.h> + +#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/host/ausb/ausb.h b/host/ausb/ausb.h new file mode 100644 index 0000000..4d62cac --- /dev/null +++ b/host/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 <laforge@gnumonks.org> + * + * Distributed under the terms of GNU LGPL, Version 2.1 + */ + + +#include <usb.h> +#include <linux/usbdevice_fs.h> + +#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/host/ausb/ausb_test.c b/host/ausb/ausb_test.c new file mode 100644 index 0000000..f7bfdee --- /dev/null +++ b/host/ausb/ausb_test.c @@ -0,0 +1,95 @@ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> + +#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/host/ausb/usb.c b/host/ausb/usb.c new file mode 100644 index 0000000..1f1078d --- /dev/null +++ b/host/ausb/usb.c @@ -0,0 +1,86 @@ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <usb.h> +#include <sys/ioctl.h> +#include <linux/usbdevice_fs.h> + +#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/host/ausb/usb.h b/host/ausb/usb.h new file mode 100644 index 0000000..66be0ee --- /dev/null +++ b/host/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 |