Featured image of post Walkman Hands-On: Giving a Ten-Year-Old Gadget a New UI (Part 1)

Walkman Hands-On: Giving a Ten-Year-Old Gadget a New UI (Part 1)

A while back I got one of those sudden itches to pick up a Walkman, having been a loyal NW-series owner back in the day. Once it arrived I did some reading and found the community has already been through all of this: custom firmwares like Walkman One, various UI tweaks. Honestly, at first I didn’t see much worth tinkering with. I flashed Walkman One and then it just sat there gathering dust. Partly because having to use wired headphones is a pain, and partly because the firmware had started having compatibility trouble with my AirPods Pro 2: they’d pair, and then play nothing at all. So it went back in the drawer.

Then over the Mid-Autumn holiday I remembered I still had the thing. It bugged me, sitting there useless. So I dug it out to see what I could actually do with it, and noticed that these custom firmwares quietly switch on the adbd that Sony left behind. Suddenly this got interesting: with a root shell, the whole machine is mine. I can do whatever I want.

First, a quick look at what this thing is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ adb devices
List of devices attached
10453485000783	device

$ adb shell
# cat /proc/meminfo | head -n 3
MemTotal:         467984 kB
MemFree:           44644 kB
Buffers:           21532 kB

# cat /proc/cmdline
console=/dev/null root=/dev/ram vmalloc=496M slub_max_order=0 slub_debug=O  lcm=1-otm8018b_vdo_cmd fps=6023 vram=6291456 androidboot.selinux=disabled bootprof.pl_t=1145 bootprof.lk_t=2137 printk.disable_uart=0 boot_reason=4 icx_pm_helper.icx_sysinfo=0x00000000 icx_pm_helper.icx_modelid=0x20000007 mmc_core.emmc_boot_serial=0x96615529 icx_pm_helper.icx_boot_option=0 leds_drv.brightness=255 androidboot.serialno=10453485000783 androidboot.bootreason=wdt_by_pass_pwk icx_pm_helper.icx_boot_reason=0x1 androidboot.hardware=icx androidboot.console=ttyMT1 androidboot.printk=0 androidboot.bid3=1 

# cat /proc/cpuinfo
Processor	: ARMv7 Processor rev 3 (v7l)
...
Processor	: ARMv7 Processor rev 3 (v7l)
...

Hardware	: MT8590
Revision	: 0000
Serial		: 0000000000000000

# ls | tr '\n' ' '
bin boot boot.sh bootshow bootui build.prop cache contents contents_ext contents_ext1 data db default.prop dev emmc@android emmc@bootimg emmc@cache emmc@cm4 emmc@contents emmc@db emmc@dkb emmc@ebr1 emmc@expdb emmc@kb emmc@logo emmc@misc emmc@nvp emmc@nvram emmc@option1 emmc@option2 emmc@option3 emmc@pro_info emmc@protect_f emmc@protect_s emmc@recovery emmc@sec_ro emmc@seccfg emmc@tee1 emmc@tee2 emmc@uboot emmc@usrdata emmc@var emmc@xhrome etc factory file_contexts home init init.hagoromo.rc init.project.rc init.rc init.real init.usbcfg.rc init.usbcfgdmp.rc install_update_script lib newroot oem_cast_shlib opt1 opt2 opt3 proc res root sbin sys system tmp ueventd.audiodefault-b1.rc ueventd.audiodefault-b2.rc ueventd.audiodefault-b3.rc ueventd.icx.rc ueventd.rc usr var xbin

Looks like a fairly ordinary Linux with a very Android-flavoured rootfs. Which raises the question: if I want to put something on this screen, how would I even go about it?

A quick search showed someone in the community had already done it: wampy. In short, Sony’s main player binary HgrmMediaPlayerApp is a Qt app, and the author cleverly used the Qt eglfs platform plugin to squeeze his own code into that process, then called QWindow::hide() to hide the original window. The screen is free again. To make it easy for others to build on his work, he also provided a /tmp/wampy.sock plus a wampyctl command, giving the rest of us a much friendlier way in.

So running things is solved. What’s left is deciding what to run. DOOM came to mind first, but an FPS on that little touchscreen is a bit rough to control (haha). Then I thought of another classic that has been ported to everything: SDLPAL.

The first thing SDLPAL needs is SDL working on this platform. Doing that properly means writing an SDL video driver, which for a little experiment like this isn’t really worth it. But wampy’s cassette renderer shows the trick: to get pixels on screen you can just build a bitmap in memory and treat it as a texture. Which is to say, run SDL in pure CPU mode, draw everything into a 480x800 SDL_Surface, then push that texture to the panel with eglSwapBuffers.

To check the idea I just had DSH write it (actually typing the code out by hand is dull, isn’t it). Getting the basic shapes up on screen went smoothly:

With the display sorted, not much was left. Next I had the AI handle touch and button input, cross-compiled SDL2 statically with zig (-target arm-linux-gnueabihf.2.23), copied my game files onto the device, and just like that the game was running.

Friend: now that’s a hifi way to knock your head

Friend: good sound is what makes a good head

It wasn’t nearly that smooth, of course. Plenty of potholes along the way. Here’s a quick list of what broke and how it got fixed; I don’t remember the details well enough anymore, so I had the AI summarise them for me:

  • Events did nothing: pushing SDL_KEYDOWN into SDL’s queue had no effect. SDLPAL reads input by polling SDL_GetKeyboardState(), so we had to write the keyboard state directly.
  • Key passthrough: hiding the window only stops the drawing; Sony’s KeyService still reads the same evdev node. Pressing Play did nothing in the game and started an MP3 instead → EVIOCGRAB on event0/1/4.
  • Red and blue swapped: SDL_PIXELFORMAT_ARGB8888 is B,G,R,A in little-endian memory, so uploading it as GL_RGBA inverted the colours → RGBA32.
  • Touch was way off: the panel reports 0..959 × 0..1599, not 480×800, so the red dot in the help overlay had nothing to do with my finger.
  • Who owns the sound card: SDL’s ALSA backend never actually made it into the cross build; the kernel’s OSS compat layer works with AUDIODEV=/dev/snd/dsp. If Sony is playing, pause it first; if that doesn’t help, run muted.

By this point a rather bold idea had hit me, maybe even a slightly cocky one. I don’t think Sony’s system is all that pleasant to use. And with some AI magic on my side, plus the fact that I know my way around Linux and audio codecs (not an expert, but enough to get by), why not build a userspace player that actually suits my own tastes?

comments powered by Disqus
Except where otherwise noted, content on this blog is licensed under CC-BY 2.0.
Built with Hugo
Theme Stack designed by Jimmy