[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[coldsync-hackers] Patch: Palm m50x USB support (Linux)



Hi all,

included is a patch against coldsync-2.1.3, which makes coldsync
work for the Palm m505 (and probably also Palm m500) USB Cradle
under linux (kernel 2.4.6).

The Palm m50x USB cradle works quite differently from the Visor
USB cradle: there is no SLP / PADP protocol running on the
serial pipe, instead the NetSync protocol is used. Or at least,
this is how the Windows software configures the USB cradle (we
are never sure of what the USB cradle can do until we get a
Palm spec).

The following steps are necessary to use the patch to get your
palm m50x USB cradle to work:
 - Get kernel version 2.4.6 or later, and select USB support
   for the Palm (which is in module visor.o). See the visor
   USB Howto for details.

 - insmod your usb-uhci or equivalent

 - modprobe visor.o.

 - Apply this patch to a fresh coldsync-2.1.3 tree:
   cd coldsync-2.1.3
   patch -p1 < /location/of/patch-m50x

 - Build coldsync

 - Press hotsync button
   and run 'coldsync -t usb_m50x -p /dev/ttyUSB1'
   (in any order)
   
   ttyUSB1 is the second serial USB tty created when
   your Palm starts to talk. It could be a different number
   if you have already serial USB devices.

Known bugs:
Sometimes coldsync hangs. This seems related to the problems
that have been reported for the USB Visor support. It looks
like data from the Palm to coldsync gets lost somewhere
on the way. There is maybe something wrong with the USB
serial/visor driver?

koen.
diff -ruN orig/coldsync-2.1.3/ChangeLog coldsync-2.1.3/ChangeLog
--- orig/coldsync-2.1.3/ChangeLog	Sat Jun 30 09:47:04 2001
+++ coldsync-2.1.3/ChangeLog	Sun Jul 15 22:48:05 2001
@@ -1,3 +1,10 @@
+2001-07-15  Koen Deforche <kdf@irule.be>
+
+        * PConnection.h, netsync.h, libpconn/Makefile, PConnection.c,
+	  PConnection_net.c, PConnection_usbm50x.c, netsync.c, config.c:
+
+	  Support for Palm m50x USB cradle (Linux).
+
 2001-06-30  Andrew Arensburger  <arensb@baa.ooblick.com>
 
 	- Version 2.1.3 released.
diff -ruN orig/coldsync-2.1.3/doc/coldsync.8 coldsync-2.1.3/doc/coldsync.8
--- orig/coldsync-2.1.3/doc/coldsync.8	Sun May  6 08:00:15 2001
+++ coldsync-2.1.3/doc/coldsync.8	Sun Jul 15 22:43:42 2001
@@ -177,6 +177,7 @@
 option. Legal values are
 .Dv serial ,
 .Dv usb ,
+.Dv usb_m50x
 and
 .Dv net .
 .It Fl s
@@ -412,6 +413,10 @@
 .Li listen usb
 is used to sync a Handspring Visor using native USB mode. This only
 works under *BSD.
+.Pp
+.Li listen usb_m50x
+is used to sync a Palm m50x from its USB cradle. This only works under Linux
+using the visor.o kernel module.
 .Pp
 The
 .Li device
diff -ruN orig/coldsync-2.1.3/include/pconn/PConnection.h coldsync-2.1.3/include/pconn/PConnection.h
--- orig/coldsync-2.1.3/include/pconn/PConnection.h	Sun Apr 15 06:32:50 2001
+++ coldsync-2.1.3/include/pconn/PConnection.h	Sun Jul 15 13:33:12 2001
@@ -39,6 +39,7 @@
 #define LISTEN_NET	2	/* Listen on TCP/UDP port (not
 				 * implemented yet). */
 #define LISTEN_USB	3	/* USB for Handspring Visor */
+#define LISTEN_USB_M50x  4	/* USB for Palm m50x */
 
 /* PConnection
  * This struct is an opaque type that contains all of the state about
diff -ruN orig/coldsync-2.1.3/include/pconn/netsync.h coldsync-2.1.3/include/pconn/netsync.h
--- orig/coldsync-2.1.3/include/pconn/netsync.h	Sun Dec 24 22:24:26 2000
+++ coldsync-2.1.3/include/pconn/netsync.h	Sun Jul 15 14:25:44 2001
@@ -8,34 +8,10 @@
  *
  * NetSync outline:
  *
- * The machine with the cradle is the client. It talks to the server host,
- * which will do the actual work of syncing.
+ * This packet encapsulation protocol is used for both 'NetSync' and
+ * talking to the Palm m50x in its USB Palm cradle.
  *
- * The client starts out by sending one or more wakeup packets to the
- * server, on UDP port 14237. These packets are of the form
- *	+------+------+------+------+
- *	|    magic    | type |   ?  |
- *	+------+------+------+------+
- *	| hostid                    |
- *	+------+------+------+------+
- *	| netmask                   |
- *	+------+------+------+------+
- *	| NUL-terminated hostname...
- *	+------+------+------+------+
- *
- * Where <magic> is the constant 0xfade, <type> appears to be the type of
- * request (1 == wakeup packet, 2 == ACK). <hostid> and <netmask> are the
- * IPv4 address and netmask of the host to sync with. <hostname> is the
- * name of the host. HotSync appears to use the address as authoritative,
- * and presumably sends the name along mainly for the server's benefit.
- *
- * The server then sends back a UDP datagram with the same information,
- * except that <type> is set to 2. The client will send up to 3 wakeup
- * requests before giving up.
- *
- * Once the server has acknowledged the wakeup packet (thereby accepting
- * the connection), it listens on TCP port 14238. At this point, data goes
- * back and forth in the following format:
+ * Data goes back and forth in the following format:
  *
  *	+------+------+
  *	| cmd  | xid  |
@@ -60,6 +36,7 @@
  *
  * $Id: netsync.h,v 1.2 2000/12/24 21:24:26 arensb Exp $
  */
+
 #ifndef _netsync_h_
 #define _netsync_h_
 
@@ -67,13 +44,30 @@
 #include "pconn.h"
 #include "pconn/palm_types.h"
 
-#define NETSYNC_WAKEUP_MAGIC	0xfade
-#define NETSYNC_WAKEUP_PORT	14237	/* UDP port on which the client
-					 * sends out the wakeup request.
-					 */
-#define NETSYNC_DATA_PORT	14238	/* TCP port on which the client and
-					 * server exchange sync data.
-					 */
+/*
+ * Ritual statements
+ * These packets are sent back and forth during the initial handshaking
+ * phase. I don't know what they mean. The sequence is:
+ * client sends UDP wakeup packet
+ * server sends UDP wakeup ACK
+ * client sends ritual response 1
+ * server sends ritual statement 2
+ * client sends ritual response 2
+ * server sends ritual statement 3
+ * client sends ritual response 3
+ *
+ * The comments are mostly conjecture and speculation.
+ */
+extern ubyte ritual_resp1[];
+#define ritual_resp1_size 22
+extern ubyte ritual_stmt2[];
+#define ritual_stmt2_size 50
+extern ubyte ritual_resp2[];
+#define ritual_resp2_size 50
+extern ubyte ritual_stmt3[];
+#define ritual_stmt3_size 46
+extern ubyte ritual_resp3[];
+#define ritual_resp3_size 8
 
 /* struct netsync_wakeup
  * At the beginning of the NetSync process, the client sends one or more
@@ -111,6 +105,10 @@
 extern int netsync_read(PConnection *pconn,
 			const ubyte **buf,
 			uword *len);
+extern int netsync_read_method(PConnection *pconn,
+			       const ubyte **buf,
+			       uword *len,
+			       int no_header);
 extern int netsync_write(PConnection *pconn,
 			 const ubyte *buf,
 			 const uword len);
diff -ruN orig/coldsync-2.1.3/include/pconn/pconn.h coldsync-2.1.3/include/pconn/pconn.h
--- orig/coldsync-2.1.3/include/pconn/pconn.h	Tue Jan  9 17:36:10 2001
+++ coldsync-2.1.3/include/pconn/pconn.h	Sun Jul 15 22:54:39 2001
@@ -18,6 +18,14 @@
 				 * ever is.
 				 */
 
+#define NETSYNC_WAKEUP_MAGIC    0xfade
+#define NETSYNC_WAKEUP_PORT     14237   /* UDP port on which the client
+                                         * sends out the wakeup request.
+                                         */
+#define NETSYNC_DATA_PORT       14238   /* TCP port on which the client and
+                                         * server exchange sync data.
+                                         */
+
 /* Debugging variables */
 extern int slp_trace;		/* Debugging level for Serial Link Protocol */
 extern int cmp_trace;		/* Debugging level for Connection
diff -ruN orig/coldsync-2.1.3/libpconn/Makefile coldsync-2.1.3/libpconn/Makefile
--- orig/coldsync-2.1.3/libpconn/Makefile	Sun Dec 10 22:27:12 2000
+++ coldsync-2.1.3/libpconn/Makefile	Sun Jul 15 13:33:50 2001
@@ -18,7 +18,8 @@
 		PConnection.c \
 		PConnection_serial.c \
 		PConnection_usb.c \
-		PConnection_net.c
+		PConnection_net.c \
+		PConnection_usbm50x.c
 
 LIBOBJS =	cfmakeraw.o \
 		dlp_cmd.o \
@@ -33,7 +34,8 @@
 		PConnection.o \
 		PConnection_serial.o \
 		PConnection_usb.o \
-		PConnection_net.o
+		PConnection_net.o \
+		PConnection_usbm50x.o
 
 CLEAN =		${LIBOBJS} ${LIBRARY} \
 		*.ln *.bak *~ core *.core .depend
diff -ruN orig/coldsync-2.1.3/libpconn/PConnection.c coldsync-2.1.3/libpconn/PConnection.c
--- orig/coldsync-2.1.3/libpconn/PConnection.c	Tue Feb 20 13:36:38 2001
+++ coldsync-2.1.3/libpconn/PConnection.c	Sun Jul 15 11:43:20 2001
@@ -27,6 +27,10 @@
 extern int pconn_net_open(PConnection *pconn,
 			  char *fname,
 			  int prompt_for_hotsync);
+extern int pconn_usbm50x_open(PConnection *pconn,
+			      char *fname,
+			      int prompt_for_hotsync);
+
 #if WITH_USB
 extern int pconn_usb_open(PConnection *pconn,
 			  char *fname,
@@ -105,7 +109,14 @@
 		free(pconn);
 		return NULL;
 #endif
-
+	    case LISTEN_USB_M50x:
+	        if (pconn_usbm50x_open(pconn, fname, promptHotSync) < 0)
+		{
+		    free(pconn);
+		    return NULL;
+		}
+		return pconn;
+	  
 	    default:
 		fprintf(stderr, _("%s: unknown listen type %d.\n"),
 			"new_PConnection", listenType);
diff -ruN orig/coldsync-2.1.3/libpconn/PConnection_net.c coldsync-2.1.3/libpconn/PConnection_net.c
--- orig/coldsync-2.1.3/libpconn/PConnection_net.c	Sun Apr 15 06:33:56 2001
+++ coldsync-2.1.3/libpconn/PConnection_net.c	Sun Jul 15 22:54:58 2001
@@ -19,6 +19,37 @@
 #include "pconn/netsync.h"
 #include "pconn/util.h"
 
+/*
+ * Moved from netsync.h to here, since it only applies to real netsyncing,
+ * not to the Palm m50x USB cradle protocol.
+
+ * The machine with the cradle is the client. It talks to the server host,
+ * which will do the actual work of syncing.
+ *
+ * The client starts out by sending one or more wakeup packets to the
+ * server, on UDP port 14237. These packets are of the form
+ *	+------+------+------+------+
+ *	|    magic    | type |   ?  |
+ *	+------+------+------+------+
+ *	| hostid                    |
+ *	+------+------+------+------+
+ *	| netmask                   |
+ *	+------+------+------+------+
+ *	| NUL-terminated hostname...
+ *	+------+------+------+------+
+ *
+ * Where <magic> is the constant 0xfade, <type> appears to be the type of
+ * request (1 == wakeup packet, 2 == ACK). <hostid> and <netmask> are the
+ * IPv4 address and netmask of the host to sync with. <hostname> is the
+ * name of the host. HotSync appears to use the address as authoritative,
+ * and presumably sends the name along mainly for the server's benefit.
+ *
+ * The server then sends back a UDP datagram with the same information,
+ * except that <type> is set to 2. The client will send up to 3 wakeup
+ * requests before giving up. Once the server has acknowledged the wakeup
+ * packet (thereby accepting  * the connection), it listens on TCP port 14238. 
+ */
+
 /* XXX - This is just for debugging, I think */
 /* INET_NTOP
  * This is a hack, intended to support both those systems that have
@@ -45,104 +76,6 @@
 	socklen_t *cliaddr_len);
 static int net_tcp_listen(PConnection *pconn);
 
-/* Ritual statements
- * These packets are sent back and forth during the initial handshaking
- * phase. I don't know what they mean. The sequence is:
- * client sends UDP wakeup packet
- * server sends UDP wakeup ACK
- * client sends ritual response 1
- * server sends ritual statement 2
- * client sends ritual response 2
- * server sends ritual statement 3
- * client sends ritual response 3
- *
- * The comments are mostly conjecture and speculation.
- */
-/* XXX - Could these be CMP 2.0? When answering this question, might want
- * to keep in mind the underlying protocol, the one with the (other) XIDs,
- * implemented by netsync_read() and netsync_write().
- */
-static ubyte ritual_resp1[] = {
-	0x90,				/* Command */
-	0x01,				/* argc */
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x20,		/* Arg ID */
-	0x00, 0x00, 0x00, 0x08,		/* Arg length */
-	/* Arg data */
-	0x00, 0x00, 0x00, 0x01,
-	0x80, 0x00, 0x00, 0x00,
-};
-
-static ubyte ritual_stmt2[] = {
-	0x12,				/* Command */
-	0x01,				/* argc */
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x20,		/* Arg ID */
-	0x00, 0x00, 0x00, 0x24,		/* Arg length */
-	/* Arg data */
-	0xff, 0xff, 0xff, 0xff,
-	0x3c, 0x00,			/* These are reversed in the
-					 * response */
-	0x3c, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0xc0, 0xa8, 0xa5, 0x1f,		/* 192.168.165.31 */
-	0x04, 0x27, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-};
-
-static ubyte ritual_resp2[] = {
-	0x92,				/* Command */
-	0x01,				/* argc */
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x20,		/* Arg ID */
-	0x00, 0x00, 0x00, 0x24,		/* Arg length */
-	/* Arg data */
-	0xff, 0xff, 0xff, 0xff,
-	0x00, 0x3c,
-	0x00, 0x3c,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x01,
-	0xc0, 0xa8, 0x84, 0x3c,		/* 192.168.132.60
-					 * Presumably, this is the IP
-					 * address (or hostid) of the
-					 * sender.
-					 */
-	0x04, 0x1c, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-};
-
-static ubyte ritual_stmt3[] = {
-	0x13,				/* Command */
-	0x01,				/* argc */
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x20,		/* Arg ID */
-	0x00, 0x00, 0x00, 0x20,		/* Arg length */
-	/* Arg data
-	 * This is very similar to ritual statement/response 2.
-	 */
-	0xff, 0xff, 0xff, 0xff,
-	0x00, 0x3c,
-	0x00, 0x3c,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x01,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-};
-
-static ubyte ritual_resp3[] = {
-	0x93,				/* Command */
-	0x00,				/* argc? */
-	0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00,
-};
-
 static int
 net_bind(PConnection *pconn,
 	 const void *addr,
@@ -460,7 +393,7 @@
 
 	/* Exchange ritual packets with server */
 	/* Send ritual response 1 */
-	err = netsync_write(pconn, ritual_resp1, sizeof(ritual_resp1));
+	err = netsync_write(pconn, ritual_resp1, ritual_resp1_size);
 	/* XXX - Error-checking */
 	IO_TRACE(5)
 		fprintf(stderr, "netsync_write(ritual resp 1) returned %d\n",
@@ -479,7 +412,7 @@
 	}
 
 	/* Send ritual response 2 */
-	err = netsync_write(pconn, ritual_resp1, sizeof(ritual_resp2));
+	err = netsync_write(pconn, ritual_resp1, ritual_resp2_size);
 	/* XXX - Error-checking */
 	IO_TRACE(5)
 		fprintf(stderr, "netsync_write(ritual resp 2) returned %d\n",
@@ -498,7 +431,7 @@
 	}
 
 	/* Send ritual response 3 */
-	err = netsync_write(pconn, ritual_resp1, sizeof(ritual_resp3));
+	err = netsync_write(pconn, ritual_resp1, ritual_resp3_size);
 	/* XXX - Error-checking */
 	IO_TRACE(5)
 		fprintf(stderr, "netsync_write(ritual resp 3) returned %d\n",
@@ -861,7 +794,7 @@
 	}
 
 	/* Send ritual statement 2 */
-	err = netsync_write(pconn, ritual_stmt2, sizeof(ritual_stmt2));
+	err = netsync_write(pconn, ritual_stmt2, ritual_stmt2_size);
 	IO_TRACE(5)
 		fprintf(stderr, "netsync_write(ritual stmt 2) returned %d\n",
 			err);
@@ -876,7 +809,7 @@
 	}
 
 	/* Send ritual statement 3 */
-	err = netsync_write(pconn, ritual_stmt3, sizeof(ritual_stmt3));
+	err = netsync_write(pconn, ritual_stmt3, ritual_stmt3_size);
 	IO_TRACE(5)
 		fprintf(stderr, "netsync_write(ritual stmt 3) returned %d\n",
 			err);
diff -ruN orig/coldsync-2.1.3/libpconn/PConnection_usbm50x.c coldsync-2.1.3/libpconn/PConnection_usbm50x.c
--- orig/coldsync-2.1.3/libpconn/PConnection_usbm50x.c	Thu Jan  1 01:00:00 1970
+++ coldsync-2.1.3/libpconn/PConnection_usbm50x.c	Sun Jul 15 18:54:24 2001
@@ -0,0 +1,228 @@
+/*
+ * PConnection_usbm50x.c - Koen Deforche <kdf@irule.be>
+ */
+#include "config.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <errno.h>
+
+#include "pconn/PConnection.h"
+#include "pconn/netsync.h"
+#include "pconn/util.h"
+
+static int
+usbm50x_bind(PConnection *pconn,
+	     const void *addr,
+	     const int addrlen)
+{
+  return 0;
+}
+
+static int
+usbm50x_read(PConnection *p, unsigned char *buf, int len)
+{
+  return read(p->fd, buf, len);
+}
+
+static int
+usbm50x_write(PConnection *p, unsigned const char *buf, const int len)
+{
+  return write(p->fd, buf, len);
+}
+
+static int
+usbm50x_accept(PConnection *pconn)
+{
+  /*
+   * perform ritual packet exchange
+   */
+  int err;
+  const ubyte *inbuf;
+  uword inlen;
+
+  /* Receive ritual response 1 */
+  inlen = ritual_resp1_size;
+  err = netsync_read_method(pconn, &inbuf, &inlen, 1);
+  IO_TRACE(5)
+    {
+      fprintf(stderr,
+	      "netsync_read(ritual resp 1) returned %d\n",
+	      err);
+      if (err > 0)
+	debug_dump(stderr, "<<<", inbuf, inlen);
+    }
+
+  /* Send ritual statement 2 */
+  err = netsync_write(pconn, ritual_stmt2, ritual_stmt2_size);
+  IO_TRACE(5)
+    fprintf(stderr, "netsync_write(ritual stmt 2) returned %d\n",
+	    err);
+
+  /* Receive ritual response 2 */
+  err = netsync_read(pconn, &inbuf, &inlen);
+  IO_TRACE(5)
+    {
+      fprintf(stderr, "netsync_read returned %d\n", err);
+      if (err > 0)
+	debug_dump(stderr, "<<<", inbuf, inlen);
+    }
+
+  /* Send ritual statement 3 */
+  err = netsync_write(pconn, ritual_stmt3, ritual_stmt3_size);
+  IO_TRACE(5)
+    fprintf(stderr, "netsync_write(ritual stmt 3) returned %d\n",
+	    err);
+
+  /* Receive ritual response 3 */
+  err = netsync_read(pconn, &inbuf, &inlen);
+  IO_TRACE(5)
+    {
+      fprintf(stderr, "netsync_read returned %d\n", err);
+      if (err > 0)
+	debug_dump(stderr, "<<<", inbuf, inlen);
+    }
+  
+  return 0;
+}
+
+static int
+usbm50x_close(PConnection *p)
+{
+	/* Clean up the protocol stack elements */
+	dlp_tini(p);
+	netsync_tini(p);
+
+	return (p->fd >= 0 ? close(p->fd) : 0);
+}
+
+static int
+usbm50x_select(PConnection *p,
+	       pconn_direction which,
+	       struct timeval *tvp)
+{
+	fd_set fds;
+
+	FD_ZERO(&fds);
+	FD_SET(p->fd, &fds);
+
+	return (which == forReading) ? select(p->fd+1, &fds, NULL, NULL, tvp)
+				     : select(p->fd+1, NULL, &fds, NULL, tvp);
+}
+
+static int
+usbm50x_connect(PConnection *p, const void *addr, const int addrlen)
+{
+	return -1;		/* Not applicable to serial connection */
+}
+
+static int
+usbm50x_drain(PConnection *p)
+{
+  /*
+   * XXX Don't know if there's a USB equivalent of flushing a stream
+   * or tty connection.
+   */
+  return 0;
+}
+
+/*
+ * pconn_usbm50x_open
+ * Initialize a new m50x USB connection
+ * 'pconn' is a partly-initialized PConnection; it must still be
+ * initialized as a m50x USB PConnection.
+ * 'device' is the pathname of the usb HotSync port.
+ * 'prompt': if set, prompt the user to press the HotSync button.
+ */
+int
+pconn_usbm50x_open(PConnection *pconn, char *device, Bool prompt)
+{
+	struct termios term;
+
+	/* Initialize the various protocols that the serial connection will
+	 * use.
+	 */
+	/* Initialize the DLP part of the PConnection */
+	if (dlp_init(pconn) < 0)
+	{
+		dlp_tini(pconn);
+		return -1;
+	}
+
+	/* Initialize the NetSync part of the PConnnection */
+	if (netsync_init(pconn) < 0)
+	{
+		dlp_tini(pconn);
+		netsync_tini(pconn);
+		return -1;
+	}
+
+	/* Set the methods used by the network connection */
+	pconn->io_bind = &usbm50x_bind;
+	pconn->io_read = &usbm50x_read;
+	pconn->io_write = &usbm50x_write;
+	pconn->io_connect = &usbm50x_connect;
+	pconn->io_accept = &usbm50x_accept;
+	pconn->io_close = &usbm50x_close;
+	pconn->io_select = &usbm50x_select;
+	pconn->io_drain = &usbm50x_drain;
+	pconn->io_private = 0;
+
+	/* Open the device.
+	 * This is rather funky, due to the fact that the Palm as
+	 * a USB device doesn't exist until the sync starts, but
+	 * under Linux, you use it as if it were a serial port.
+	 *
+	 * Under Linux, open() returns ENXIO if the device doesn't
+	 * exist at all, and ENODEV if it doesn't exist at the
+	 * moment. I don't think open() ever returns ENODEV under
+	 * any other OS, so this should be okay. Otherwise, it
+	 * might be necessary to check the major and/or minor
+	 * device numbers under Linux, and add other Linux-specfic
+	 * hacks.
+	 */
+	while (1)
+	{
+	  	if ((pconn->fd = open(device, O_RDWR | O_BINARY))
+			    >= 0)
+				break;	/* Okay. Break out of bogus loop */
+
+			switch (errno)
+			{
+			    case ENODEV:
+				fprintf(stderr,
+					"Warning: no device on %s. "
+					"Sleeping\n",
+					device);
+				sleep(5);
+				continue;
+
+			    default:
+				fprintf(stderr,
+					"Error: Can't open \"%s\".\n",
+					device);
+				perror("open");
+				dlp_tini(pconn);
+				netsync_tini(pconn);
+				return pconn->fd;
+			}
+		}
+
+	/* Set up the terminal characteristics */
+	tcgetattr(pconn->fd, &term);	/* Get current characteristics */
+
+	/* Set initial rate. 9600 bps required for handshaking */
+	cfsetispeed(&term, B9600);
+	cfsetospeed(&term, B9600);
+
+	cfmakeraw(&term);		/* Make it raw */
+	/* XXX - Error-checking */
+	tcsetattr(pconn->fd, TCSANOW, &term);
+	/* XXX - Error-checking */
+
+	if (prompt)
+		printf("Please press the HotSync button.\n");
+
+	return pconn->fd;
+}
diff -ruN orig/coldsync-2.1.3/libpconn/netsync.c coldsync-2.1.3/libpconn/netsync.c
--- orig/coldsync-2.1.3/libpconn/netsync.c	Sun Apr 15 06:44:18 2001
+++ coldsync-2.1.3/libpconn/netsync.c	Sun Jul 15 22:06:48 2001
@@ -6,6 +6,7 @@
  */
 
 #include "config.h"
+#include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -32,6 +33,91 @@
 int net_trace = 0;		/* Debugging level for NetSync */
 #define NET_TRACE(n)	if (net_trace >= (n))
 
+/* XXX - Could these be CMP 2.0? When answering this question, might want
+ * to keep in mind the underlying protocol, the one with the (other) XIDs,
+ * implemented by netsync_read() and netsync_write().
+ */
+ubyte ritual_resp1[] = {
+	0x90,				/* Command */
+	0x01,				/* argc */
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x20,		/* Arg ID */
+	0x00, 0x00, 0x00, 0x08,		/* Arg length */
+	/* Arg data */
+	0x00, 0x00, 0x00, 0x01,
+	0x80, 0x00, 0x00, 0x00,
+};
+
+ubyte ritual_stmt2[] = {
+	0x12,				/* Command */
+	0x01,				/* argc */
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x20,		/* Arg ID */
+	0x00, 0x00, 0x00, 0x24,		/* Arg length */
+	/* Arg data */
+	0xff, 0xff, 0xff, 0xff,
+	0x3c, 0x00,			/* These are reversed in the
+					 * response */
+	0x3c, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0xc0, 0xa8, 0xa5, 0x1f,		/* 192.168.165.31 */
+	0x04, 0x27, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+};
+
+ubyte ritual_resp2[] = {
+	0x92,				/* Command */
+	0x01,				/* argc */
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x20,		/* Arg ID */
+	0x00, 0x00, 0x00, 0x24,		/* Arg length */
+	/* Arg data */
+	0xff, 0xff, 0xff, 0xff,
+	0x00, 0x3c,
+	0x00, 0x3c,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x01,
+	0xc0, 0xa8, 0x84, 0x3c,		/* 192.168.132.60
+					 * Presumably, this is the IP
+					 * address (or hostid) of the
+					 * sender.
+					 */
+	0x04, 0x1c, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+};
+
+ubyte ritual_stmt3[] = {
+	0x13,				/* Command */
+	0x01,				/* argc */
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x20,		/* Arg ID */
+	0x00, 0x00, 0x00, 0x20,		/* Arg length */
+	/* Arg data
+	 * This is very similar to ritual statement/response 2.
+	 */
+	0xff, 0xff, 0xff, 0xff,
+	0x00, 0x3c,
+	0x00, 0x3c,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x01,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+};
+
+ubyte ritual_resp3[] = {
+	0x93,				/* Command */
+	0x00,				/* argc? */
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+};
+
 /* bump_xid
  * Pick a new NetSync transaction ID by incrementing the existing one.
  * XXX - If, in fact, NetSync uses PADP, then there might be reserved XIDs,
@@ -71,6 +157,16 @@
 	return 0;
 }
 
+int
+netsync_read(PConnection *pconn,	/* Connection to Palm */
+	     const ubyte **buf,		/* Buffer to put the packet in */
+	     uword *len)		/* Length of received message */
+					/* XXX - Is a uword enough? */
+
+{
+  return netsync_read_method(pconn, buf, len, 0);
+}
+
 /* netsync_read
  * Read a NetSync packet from the given PConnection. A pointer to the
  * packet data (without the NetSync header) is put in '*buf'. The
@@ -81,10 +177,11 @@
  * negative value and sets 'palm_errno' to indicate the error.
  */
 int
-netsync_read(PConnection *pconn,	/* Connection to Palm */
-	     const ubyte **buf,		/* Buffer to put the packet in */
-	     uword *len)		/* Length of received message */
-					/* XXX - Is a uword enough? */
+netsync_read_method(PConnection *pconn,	/* Connection to Palm */
+		    const ubyte **buf,	/* Buffer to put the packet in */
+		    uword *len,		/* Length of received message */
+		    			/* XXX - Is a uword enough? */
+		    int no_header)	/* m50x starts without a header! */
 {
 	int err;
 	ubyte hdr_buf[NETSYNC_HDR_LEN];	/* Unparsed header */
@@ -96,34 +193,38 @@
 	NET_TRACE(3)
 		fprintf(stderr, "Inside netsync_read()\n");
 
-	/* Read packet header */
-	err = read(pconn->fd, hdr_buf, NETSYNC_HDR_LEN);
-	if (err < 0)
-	{
-		fprintf(stderr, _("Error reading NetSync packet header.\n"));
-		perror("read");
-		return -1;	/* XXX - Ought to retry */
-	} else if (err != NETSYNC_HDR_LEN)
-	{
-		fprintf(stderr,
-			_("Error: only read %d bytes of NetSync packet "
-			  "header.\n"),
-			err);
-		return -1;	/* XXX - Ought to continue reading */
-	}
-
-	/* Parse the header */
-	rptr = hdr_buf;
-	hdr.cmd = get_ubyte(&rptr);
-	hdr.xid = get_ubyte(&rptr);
-	hdr.len = get_udword(&rptr);
+	if (!no_header) {
+		/* Read packet header */
+	  	err = read(pconn->fd, hdr_buf, NETSYNC_HDR_LEN);
+		if (err < 0)
+		{
+		  fprintf(stderr, _("Error reading NetSync packet header.\n"));
+		  perror("read");
+		  return -1;	/* XXX - Ought to retry */
+		} else if (err != NETSYNC_HDR_LEN)
+		{
+		  fprintf(stderr,
+			  _("Error: only read %d bytes of NetSync packet "
+			    "header.\n"),
+			  err);
+		  return -1;	/* XXX - Ought to continue reading */
+		}
 
-	NET_TRACE(5)
-		fprintf(stderr,
-			"Got header: cmd 0x%02x, xid 0x%02x, len 0x%08lx\n",
-			hdr.cmd, hdr.xid, hdr.len);
+		/* Parse the header */
+		rptr = hdr_buf;
+		hdr.cmd = get_ubyte(&rptr);
+		hdr.xid = get_ubyte(&rptr);
+		hdr.len = get_udword(&rptr);
+
+		NET_TRACE(5)
+		  fprintf(stderr,
+			  "Got header: cmd 0x%02x, xid 0x%02x, len 0x%08lx\n",
+			  hdr.cmd, hdr.xid, hdr.len);
 
-	/* XXX - What to do if cmd != 1? */
+		/* XXX - What to do if cmd != 1? */
+	} else {
+		hdr.len = *len;
+	}
 
 	/* Allocate space for the payload */
 	if (pconn->net.inbuf == NULL)
@@ -132,7 +233,7 @@
 		/* XXX - Error-checking */
 	} else {
 		pconn->net.inbuf = (ubyte *)
-			realloc(pconn->net.inbuf, hdr.len);
+		realloc(pconn->net.inbuf, hdr.len);
 		/* XXX - Error-checking */
 	}
 
@@ -158,6 +259,8 @@
 			return 0;
 		}
 		got += err;
+		NET_TRACE(6)
+			fprintf(stderr, "want: %ld, got: %ld\n", want, got);
 	}
 
 	NET_TRACE(6)
diff -ruN orig/coldsync-2.1.3/src/config.c coldsync-2.1.3/src/config.c
--- orig/coldsync-2.1.3/src/config.c	Sun May  6 08:04:27 2001
+++ coldsync-2.1.3/src/config.c	Sun Jul 15 13:46:37 2001
@@ -1280,6 +1280,8 @@
 		return LISTEN_NET;
 	if (strcasecmp(str, "usb") == 0)
 		return LISTEN_USB;
+	if (strcasecmp(str, "usb_m50x") == 0)
+		return LISTEN_USB_M50x;
 	return -1;		/* None of the above */
 }