Thursday, 6 November 2008

Kernel changes for USB host

Oh, in case anyone wants to experiment with this, just add this to your machine file (arch/arm/mach-pxa/palmXX.c). I'm not going to post binaries or even a full patch now as this is still pretty experimental and you'll need to compile your own kernel with the drivers for whatever you want to connect anyway. Add the following headers, functions and a call in machine_init(). This should work on most of the PXA270 Palms.

#include <mach/pxa27x-udc.h>
#include <mach/ohci.h>

/*
 * USB Host (OHCI)
 */
static int palmt650_ohci_init(struct device *dev)
{
       UP2OCR = UP2OCR_HXS | UP2OCR_HXOE;
       UHCRHDA |= UHCRHDA_NOCP;
       UHCHR &= ~(UHCHR_SSEP2 | UHCHR_SSE);
       return 0;
}

static struct pxaohci_platform_data palmt650_ohci_platform_data = {
       .port_mode      = PMM_NPS_MODE,
       .init           = palmt650_ohci_init,
};

static void __init palmt650_init(void)
{
        ...
        pxa_set_ohci_info(&palmt650_ohci_platform_data);
}

You'll need to enable OHCI under USB host. I have been disabling USB gadget (client) support and I haven't tested what happens if you have both host and client enabled. I assume though that host probably takes precedence.

The easiest way to get a full speed device to enumerate is to plug the device in and use the "USB console" menu in Cocoboot before starting Linux. That'll turn on the USB pullups which will trick Linux into realizing there's a full speed device connected. You can also try turning on/off the pullups directly in Linux (GPIO 114 on the Treo 650). You can use gpio-val.c to control them within Linux (or a kernel module like GPIOed if you're using our older linux-hnd kernels).

Plus, someone was asking for a copy of the rootfs I use. For development work I just have an SD card with Debian/armel installed on it. This is not completely suitable for mobile devices but Debian has a ton of precompiled packages which you can just install with apt-get. This saves mucking around compiling. A few weeks ago I wrote some instructions in the forum including a tarball of a bare bones Debian image. I just install gcc, git-core and such on there and compile stuff on the device itself must of the time.

First attempt at a wifi dongle

...was unfortunately only partially successful. I picked up a few cheap link cables and the smallest USB wifi dongle I found in a brief search. The wifi dongles turned out to be based on the Zydas ZD1211 chipset (actually rebranded as Atheros AR5524) which is excellent for two reasons: they have drivers in the mainstream Linux kernel and they can run fine off a 3.3V power source. I went for the cheap after-market link cables (actually retractable ones) as they have easy to solder connectors which have all the pins.

I chopped the ends off one of each and soldered the GND, USB+ and USB- appropriately. For the dongles' power supply I tried the "EXT_POWER" pin on the multiconnector, which is supposed to be for powering accessories. To make Palm OS activate the power pin, tie the serial pins on the multiconnector to ground. In Linux on the Treo 650 you can toggle it with GPIO 37.

The dongle was detected fine by Linux and the driver sucessfully uploaded the firmware. Unfortunately on powering up the radio though the device appears to hang and the driver starts reporting timeouts. My guess was the "EXT_POWER" pin cannot supply enough current. To check this, I used my usual trick of stealing power from a molex connector in my PC. Sure enough, it started working fine and I was able to scan and connect to a network and then SSH in from my PC.

This is unfortunate as I'll probably end up having to add a battery pack of some sort. It's much neater a tidier without one. Oh well, probably a smallish Polymer Lithium-ion battery would be suitable. However, the fact that the device enumerates and can have the firmware uploaded while powered by "EXT_POWER" means it may be suitable for lower power USB devices, like flash drives or mice.

Yes, I have heard of SDIO, but it's more fun this way.

Friday, 17 October 2008

USB host mode on the Treo 650

Previously I'd always just assumed the USB host pins were separate from the USB client ones, so we wouldn't be able to use the USB port on the multiconnector as a host. Turns out I was wrong. Sleep_Walker pointed out that the PXA27x's USB client pins can the routed to the host controller. I had to try it. So I cut the USB connectors of an old dead motherboard with a jigsaw and soldered the D+ pins and D- pins of each connector respectively together. I then ran +5V from my PC because the Treo can't supply it. Any +5V source should do, so a battery pack or some kind of charge powered by the treo's 3.7V output would also work, the PC was just the closest handy source. I then configured USB port 2 in host mode and powered it up.
UP2OCR = UP2OCR_HXS | UP2OCR_HXOE;
UHCRHDA |= UHCRHDA_NOCP;
UHCHR &= ~(UHCHR_SSEP2 | UHCHR_SSE);
I found low-speed devices (like old mice) just work, but full-speed (USB1.1+ devices) fail to detect. There seems to be an extra strong pull-down on the USB+ pin, probably as part of the USB client hardware. To get around this we can turn on the Treo's own usb client pullups and trick itself into realising there's a full-speed device attached. ;-) Anyway here's the result, a USB keyboard (with builtin hub) and mouse controlling the Treo directly:

Virtually every USB device with a Linux driver I've tried works. I'm looking to get a USB wifi dongle. Not sure it'll be so easy to mount inside as the Eee PC upgrades are. ;-) Update: Sleep_Walker has now tried the same thing on the 680. He reports that there's no pulldown problems on the 680 so full-speed devices detect correctly without any hacks. He also tried a slightly easy way of doing it, all you need is standard powered USB hub (to supply the +5V) and a USB gender changer, no soldering required.

Friday, 10 October 2008

Success: Two-way phone call with Treo 650 in Linux

Now that I have a VOIP account that can make unmetered calls to mobiles I decided to try having a play with getting two-way phone calls working from Linux on the Treo 650. I turned on the phone part in Palm OS, booted this kernel and reset the power on the gsm module with:
echo 0 > /sys/devices/platform/palmt650-pm-gsm/power_on
echo 1 > /sys/devices/platform/palmt650-pm-gsm/power_on
echo 1 > /sys/devices/platform/palmt650-pm-gsm/wake
I then fired open minicom and opened /dev/ttyS0 at baud 460800 without flow control. I then connected the modem to the network and entered my subsidy unlock pin:
AT+CFUN=1
AT+CPIN="xxxxxxxxx"
Once connected, I called my phone via VOIP and then answered with the ATA command:
RING
RING

ATA
OK
At that point I opened up a few terminal windows and started fiddling with ALSA. I first started playing some white noise so I could heer when I started transmitting:
cat /dev/urandom > /dev/dsp
I discovered you can divert PCM to be transmitted by the phone using:
      Master Mono: Enable, set transmit volume
              PCM: Enable, set PCM volume
PCM Play to Phone: Enable to route PCM signal to the phone module
After some more fiddling I routed the microphone to the phone. The labeling of the Mic controls in the ALSA driver is rather strange but here are the key settings:
      Master Mono: Enable, set transmit volume
Mic Select Source: mic1=handset, mic2=headset
            Mic 2: Selected mic volume
   Mic 1 to phone: Enable/disable handset mic 
   Mic 2 to phone: Enable/disable oheadset mic
   Mic 20dB Boost: Useful in speakerphone mode, you can talk from quite a distance.

Mic 1: [irrelevant?]
Mic select:  [irrelevant?]
After that I managed to get the incoming audio going out the handset earpiece with these settings:
         Master: Enable, earpiece volume
Master Left Inv: Enable
          Phone: Seems you don't need to unmute, but need to set volume.
Phone to Master: Enable
            Aux: Set a high volume (weird stuff happens if low)
    Out3 LR Mux: Master Mix (mislabeled, it's actually out2)
I've made an ALSA state file for working two-way phone audio with the handset.

Thursday, 14 August 2008

Hang on palmt650 first printk

Locks up in kernel/printk.c with time enabled:
asmlinkage int vprintk(const char *fmt, va_list args)
{
...
                        if (printk_time) {
                                /* Follow the token with the time */
                                char tbuf[50], *tp;
                                unsigned tlen;
                                unsigned long long t;
                                unsigned long nanosec_rem;

                                t = cpu_clock(printk_cpu);
                                nanosec_rem = do_div(t, 1000000000);
                                tlen = sprintf(tbuf, "[%5lu.%06lu] ",
                                                (unsigned long) t,
                                                nanosec_rem / 1000);

                                for (tp = tbuf; tp < tbuf + tlen; tp++)
                                        emit_log_char(*tp);
                                printed_len += tlen;
                        }

Friday, 18 April 2008

Palm Tungsten C wifi in Linux

Just noting this before I forget it. Use fc447e3213efb31cb16b5d9a2b0ebb77fbafd131 from git://git.hackndev.com/linux-2.6 with the defconfig. You'll need to load standard RAM prism firmware (pm010102.hex and rf010804.hex should work), but prism2_srec has to be patched as the production data area ("PDA") has an invalid CRC. A patch like this should do the trick:
diff -ru hostap-utils-0.4.7/util.c hostap-utils-0.4.7-hacked/util.c
--- hostap-utils-0.4.7/util.c   2004-02-14 18:50:12.000000000 +0000
+++ hostap-utils-0.4.7-hacked/util.c    2008-04-18 21:32:17.000000000 +0000
 -372,7 +372,7 @@
 
        fclose(f);
 
-       return parse_wlan_pda(pda_info, 0);
+       return parse_wlan_pda(pda_info, 1);
 }
Add to /etc/pcmcia/hostap_cs.conf (or equivalent)
card "PRISM ISL37101P-SSF Adapter"                                                                                                 
  manfid 0x000b, 0x7110
  bind "hostap_cs"
Then start the "cardmgr" daemon. It should detect and bind the card to hostap_cs, so you can see it as "wlan0" and "wifi0" in "ifconfig -a". You should then be able to load firmware using something like:
prism2_srec -gs wlan0 pm010102.hex
prism2_srec -gp wlan0 pm010102.hex
prism2_srec -rp wlan0 rf010804.hex
You can then configure and use as normal:
ifconfig wifi0 up
ifconfig wlan0 up
iwconfig mode wlan0 managed
iwlist scan
...or whatever