It helps to separate kernel incompatibilities from rootfs incompatibilities.
Kernel incompatibilities include:
- OSS (legacy) vs ALSA (OD)
- Direct hardware access through /dev/mem (possible on legacy, blocked on OD)
- Ingenic specific kernel interfaces in /proc/jz (available on legacy, replaced by standard interfaces on OD)
Rootfs incompatibilities include:
- Incompatible library versions (different SONAME) for some libraries
- Hardware vs software floating point ABI (OD on the GCW Zero uses hardware float; both legacy and OD on the A320 use software float since the JZ4740 doesn't have an FPU)
Working around rootfs incompatibilities is easy: you can just mount the rootfs of the system you're trying to mimic and then use chroot to make it appear as the main rootfs to an application. Well, you'd have to bind-mount /dev and /tmp and add second mounts of /sys and /proc in the compatibility rootfs, so it's a bit more involved than that, but it's not beyond what a shell script of a dozen or so lines could do.
Working around kernel incompatibilities is hard:
- We tried the OSS emulation that exists for ALSA, but performance was poor and on A320 we lost software volume control, so it was always playing at maximum volume. In the end, we decided it was not worth enabling it in a release.
- Having applications access hardware registers directly that are also accessed by the kernel is waiting for an accident to happen. It would also break suspend, since the driver would not be able to restore the hardware to the right state when resuming. We think applications poking into hardware registers is a very bad idea and we also don't want the support nightmare of having this feature enabled, so it is removed in OD. You'd either have to write some kind of simulator for /dev/mem or accept that some apps won't run.
- Regarding /proc/jz, most of the things that happen there are not very critical (such as changing screen brightness), so you could probably put a ramdisk (tmpfs) there to make it appear to the application that writes succeeded but let nothing happen.
I don't think there are all that many applications using /dev/mem fortunately. But reliable and well-performing OSS emulation would be crucial to make a compatibility layer like this usable.
I doubt though whether a compatibility layer is the right approach in making more applications available. Most software for the Dingoo and Zero is open source, so let's take advantage of that by modernizing and standardizing the applications. OpenDingux uses standard interfaces as much as possible, so if you make an application run on OpenDingux it will also be much easier to run it on other Linux systems. It's an investment in keeping the application usable on current and future devices, while a compatibility layer is far less future proof.
Also porting applications is a great way for beginning developers to learn, while creating the kernel parts of a compatibility layer requires an expert developer. So the porting approach will also help towards decreasing the developer shortage, while the compatibility layer approach would just use up development time that could be used better in my opinion (we still need SDL2 support on the Zero, for example).
What would help a lot is if porters would adopt a workflow where they publish their changes as commits instead of as ZIP files / tarballs. What I mean is something like this:
- commit 1: Import upstream application release.
- commit 2: Add/change Makefile for compiling for OpenDingux.
- commit 3: Work around function missing in uClibc.
- commit 4: Add button mapping for OpenDingux.
- commit 5: Render using double buffering.
- commit 6: Save in home dir instead of installation dir.
- commit 7: Add Makefile rule to package as OPK.
And publish those commits on GitHub (or BitBucket or SourceForge etc). Although I didn't finish it, I did start on this process for Mr Drillux
. Please look through the commits list there and compare that to getting a ZIP file with sources.
This approach solves a number of issues:
- Future porters have an easier time finding the latest version of the source: there is a single repository that contains everything, instead of having to dig through old forum posts and hope that the source download link still works.
- It is much easier for another developer who wants to make improvements to see what the first porter did.
- It is much easier for another porter to port to a new device: they can cherry-pick the commits that are appropriate to the new device and for commits that don't match the new device they can still see what part of the code needs modification, saving them a lot of time digging through the code.
- If the upstream (parent project) is still active, you can import newer releases and easily re-apply the customizations on top of that.
- If the upstream is still active, they might include some of your customizations into the parent project, making it easier to port in the future.
To summarize: making a compatibility layer is not easy and in my opinion the effort is better spent in cleaning up and modernizing application source code, since that will have more long term benefits.