?

Log in

No account? Create an account

Zaurus and sound

Last June I got a Zaurus PDA. IT runs Linux, and the idea is that I'll be able to use it for contact management, etc. If I can just get it talking.


But the sound driver crashes in audio_sync some times when the SNDCTL_SYNC IOCTL is issued. The kernel oopses and no more sound comes out. All very sad. And it's useless until I can fix this.

I finally got a chance to look at pxa-i2s.c in the Zaurus kernel sources. What complete crap. It seems like there is basically no locking in the code at all. I'm not completely convinced this is wrong for a uniprocessor machine, but the coding style does not inspire confidence so it will take me a while to reason about locking correctness. Here's a typical example of the style:
 if (b->offset &= ~3)  
I think that statement actually happens to be more or less correct, although it will sometimes lose a partial sample, but it brings new meaning to the word side effect. Hopefully I can figure out a solution to this problem before going to Japan.

Here's what I've discovered so far. In most other Linux sound drivers I've examined, the sync routine just calls the appropriate routine to kick off DMA even if the buffers aren't full, then waits until DMA catches up with the current sample. The Sharp driver doesn't seem to have any other conditions that wil start DMA other than full buffers, so the DMA code is inlined. In addition, the Sharp code is structured to only deal with DMA for full fragments. The rest of the code seems to mostly assume that DMA descriptors will always point to the next DMA descriptor in a fragment or at least that's the steady state. So, the sync code interrupts the dMA descriptor chain, replacing the DMA descriptor that overlaps the end of the partial fragment with one that ends early and that points to stop for the next descriptor. It then starts up DMA if it is not already running and waits for DMA to stop. That's right, it waits for DMA to stop, not for DMA to get past the point where the sync is called. I'm a bit concerned about what happens if one process calls sync while another calls write with a full buffer, but I don't think my application does that. After DMA catches up, the sync code patches the DMA descriptors back together and returns.

Somewhere in this mess is a memory handling error that seems to be causing a null pointer dereference. Next up is debugging by excessive printf. AT least the code is incredibly simple; instead of using per-device data structures, it uses global statics. Instead of using abstraction, it seems to all be inlined. Instead of using error checking or defensive programming, it lets me find bugs.
Tags:

Comments