[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[coldsync-hackers] [patch] Linux/BSD USB support via libusb
I just picked up a Visor this week and wanted to get the USB interface
working. Coldsync had USB support, but it was specific to BSD systems,
so I ported coldsync to use libusb.
I've done a couple of full syncs with this code, but it hasn't received
extensive testing. It works for me :)
It requires the CVS version of libusb.
JE
diff -ur coldsync-2.2.0.orig/configure.in coldsync-2.2.0/configure.in
--- coldsync-2.2.0.orig/configure.in Sun Aug 5 17:28:32 2001
+++ coldsync-2.2.0/configure.in Wed Aug 29 18:43:03 2001
@@ -471,32 +471,20 @@
AC_MSG_RESULT(no))
-# Optional USB support
-# (Only works under FreeBSD 4.x, for now)
+dnl Optional USB support
-# The --with(out)-usb option only indicates the user's desire. Even if
-# it's turned on, 'configure' still checks to see whether it's
-# possible to use the USB code. IOW, "--without-i18n" allows the user
-# to turn off USB under *BSD, but that's it.
-AC_ARG_WITH(usb,dnl
-[ --without-usb Disable USB support for Visor (FreeBSD 4.x only).],
- [WITH_USB="$withval"],[WITH_USB="yes"])
+dnl Compile in usb support
+AC_PATH_PROG(LIBUSB_CONFIG,libusb-config)
+if test -n "${LIBUSB_CONFIG}"; then
+ LDFLAGS="$LDFLAGS `libusb-config --libs`"
+ CFLAGS="$CFLAGS `libusb-config --cflags`"
+ AC_DEFINE_UNQUOTED(WITH_USB)
+else
+ AC_MSG_WARN([
-if test x"$WITH_USB" != xno; then
- AC_MSG_CHECKING([for BSD USB support])
-
- # This code snippet checks several things:
- # 1) <dev/usb/usb.h> exists
- # 2) It contains 'struct usb_device_info'
- # 3) That struct contains a 'vendorNo' field.
- # All three conditions must be true for USB support to be enabled
- AC_TRY_COMPILE(dnl
- [#include <dev/usb/usb.h>],dnl
- [struct usb_device_info udi;
- udi.vendorNo = 0x082d;],dnl
- [AC_DEFINE_UNQUOTED(WITH_USB)
- AC_MSG_RESULT(yes)],dnl
- [AC_MSG_RESULT(no)])
+*** You need the libusb library for USB support
+*** http://download.sourceforge.net/libusb/libusb-0.1.3b.tar.gz
+])
fi
# Don't build the Perl stuff
diff -ur coldsync-2.2.0.orig/libpconn/PConnection.c coldsync-2.2.0/libpconn/PConnection.c
--- coldsync-2.2.0.orig/libpconn/PConnection.c Tue Aug 14 21:17:39 2001
+++ coldsync-2.2.0/libpconn/PConnection.c Thu Aug 30 19:41:39 2001
@@ -108,6 +108,7 @@
#if WITH_USB
/* XXX - Should be able to specify "-" for the filename to
* listen on stdin/stdout.
+ * USB over stdin/stdout? I don't think that's a good idea :)
*/
if (pconn_usb_open(pconn, device, protocol, promptHotSync) < 0)
{
diff -ur coldsync-2.2.0.orig/libpconn/PConnection_usb.c coldsync-2.2.0/libpconn/PConnection_usb.c
--- coldsync-2.2.0.orig/libpconn/PConnection_usb.c Mon Jul 30 00:23:56 2001
+++ coldsync-2.2.0/libpconn/PConnection_usb.c Fri Aug 31 18:05:59 2001
@@ -35,7 +35,7 @@
# endif /* HAVE_MEMCPY */
#endif /* STDC_HEADERS */
-#include <dev/usb/usb.h>
+#include <usb.h>
#if HAVE_LIBINTL_H
# include <libintl.h> /* For i18n */
@@ -47,6 +47,8 @@
#include "pconn/netsync.h"
struct usb_data {
+ usb_dev_handle *dev;
+ int hotsync_ep;
unsigned char iobuf[1024]; /* XXX - Is there anything
* magical about 1024? Make
* this a cpp symbol */
@@ -77,12 +79,11 @@
*/
#define usbRequestVendorGetConnectionInfo 0x03
-/* note: uWord and uByte are defined in <dev/usb/usb.h> */
typedef struct {
- uWord numPorts;
+ unsigned short numPorts;
struct {
- uByte portFunctionID;
- uByte port;
+ unsigned char portFunctionID;
+ unsigned char port;
} connections[20];
} UsbConnectionInfoType, * UsbConnectionInfoPtr;
@@ -176,9 +177,14 @@
}
u->iobufp = u->iobuf;
- u->iobuflen = read(p->fd, u->iobufp, sizeof(u->iobuf));
+ IO_TRACE(2)
+ fprintf(stderr, "calling usb_bulk_read(%02x)\n", u->hotsync_ep | 0x80);
+ u->iobuflen = usb_bulk_read(u->dev, u->hotsync_ep | 0x80,
+ (char *)u->iobufp, sizeof(u->iobuf), 5000);
+ IO_TRACE(2)
+ fprintf(stderr, "usb read %d, ret %d\n", sizeof(u->iobuf), u->iobuflen);
if (u->iobuflen < 0) {
- perror("usb read");
+ fprintf(stderr, "usb read: %s\n", usb_strerror());
return u->iobuflen;
}
}
@@ -190,7 +196,15 @@
static int
usb_write(PConnection *p, unsigned const char *buf, const int len)
{
- return write(p->fd, buf, len);
+ struct usb_data *u = p->io_private;
+ int ret;
+
+ ret = usb_bulk_write(u->dev, u->hotsync_ep, (char *)buf, len, 5000);
+ IO_TRACE(2)
+ fprintf(stderr, "usb write %d, ret %d\n", len, ret);
+ if (ret < 0)
+ fprintf(stderr, "usb write: %s\n", usb_strerror());
+ return ret;
}
static int
@@ -208,6 +222,7 @@
* cmp_accept().
*/
+printf("usb_accept: %d\n", pconn->protocol);
switch (pconn->protocol)
{
case PCONN_STACK_FULL:
@@ -231,11 +246,12 @@
return -1;
}
+printf("usb_accept done\n");
return 0;
}
static int
-usb_close(PConnection *p)
+pconn_usb_close(PConnection *p)
{
struct usb_data *u = p->io_private;
@@ -267,36 +283,19 @@
break;
}
+ if (u->dev)
+ usb_close(u->dev);
+
if (u != NULL)
free((void *)u);
- return (p->fd >= 0 ? close(p->fd) : 0);
+
+ return 0;
}
static int
usb_select(PConnection *p, pconn_direction which, struct timeval *tvp)
{
- fd_set fds;
- struct usb_data *u = p->io_private;
-
- FD_ZERO(&fds);
- FD_SET(p->fd, &fds);
-
- /*
- * If there's buffered read data, then return true.
- */
- if ((which == forReading) && (u->iobuflen > 0)) {
- return 1;
- }
-
- /*
- * So this code looks really good, but in actuallity, the
- * ugen(4) kernel driver will always return ready.
- *
- * Really fixing this would require something horrible, like
- * interrupting a read with an alarm signal.
- */
- return (which == forReading) ? select(p->fd+1, &fds, NULL, NULL, tvp)
- : select(p->fd+1, NULL, &fds, NULL, tvp);
+ return 1;
}
static int
@@ -315,13 +314,13 @@
const Bool prompt)
{
struct usb_data *u;
- struct usb_device_info udi;
- struct usb_ctl_request ur;
- char *hotsync_ep_name;
- int usb_ep0 = -1, hotsync_endpoint = -1;
- int i;
+ int i, ret;
unsigned char usbresponse[50];
UsbConnectionInfoType ci;
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ usb_init();
if (protocol == PCONN_STACK_DEFAULT)
pconn->protocol = PCONN_STACK_FULL;
@@ -335,23 +334,20 @@
{
case PCONN_STACK_FULL:
/* Initialize the SLP part of the PConnection */
- if (slp_init(pconn) < 0)
- {
+ if (slp_init(pconn) < 0) {
free(pconn);
return -1;
}
/* Initialize the PADP part of the PConnection */
- if (padp_init(pconn) < 0)
- {
+ if (padp_init(pconn) < 0) {
padp_tini(pconn);
slp_tini(pconn);
return -1;
}
/* Initialize the DLP part of the PConnection */
- if (dlp_init(pconn) < 0)
- {
+ if (dlp_init(pconn) < 0) {
dlp_tini(pconn);
padp_tini(pconn);
slp_tini(pconn);
@@ -362,15 +358,13 @@
case PCONN_STACK_SIMPLE: /* Fall through */
case PCONN_STACK_NET:
/* Initialize the DLP part of the PConnection */
- if (dlp_init(pconn) < 0)
- {
+ if (dlp_init(pconn) < 0) {
dlp_tini(pconn);
return -1;
}
/* Initialize the NetSync part of the PConnnection */
- if (netsync_init(pconn) < 0)
- {
+ if (netsync_init(pconn) < 0) {
dlp_tini(pconn);
netsync_tini(pconn);
return -1;
@@ -388,11 +382,13 @@
pconn->io_write = &usb_write;
pconn->io_connect = &usb_connect;
pconn->io_accept = &usb_accept;
- pconn->io_close = &usb_close;
+ pconn->io_close = &pconn_usb_close;
pconn->io_select = &usb_select;
pconn->io_drain = &usb_drain;
u = pconn->io_private = malloc(sizeof(struct usb_data));
+ if (!u)
+ return -1;
bzero((void *) pconn->io_private, sizeof(struct usb_data));
@@ -407,41 +403,33 @@
printf(_("Please press the HotSync button.\n"));
/*
- * We've got to loop trying to open the USB device since
- * you'll get an ENXIO until the device has been inserted
- * on the USB bus.
+ * Loop waiting for a device we know about to appear
*/
/* XXX - Perhaps add a "transient" flag to listen blocks. This
- * indicates that it's okay for the device (both /dev/ugen0 and the
- * endpoint, /dev/ugen0.2) not to exist, so keep trying.
+ * indicates that it's okay for the device not to exist, so keep
+ * trying.
*/
+ dev = NULL;
for (i = 0; i < 30; i++) {
- if ((usb_ep0 = open(device, O_RDWR | O_BINARY)) >= 0)
- /* The O_BINARY flag is rather bogus, since
- * the only relevant platform that uses it
- * is Windows, and this USB code only works
- * under FreeBSD. But hey, it doesn't cost
- * anything, and it makes things
- * consistent.
- */
- break;
+ usb_find_busses();
+ usb_find_devices();
- IO_TRACE(1)
- perror(device);
+ for (bus = usb_busses; bus; bus = bus->next) {
+ for (dev = bus->devices; dev; dev = dev->next) {
+ if (dev->descriptor.idVendor == 0x082d &&
+ dev->descriptor.idProduct == 0x0100)
+ break;
+ }
+ }
- if (errno != ENXIO) {
- fprintf(stderr, _("Error: Can't open \"%s\".\n"),
- device);
- perror("open");
- /* If some other error, don't bother waiting
- * for the timeout to expire.
- */
+ if (dev)
break;
- }
+
sleep(1);
}
+#if 0
/*
* If we've enabled trace for I/O, then poke the USB kernel
* driver to turn on the minimal amount of tracing. This can
@@ -453,7 +441,7 @@
else
i = 0;
(void) ioctl(usb_ep0, USB_SETDEBUG, &i);
-
+#endif
/*
* Open the control endpoint of the USB device. We'll use this
@@ -461,26 +449,13 @@
* interested in and understand, and then to configure it in
* preparation of doing I/O for the actual hot sync operation.
*/
- if (usb_ep0 < 0) {
+ if (!dev || !(u->dev = usb_open(dev))) {
fprintf(stderr, _("%s: Can't open USB device.\n"),
"pconn_usb_open");
- perror("open");
- free(u);
- u = pconn->io_private = NULL;
-
- dlp_tini(pconn);
- padp_tini(pconn);
- slp_tini(pconn);
- return -1;
- }
+ if (dev)
+ perror("open");
- if (ioctl(usb_ep0, USB_GET_DEVICEINFO, &udi)) {
- fprintf(stderr,
- _("%s: Can't get information about USB device.\n"),
- "pconn_usb_open");
- perror("ioctl(USB_GET_DEVICEINFO)");
- (void) close(usb_ep0);
- free((void *)u);
+ free(u);
u = pconn->io_private = NULL;
dlp_tini(pconn);
@@ -489,28 +464,17 @@
return -1;
}
-#define SURE(x) \
- (((x!=NULL) && (*x !='\0')) ? x : "<not defined>")
-
/*
* Happily, all of the multibyte values in the struct usb_device_info
* are in host byte order, and don't need to be converted.
*/
IO_TRACE(1) {
fprintf(stderr,
- "Device information: %s vendor %04x (%s) product %04x (%s) rev %s addr %x\n",
- device, udi.vendorNo, SURE(udi.vendor),
- udi.productNo, SURE(udi.product),
- SURE(udi.release), udi.addr);
+ "Device information: vendor %04x product %04x\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
}
- if (udi.vendorNo != HANDSPRING_VENDOR_ID) {
- fprintf(stderr,
- _("%s: Warning: Unexpected USB vendor ID %#x.\n"),
- "pconn_usb_open", udi.vendorNo);
- }
-
/*
* Eventually, it might be necessary to split out the following
* code should another Palm device with a USB peripheral interface
@@ -519,16 +483,16 @@
* inventing Yet Another exquisitely round wheel of their own.
*/
-
/*
* Ensure that the device is set to the default configuration.
* For Visors seen so far, the default is the only one they
* support.
*/
- i = 1;
- if (ioctl(usb_ep0, USB_SET_CONFIG, &i) < 0) {
- perror("warning: ioctl(USB_SET_CONFIG) failed");
- }
+ if (usb_set_configuration(u->dev, 1) < 0)
+ perror("warning: usb_set_configuration failed");
+
+ if (usb_claim_interface(u->dev, 0) < 0)
+ perror("warning: usb_claim_interface failed");
/*
* Now, ask the device (which we believe to be a Handspring Visor)
@@ -539,19 +503,10 @@
* change based on what other applications are running and perhaps
* on future hardware platforms.
*/
- bzero((void *) &ur, sizeof(ur));
- ur.request.bmRequestType = UT_READ_VENDOR_ENDPOINT;
- ur.request.bRequest = usbRequestVendorGetConnectionInfo;
- USETW(ur.request.wValue, 0);
- USETW(ur.request.wIndex, 0);
- USETW(ur.request.wLength, 18);
- ur.data = (void *) &ci;
- ur.flags = USBD_SHORT_XFER_OK;
- ur.actlen = 0;
bzero((void *)&ci, sizeof(ci));
- if (ioctl(usb_ep0, USB_DO_REQUEST, &ur) < 0) {
- perror(_("ioctl(USB_DO_REQUEST) usbRequestVendorGetConnectionInfo failed"));
- (void) close(usb_ep0);
+ if (usb_control_msg(u->dev, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | 0x80, usbRequestVendorGetConnectionInfo, 0, 0, (char *)&ci, 18, 5000) < 0) {
+ perror(_("usb_control_msg(usbRequestVendorGetConnectionInfo) failed"));
+ usb_close(u->dev);
free((void *)u);
u = pconn->io_private = NULL;
@@ -561,7 +516,6 @@
return -1;
}
-
/*
* Now search the list of functions supported over the USB interface
* for the endpoint associated with the HotSync function. So far,
@@ -574,7 +528,8 @@
* little endian, but we should use the accessor macros to ensure
* the code continues to run on big endian CPUs too.
*/
- for (i = 0; i < UGETW(ci.numPorts); i++) {
+ /* FIXME: endian for ci.numPorts */
+ for (i = 0; i < ci.numPorts; i++) {
IO_TRACE(2)
fprintf(stderr,
"ConnectionInfo: entry %d function %s on port %d\n",
@@ -585,14 +540,14 @@
ci.connections[i].port);
if (ci.connections[i].portFunctionID == hs_usbfun_Hotsync)
- hotsync_endpoint = ci.connections[i].port;
+ u->hotsync_ep = ci.connections[i].port;
}
- if (hotsync_endpoint < 0) {
+ if (u->hotsync_ep < 0) {
fprintf(stderr,
_("%s: Could not find HotSync endpoint on Visor.\n"),
"PConnection_usb");
- (void) close(usb_ep0);
+ usb_close(u->dev);
free((void *)u);
u = pconn->io_private = NULL;
@@ -602,39 +557,26 @@
return -1;
}
- bzero((void *) &ur, sizeof(ur));
- ur.request.bmRequestType = UT_READ_VENDOR_ENDPOINT;
- ur.request.bRequest = usbRequestVendorGetBytesAvailable;
- USETW(ur.request.wValue, 0);
- USETW(ur.request.wIndex, 5);
- USETW(ur.request.wLength, 2);
- ur.data = &usbresponse[0];
- ur.flags = USBD_SHORT_XFER_OK;
- ur.actlen = 0;
-
- if (ioctl(usb_ep0, USB_DO_REQUEST, &ur) < 0) {
- perror(_("ioctl(USB_DO_REQUEST) usbRequestVendorGetBytesAvailable failed"));
- }
+ ret = usb_control_msg(u->dev, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | 0x80, usbRequestVendorGetBytesAvailable, 0, 5, (char *)usbresponse, 2, 5000);
+ if (ret < 0)
+ perror(_("usb_control_msg(usbRequestVendorGetBytesAvailable) failed"));
IO_TRACE(2) {
- fprintf(stderr, "first setup 0x1 returns %d bytes: ",
- ur.actlen);
- for (i = 0; i < ur.actlen; i++) {
- fprintf(stderr, " 0x%02x", usbresponse[i]);
+ if (ret > 0) {
+ for (i = 0; i < ret; i++)
+ fprintf(stderr, " 0x%02x", usbresponse[i]);
+
+ fprintf(stderr, "\n");
}
- fprintf(stderr, "\n");
}
- if (UGETW(usbresponse) != 1) {
+ if ((usbresponse[0] | (usbresponse[1] << 8)) != 1) {
fprintf(stderr,
_("%s: unexpected response %d to "
"GetBytesAvailable.\n"),
- "PConnection_usb", UGETW(usbresponse));
+ "PConnection_usb", usbresponse[0] | (usbresponse[1] << 8));
}
-
- (void) close(usb_ep0);
-
/* ------------------------------------------------------------------
*
* Ok, all of the device specific control messages have been
@@ -647,58 +589,8 @@
*
* ---------------------------------------------------------------- */
-
- /*
- * Construct the name of the device corresponding to the
- * USB endpoint associated with the hot sync service.
- */
- if ((hotsync_ep_name = malloc(strlen(device)+20)) == NULL) {
- free((void *)u);
- u = pconn->io_private = NULL;
-
- dlp_tini(pconn);
- padp_tini(pconn);
- slp_tini(pconn);
- return -1;
- }
-
- sprintf(hotsync_ep_name, "%s.%d", device, hotsync_endpoint);
-
- IO_TRACE(1)
- fprintf(stderr, "Hotsync endpoint name: \"%s\"\n",
- SURE(hotsync_ep_name));
-
- /* XXX - Under FreeBSD 5.x, this might not exist yet */
- pconn->fd = open(hotsync_ep_name, O_RDWR, 0);
-
- if (pconn->fd < 0) {
- fprintf(stderr, _("%s: Can't open \"%s\".\n"),
- "pconn_usb_open", hotsync_ep_name);
- perror("open");
- (void) close(usb_ep0);
- free(hotsync_ep_name);
- free((void *)u);
- u = pconn->io_private = NULL;
-
- dlp_tini(pconn);
- padp_tini(pconn);
- slp_tini(pconn);
- return -1;
- }
-
- if ((i = fcntl(pconn->fd, F_GETFL, 0))!=-1) {
- i &= ~O_NONBLOCK;
- fcntl(pconn->fd, F_SETFL, i);
- }
-
- i = 1;
- if (ioctl(pconn->fd, USB_SET_SHORT_XFER, &i) < 0)
- perror("ioctl(USB_SET_SHORT_XFER)");
-
- free(hotsync_ep_name);
-
/* Make it so */
- return pconn->fd;
+ return 1;
}
#endif /* WITH_USB */