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/ausb.c | |
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/ausb.c')
-rw-r--r-- | host/ausb/ausb.c | 331 |
1 files changed, 331 insertions, 0 deletions
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); +} |