Paul Kocialkowski's coding blog

Free software, programming and stuff

kernel

Android with mainline Linux kernel support on the Goldelico GTA04

Written by Paul Kocialkowski - 27 june 2014 - 3 comments

During the past few months, I've been working on bringing Replicant 4.2 support to the Goldelico GTA04, a montherboard replacement for the Openmoko FreeRunner (GTA02) that is manufactured by Golden Delicious with the intent of being free software friendly. The board design is also released under a free licence. There is an active community of developers and users dedicated to the GTA04 and other similar projects, brougt together under the hood of OpenPhoenux. Other similar projects include the upcoming Neo900, a motherboard replacement for the Nokia N900 using similar hardware as the GTA04 and also aiming to be free software friendly, with a particular emphasis on security and privacy features.

I recently published a blog post covering the status of the Replicant 4.2 port to the Goldelico GTA04 on the Replicant blog, with a nice video highlighting which features already work well. However, in the present post, I would like to cover some of the technical aspects of the port, especially regarding the use of a recent mainline Linux kernel with Android 4.2.

Currently, Android devices ship with Linux 3.4, after a long time of using version 3.0, which started with Android 4.0 Ice Cream Sandwich. To this day, the reference common Android kernel repos have branches with Linux 3.10 and experimental work is done on Linux 3.14. That's pretty close to the Linux 3.12 version we're using on the GTA04!

Opportunistic suspend

The first challenge to overcome was dealing with suspend and resume. Android uses a particular mechanism to implement opportunistic suspend, using wakelocks: both the kernel and userspace can register these locks to prevent the device from going to suspend. In Android kernels, there is another mechanism that allows some non-critical chips to reach suspend state before the rest of the system: this is earlysuspend. As the whole Android system is built around the concept of wakelocks to handle power management, something similar needed to be implemented in the mainline Linux kernel. After efforts from the Android kernel maintainers, wakelocks were implemented in a clean fashion some time ago. In order to implement opportunistic suspend, a separate interface was implemented on mainline Linux, known as autosleep, which uses different nodes than /sys/power/state (that the Android kernels use directly for opportunistic suspend). Starting in Android 4.1, a library was added to Android in order to detect and handle these different modes.

So thankfully, everything was already in place to use autosleep properly on Android 4.2. Except that it didn't work. This turned out to be because of a dedicated capability that was missing from the Android userspace: CAP_BLOCK_SUSPEND. It turned out to be easier to just revert the patch restricting access to wakelocks to users with that capability in the kernel.

Android USB Gadget and Android Debug Bridge

Android also went their own way in implementing USB device drivers for the various things that are used by Android: mass storage, rndis for USB networking, MTP for file access and a couple others, including ADB. The Android Debug Bridge (ADB) is a great way of debugging what's going on with an Android device, providing easy access to the logs, to a shell and file transfer (these are the features of ADB I use the most). All of that is not integrated at all in the mainline Linux kernel, so there was some substantial work to do here. The first thing to do was importing the related commits from the android-3.10 branch of the common Android Linux kernel. All of that built nicely with only minor code corrections, to follow some API changes in 3.12 and some features like rndis or MTP worked right away, but the most interesting part was left not working: that's the Android Debug Bridge. A few kernel versions back, there used to be a dedicated composite function driver for ADB, but a commit by one of Android's kernel maintainers totally gets rid of it, calling it obsolete with no further information. While attempts to restore it failed, I tried to find out in details why it is obsolete and if that meant the final death of ADB, that I found rather convenient. Thankfully, someone found out what happened and wrote about it: the dedicated ADB driver was being replaced by another one using FunctionFS, a more flexible and generic way of implementing such drivers, directly from userspace. It turns out that FunctionFS support for the userspace ADB server was merged nearly entirely in Android 4.2. I had to backport a missing fix to have it fully working properly and also had to import adaptation a patch in recovery to have sideload working with FunctionFS too. A few bits were also needed in the initialization procedure to have things set up right. Once all of that was done, it could finally run flawlessly!

Headset/headphones detection with SoC Jack

So Jack's a good guy. Everyone knows about that. Whether he's saving the homeland from yet another threat or just letting us know something of interest just got plugged in one hole or another, it always feels great to hear from Jack. However, the Android kernel guys didn't seem to appreciate his participation in the show as much as we all do, or at least until recently.

The traditional way of reporting a headset or headphones plug/unplug in Android kernels was using a switch called h2w, reporting these events to userspace. The mainline kernel prefers another approach, using our beloved Jack SoC architecture. It also provides a convenient way of reporting button pushes, which is quite nice. So instead of rewriting it all using the h2w switch, it struck me that there is a frameworks config option to politely ask Android to give Jack some consideration. And when it does that, everything works great, including button press reports!

Galaxy S2 Replicant port status update

Written by Paul Kocialkowski - 04 february 2013 - 2 comments

Quite some time ago, I was given the opportunity to receive a crowd-funded Galaxy S2 phone. Even though I was very thankful for it, I couldn't really focus on it at first since I had to handle other things on various other devices I was working on. It left me somehow sad as I felt that it was my duty to add proper Replicant support for it. Today, I'm proud to announce that the biggest part of the work to support it is over.

The modem (XMM6260)

At first, we had to add support for the modem, an XMM 6260 modem with a custom Samsung firmware. The modem protocol is what we call Samsung IPC, the very same as the one used in the Nexus S or Galaxy S. Our lower-layer library to handle it is libsamsung-ipc, that is shared between Replicant and SHR. So We had to add support for XMM6260 in libsamsung-ipc, along with Galaxy S2-specific bits. Thoughtfully, we designed the upper layer, Samsung-RIL (that is specific to Replicant) to work with libsamsung-ipc regardless of the device it's running on. Nowadays, the modem support is complete and we have working calls, messages and data. Anyway, modem features support is up to Samsung-RIL, so it's not Galaxy S2-specific.

The Audio CODEC (Yamaha MC1N2)

After doing a break in Galaxy S2 development, I finally got back to it, and started the 4.0 Replicant version for the occasion. Since the audio module was non-free in CyanogenMod, it was one of the key components to add support for. (What good is a phone if you can't get any sound out of it?) So after digging a little in the kernel code, it turned out that the Audio CODEC had an ALSA interface driver. That means PCM In/Out interfaces as well as Mixer controls. Only problem was that I still couldn't get any sound out of it using the TinyALSA test utils. After doing a bit of research, I found out about the /dev/snd/hwC0D0 node, that was implementing hardware-specific controls (via ioctl). After adding debug prints to it and with the help of some CyanogenMod developers, I was able to reimplement it on my Yamaha-MC1N2-Audio library. The ALSA part was done with a 4.0 update (call it a complete rewrite) of my TinyALSA-Audio library. The combination of the two made it possible to have sound with Replicant (including during calls). It is even used by CyanogenMod since version 10.1!

The sensors (K3DH accelerometer)

With modem and audio support, the Galaxy S2 was made usable as a phone. Thanks to the free hwcomposer module, it's very fast too, so I decided to use it as a main phone for a time, and frankly quite enjoyed the ride. The sensors were also relying on a non-free library, the one called libakm: AKM is the compass manufacturer. Nonetheless, it includes the bits to properly handle the K3DH accelerometer chip too. The situation is quite similar to the Nexus S sensors, and I was able to figure out the accelerometer part back then (it was a KR3DH) and implemented it in the libakm_free library. Since it was quite easy for Nexus S (libakm was just a passthrough), I gave it a try on the Galaxy S2. After tracing the K3DH kernel driver, I figured that the values returned by libakm were just the result of linear functions applied to the data returned by the kernel. I renamed libakm_free to Samsung-Sensors and added support for the K3DH there.

The cameras (M5MO/S5K5BAFX)

Galaxy S2 Camera

Galaxy S2 support was then already pretty decent, and I was kind of proud of myself. Though, it take a look at the Galaxy S2 characteristics, you'll see that one of its key features is the 8MP camera it embeds. And sadly, there was no usable camera module around. Though, it appeared to have a V4L2 driver, which is pretty standard and easy to implement. However, I feared that I'd have to face the same situation as audio: standard interface but only usable with a non-trivial interface aside. Once again, I traced the kernel driver and started implementing, step by step. After a couple weeks of work (I wrote the implementation from scratch and obviously couldn't spend time on it everyday), it appeared that the original non-free camera module was doing a lot of unnecessary output/overlay operations. So I decided to cut out the crap and get to the essential, that is only using the capture V4L2 interface. This comes with some issues such as the inability to resize/crop the output buffer, but I think I found acceptable workarounds for that. In the end, my camera module turned out to work quite well and is now fully-featured (except EXIF that is currently broken, but it's such a pain in the ass that I don't really want to get into it and fix things). I pushed the code on the Galaxy S2 device tree as well as on my personal Exynos Camera git repo.

The future?

Now the Galaxy S2 is supported as well as the Nexus S in Replicant and the missing (and doable) parts left are mainly GPS and compass. The compass is an AKM8975 chip. Some code was released by AKM for this chipset and even though my first attempts to make it work failed, I guess there is a way to have it working properly. I didn't renew my attempts since this is quite a detail and there is probably more important things to work on at the moment. That's for instance the GPS: it's a GSD4t chip, the very same as the Galaxy Nexus. It needs a firmware upload and uses a SiRF-derived protocol that does not seem to be documented anywhere. I hope we'll be able to figure it out somehow: it would be very nice to have GPS support on these two devices!