[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 */