summaryrefslogtreecommitdiff
path: root/host/ausb
diff options
context:
space:
mode:
Diffstat (limited to 'host/ausb')
-rw-r--r--host/ausb/Makefile21
-rw-r--r--host/ausb/ausb.c331
-rw-r--r--host/ausb/ausb.h68
-rw-r--r--host/ausb/ausb_test.c95
-rw-r--r--host/ausb/usb.c86
-rw-r--r--host/ausb/usb.h8
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
personal git repositories of Harald Welte. Your mileage may vary