Subject: Help Wanted with USB Code
To: None <tech-kern@netbsd.org>
From: Curt Sampson <cjs@cynic.net>
List: tech-kern
Date: 12/10/2001 00:53:23
Problem summary: I'm a loser who doesn't know his back-end from
his front-end when it comes to our USB subsystem, so I need help
doing something fairly trivial.

Details:

I just bought a Sony Clie 600 (the Japanese version of the 610).
It comes with a USB cradle which seems mostly Visor-compatable.
However, there are some tweaks needed to get it (and apparently
any of the USB-cradle PalmOS 4.x devices) to work. Since the Linux
guys seem to have it going, I tried to port their patches to NetBSD.

What I'm stuck on at the moment is some "unknown data" that apparently
need to be transferred before normal visor-type operations can
start. The Linux driver does this:


	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION,
					0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
	if (response < 0) {
		err(__FUNCTION__ " - error getting connection information");
	} else {
		struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
		char *string;

		le16_to_cpus(&connection_info->num_ports);
		info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports);
		for (i = 0; i < connection_info->num_ports; ++i) {
			switch (connection_info->connections[i].port_function_id) {
				case VISOR_FUNCTION_GENERIC:
					string = "Generic";
					break;
				case VISOR_FUNCTION_DEBUGGER:
					string = "Debugger";
					break;
				case VISOR_FUNCTION_HOTSYNC:
					string = "HotSync";
					break;
				case VISOR_FUNCTION_CONSOLE:
					string = "Console";
					break;
				case VISOR_FUNCTION_REMOTE_FILE_SYS:
					string = "Remote File System";
					break;
				default:
					string = "unknown";
					break;
			}
			info("%s: port %d, is for %s use and is bound to ttyUSB%d", serial->type->name, connection_info->connections[i].port, string, serial->minor + i);
		}
	}

	if (serial->dev->descriptor.idVendor == PALM_VENDOR_ID) {
		/* Palm USB Hack */
		response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0),
					    PALM_GET_SOME_UNKNOWN_INFORMATION,
					    0xc2, 0x0000, 0x0000, transfer_buffer,
					    0x14, 300);
		if (response < 0) {
			err(__FUNCTION__ " - error getting first unknown palm command");
		} else {
			usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer);
		}
		response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0),
					    PALM_GET_SOME_UNKNOWN_INFORMATION,
					    0xc2, 0x0000, 0x0000, transfer_buffer,
					    0x14, 300);
		if (response < 0) {
			err(__FUNCTION__ " - error getting second unknown palm command");
		} else {
			usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer);
		}
	}

	/* ask for the number of bytes available, but ignore the response as it is broken */
	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
					0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
	if (response < 0) {
		err(__FUNCTION__ " - error getting bytes available request");
	}

The "Palm USB Hack" portion is what I'm attempting to emulate at
the moment. However, with this code:

	/* (Junkbuf is a 250 byte automatic char[] (i.e., on the stack).) */

	if ((vendor == USB_VENDOR_PALM) || (vendor == USB_VENDOR_SONY))
	{
		/*
		 * XXX In the Linux driver comments, this has been claimed at
		 * various times to be either a Palm USB hack or a PalmOS 4.0
		 * hack. But even when claimed to be a 4.0 hack, it's also
		 * being applied to PalmOS 3.5 devices (the 3.5 Clie and maybe
		 * the m500, if that's 3.5). This needs to be tested with a 3.5
		 * USB device to see if it really works with that.
		 */
		DPRINTF(("uvisor_init: PalmOS USB/4.0 hack\n"));
		req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
		req.bRequest = UVISOR_GET_SOME_UNKNOWN_INFORMATION;
		USETW(req.wValue, 0);
		USETW(req.wIndex, 0);
		USETW(req.wLength, sizeof junkbuf);
		err = usbd_do_request(sc->sc_udev, &req, &junkbuf);
		if (err) {
			DPRINTF(("uvisor_init: unknown 1 failed: %d", err));
			return (err);
		}
		DPRINTF(("uvisor_init: unknown data 1\n"));

		req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
		req.bRequest = UVISOR_GET_SOME_UNKNOWN_INFORMATION;
		USETW(req.wValue, 0);
		USETW(req.wIndex, 0);
		USETW(req.wLength, sizeof junkbuf);
		err = usbd_do_request(sc->sc_udev, &req, &junkbuf);
		if (err) {
			DPRINTF(("uvisor_init: unknown 2 failed: %d", err));
			return (err);
		}
		DPRINTF(("uvisor_init: unknown data 2\n"));
	}


inserted between the "getting connection info" and "getting available
bytes" portion of uvisor.c (around line 375), I get

    uvisor0: Palm, Inc. Palm Handheld, rev 1.00/1.00, addr 2
    uvisor_init: getting connection info
    usb_schedsoftintr: polling=0
    uvisor_init: PalmOS USB/4.0 hack
    usb_schedsoftintr: polling=0
    usb_schedsoftintr: polling=0
    uvisor_init: unknown 1 failed: 17
    uvisor0: init failed, STALLED
    uvisor_attach: ATTACH ERROR

Can someone throw me a bone and tell me what I'm doing wrong, here?

And while we're at it, what's the deal with the "uhub0: device
problem, disabling port n" messages? I seem to get a lot of these
with various unsupported devices, and looking at the code it makes
it look like the device just isn't responding to a status request.
Is there something more I can do (under NetBSD) to figure out why
these devices aren't supported? Or is this a "run it under Windows
with the USB sniffer" kind of situation?

cjs
-- 
Curt Sampson  <cjs@cynic.net>   917 532 4208   http://www.netbsd.org
    Don't you know, in this new Dark Age, we're all light.  --XTC