desrod / pilot-link

pilot-link is a suite of tools used to connect your Palm or PalmOS® compatible handheld with Unix, Linux, and any other POSIX-compatible machine.
GNU General Public License v2.0
11 stars 7 forks source link

Trouble trying to sync Handspring Treo 90 #13

Open Lana-chan opened 1 year ago

Lana-chan commented 1 year ago

I'm trying to hotsync a Treo 90, which doesn't seem to work with the usbserial/visor kernel modules, so it seems it needs the libusb mode. I can sync a Visor Neo with this method fine, but not the Treo. Using the debug log, I found this:

libusb.c: 132, 0x082d 0x0200.
libusb.c: trying to open device 0x55b392af2d20
libusb.c: USB_handle=0x55b392af4180
usb: PALM_GET_EXT_CONNECTION_INFORMATION, num_ports=16, endpoint_numbers_different=147
    [0] port_function_id='�U'
    [0] port=32
    [0] endpoint_info=80
    [1] port_function_id='�U'
    [1] port=0
    [1] endpoint_info=0
    [2] port_function_id=''
    [2] port=0
    [2] endpoint_info=73
    [3] port_function_id='89��'
    [3] port=176
    [3] endpoint_info=149
    [4] port_function_id='�'
    [4] port=80
    [4] endpoint_info=211
    [5] port_function_id='�'
    [5] port=0
    [5] endpoint_info=0
    [6] port_function_id=''
    [6] port=210
    [6] endpoint_info=149
    [7] port_function_id='�'
    [7] port=209
    [7] endpoint_info=149
    [8] port_function_id='�'
    [8] port=224
    [8] endpoint_info=170
    [9] port_function_id='�U'
    [9] port=128
    [9] endpoint_info=65
    [10] port_function_id='�U'
    [10] port=150
    [10] endpoint_info=40
    [11] port_function_id=''
    [11] port=0
    [11] endpoint_info=150
    [12] port_function_id='�'
    [12] port=0
    [12] endpoint_info=73
    [13] port_function_id='89��'
    [13] port=0
    [13] endpoint_info=150
    [14] port_function_id='�'
    [14] port=16
    [14] endpoint_info=220
    [15] port_function_id='�'
    [15] port=208
    [15] endpoint_info=157
usb: PALM_GET_EXT_CONNECTION_INFORMATION - no hotsync port found.
libusb.c: USB configure failed for familar device: 0x082d 0x0200. (LifeDrive issue?)

On a whim I tried to set the Treo's device configuration with the visor flag and recompiled pilot-link, just in case it would somehow work, but it doesn't:

libusb.c: 132, 0x082d 0x0200.
libusb.c: trying to open device 0x55dc116ebd20
libusb.c: USB_handle=0x55dc116ed180
usb: VISOR_GET_CONNECTION_INFORMATION, num_ports=0
GENERIC_REQUEST_BYTES_AVAILABLE returns 0x0000
Out: 0x3 0xff.
In: 0x84 0xff.
Config: 0, 0xff 0xff | 0x84 0x3.
libusb.c: 225.
libusb.c 453 (u_poll).
libusb.c 499 (u_read_i): 1 1 0
libusb.c 522 (u_read_i): 1 0.
Reading: len: 64, timeout: 0.
libusb.c 281 (RD_do_read): 0
Reading: len: 64, timeout: 0.
libusb.c 281 (RD_do_read): 0
Reading: len: 64, timeout: 0.
libusb.c 281 (RD_do_read): 0
Reading: len: 64, timeout: 0.
[...]

Any ideas?

EDIT: This Treo hotsyncs fine on Windows machines with Palm Desktop, so I know neither the device or the cable should be the issue.

Lana-chan commented 1 year ago

I managed to capture a complete hotsync transaction with Wireshark on my Windows machine using Palm Desktop 6.2.2. Of note I can see the proper "cnys" id that pilot-link looks for in the following frame: image I'm not well versed in USB protocols but I'm going to try moving forward with this. If anyone is interested in the capture (which I've saved truncated up until the point where the device identifies my hotsync username) please contact me.

Lana-chan commented 1 year ago

I tried adding a new USB init flag for the Treo (which would undoubtedly break other Treo models, but at least for sake of attempted fixes for now) and modifying USB_configure_generic like so (which also involved adding the interrupt_read handler to libusb.c):

    if (flags & USB_INIT_TREO) {
        // weird beast
        unsigned char buf[sizeof(palm_ext_connection_info_t) + 6];
        ret = dev->impl.control_request (dev, 0xc2, VISOR_GET_CONNECTION_INFORMATION, 0, 0, &ci, sizeof (ci), 0);
        LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "usb: VISOR_GET_CONNECTION_INFORMATION (ret=%08x)\n", ret));
        ret = dev->impl.control_request (dev, 0xc2, PALM_GET_EXT_CONNECTION_INFORMATION, 0, 0, &ci, sizeof (ci), 0);
        LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "usb: PALM_GET_EXT_CONNECTION_INFORMATION (ret=%08x)\n", ret));
        ret = dev->impl.interrupt_read (dev, 0x82, &buf, sizeof (buf), 0);
        memcpy(&ci, (buf+6), sizeof (ci));
    } else {
        ret = dev->impl.control_request (dev, 0xc2, PALM_GET_EXT_CONNECTION_INFORMATION, 0, 0, &ci, sizeof (ci), 0);
    }

However, despite getting the correct Palm hotsync header and USB endpoints (which match the ones used in the USB bulk transfers on Windows) now, the device still doesn't go any further:

libusb.c: 135, 0x082d 0x0200.
libusb.c: trying to open device 0x563af1a74410
libusb.c: USB_handle=0x563af1a75ee0
usb: VISOR_GET_CONNECTION_INFORMATION (ret=00000000)
usb: PALM_GET_EXT_CONNECTION_INFORMATION (ret=00000000)
usb: PALM_GET_EXT_CONNECTION_INFORMATION, num_ports=1, endpoint_numbers_different=1
    [0] port_function_id='cnys'
    [0] port=0
    [0] endpoint_info=67
GENERIC_REQUEST_BYTES_AVAILABLE returns 0x0000
Out: 0x3 0x3.
In: 0x84 0x4.
Config: 0, 0x4 0x3 | 0x84 0x3.
libusb.c: 228.
libusb.c 456 (u_poll).
libusb.c 502 (u_read_i): 1 1 0
libusb.c 525 (u_read_i): 1 0.
Reading: len: 64, timeout: 0.

EDIT: Looking closer at the USB capture, a simpler way to modify USB_configure_generic follows:

    ret = dev->impl.control_request (dev, 0xc2, PALM_GET_EXT_CONNECTION_INFORMATION, 0, 0, &ci, sizeof (ci), 0);

    if (ret == 0) {
        // empty response from PALM_GET_EXT_CONNECTION_INFORMATION, try interrupt
        unsigned char buf[sizeof(palm_ext_connection_info_t) + 6];
        // 6 first bytes seem to indicate a vendor id, we don't use that yet
        ret = dev->impl.interrupt_read (dev, 0x82, &buf, sizeof (buf), 0);
        memcpy(&ci, (buf+6), sizeof (ci));
    }

This way the need to single out the Treo 90 with a USB init flag is no longer necessary, and my Palm TX still syncs over libusb without change. However the debug log for the Treo above still follows, getting the correct USB endpoints but then getting stuck.

Lana-chan commented 1 year ago

I'm comparing the bulk transfers past the hotsync endpoint handshake between the Treo 90 and my Palm TX from USB captures with Palm Desktop 6.2.2 and so far I haven't seen any differences that jump out to me. Which makes me think there's still some extraneous part of the device detection that's hanging when trying to read the first couple of bulk packets before sending more data, rather than a difference in the hotsync protocol itself.

For comparison here's a partial dump from the TX syncing with pilot-link (flag -l to list packages):

libusb.c: 135, 0x0830 0x0061.
libusb.c: trying to open device 0x55dc3e65c5b0
libusb.c: USB_handle=0x55dc3e65dfb0
usb: PALM_GET_EXT_CONNECTION_INFORMATION, num_ports=1, endpoint_numbers_different=1
    [0] port_function_id='cnys'
    [0] port=0
    [0] endpoint_info=103
In: 0x81 0x6.
Out: 0x2 0x7.
In: 0x86 0x6.
Out: 0x7 0x7.
Config: 0, 0x6 0x7 | 0x86 0x7.
libusb.c: 228.
libusb.c 456 (u_poll).
libusb.c 502 (u_read_i): 1 1 0
Reading: len: 64, timeout: 0.
libusb.c 525 (u_read_i): 1 0.
libusb.c 284 (RD_do_read): 6
Reading: len: 64, timeout: 0.
libusb.c 546 (u_read_i): 1 6.
libusb.c 553 (u_read_i): 1 6.
libusb.c 580 (u_read_i).
libusb.c 502 (u_read_i): 10 1 0
libusb.c 525 (u_read_i): 10 6.
libusb.c 284 (RD_do_read): 22
Reading: len: 64, timeout: 0.
libusb.c 546 (u_read_i): 10 28.
libusb.c 553 (u_read_i): 10 28.
libusb.c 580 (u_read_i).
Read: 10 (10).
usb.c: 434, prot: 0x6, type: 0x10, cmd: 0x2.
usb.c: 477, net rx.

On my USB captures, both the Treo 90 and the TX exhibit the first two bulk reads with packet lengths 6 and 22 (the Treo immediately after the interrupt read, and the TX immediately after the palm control request), which matches the first two pilot-link reads of the TX's debug. However the Treo simply doesn't send them to pilot-link and it hangs on RD_do_read instead, until it times out with 0 bytes read. Perhaps something is needed to free the device after the interrupt read, but I'm not clear on what yet.

Lana-chan commented 1 year ago

Perhaps something is needed to free the device after the interrupt read, but I'm not clear on what yet.

Ha, the answer was really quite that obvious. I noted the packet from the interrupt read in my USB capture was 64 bytes long, which meant that in trying to make it similar to the control request and asking only for as many bytes to fill the palm_ext_connection_info struct, the Treo didn't know what to do with the remaining bytes and would wait for a remaining read that never happened. Once I hardcoded the size of the buffer in my patch to 64 bytes instead, the Treo instantly synced with pilot-link.

Now I need to clean up my code so I can submit a PR.