If you're not interested in the details, you can skip ahead to the installation instructions, but it might be worhth giving this section a skim so you can see what's going on and fix things if they break later.
This section refers to the modifications performed by the automatic configuration script in this repo. For details on unlocking the write protect setting and installing linux in the first place, see the installation instructions.
The kernel is compiled from Google's ChromiumOS fork of the linux kernel, which enables support for the display backlight controls and the audio hardware.
This approach was heavily inspired by @megabytefisher's brilliant hack, the key insight of which is to compile the chromium fork of the linux kernel with a configuration that's as close to the one used by the stock Pixelbook as possible. Many thanks to @megabytefisher, and I hope that my work will be useful to them as well.
The configuration is copied from @megabytefisher's
, with some very small modifications since I'm using a slightly newer
version of the kernel (4.4.178
vs 4.4.164
).
The chromium fork of the kernel does not support swapping to disk by design, to prevent wearing out the flash chips that are commonly used for storage on ChromeOS devices.
It is possible to enable swapping to a portion of ram that's been setup to compress its contents using a kernel feature called zram.
The automatic install will add a /usr/local/sbin/setup-zram-swap.sh
script and a zram-swap
systemd service
that runs the setup script at boot. By default the script will enable zram-based swap of about 1.5x the size
of physical RAM. I have no idea if this is a good value or not; the script is a minimally altered version of
the chromiumos swap setup script.
The size of the zram swap allocation can be controlled by writing an integer value to /root/.zram-swap
.
Check the setup script source for valid values.
Hibernation is a power state where the contents of ram are written out to disk, to prevent loss of data in the case of complete power loss. Because this feature relies on a disk-based swap partition or file, it's not possible to enable while running the chromium-flavored kernel.
In practice, the suspend state should last for several days before draining the battery completely, which is good enough for me.
Again, this is inspired by @megabytefisher
. To enable the audio hardware, we need some firmware files that can be
extracted from a Pixelbook recovery image. The automated configuration script will pull all the firmware files from
the recovery image and install them to the correct place, and also pull some configuration needed for full audio
support using cras
.
Once we're running the chromium-flavored kernel with the firware files in place, we can access the raw audio hardware,
and aplay -l
should show some output devices. However, the Pixelbook uses an audio chip that's not well supported by
the linux audio "userland" components (ALSA and pulseaudio). As a result, both ALSA and pulseaudio can only playback
through the internal speakers, and there's no way to switch to the headphones. Recording is also unsupported out of
the box, as none of the capture devices are recognized.
This was a deal-breaker for me, since my hope for this machine was to use it for work, where I often need to participate in video calls.
Before getting into the solution, let me give a quick overview of how audio on linux works, filtered through my super limited understanding.
At the bottom is the hardware driver, which takes the form of a kernel module, which in our case also requires some special firmware files. Once those are in place, the audio hardware is avalable outside of the kernel. However, the "interface" for using the hardware is extremely low-level and not directly usable by most linux programs and end users.
The layer just above the kernel is ALSA, the Advanced Linux Sound Architecture. This provides a common interface to the many, many kinds of audio drivers exposed by the kernel. It lets you do things like adjust the volume and other parameters exposed by the driver, and provides a high-level API that applications can use to play and record audio.
Above ALSA is pulseaudio, which serves as an "audio server", allowing many "client" applications to all share the same audio hardware, something which is quite difficult with ALSA alone. PulseAudio is used by Gnome and other desktop environments; when you move the volume slider in the Gnome UI, it tells the PulseAudio server to adjust the volume on the current output device. PulseAudio uses ALSA for the acutal playback and recording, although I think it also supports other backends.
The problem with audio on the Pixelbook is that neither ALSA nor PulseAudio are configured to use the specific controls and devices provided by the kernel audio driver. ALSA tries to map the driver interfaces to known configurations, but since there's no special mapping for the Pixelbook chip, it falls back on the default "Analog Stereo" profile, which only supports the internal speakers.
Everything works great on ChromeOS, of course, because Google has put in the engineering work to get everything playing nice with
the hardware. However, while ChromeOS uses ALSA, it doesn't use it directly, and it also doesn't use PulseAudio. Instead, Google
wrote their own audio server, cras
,
the Chromium OS Audio Server. This serves the same purpose as PulseAudio but consumes fewer resources.
I spent a little while trying to figure out how to get ALSA and PulseAudio to play nice with the Pixelbook audio driver, but I didn't manage to make any headway.
The breakthrough came when I saw that crouton supports audio by actually compiling cras
inside the
chroot
environment and letting cras
talk to ALSA and manage the hardware. I had already discovered that the eve recovery image contained
configuration files for cras
that are specific to the pixelbook hardware, so I figured that the best shot of getting everything to work
would be to get cras
in the mix.
I decided to try compiling cras
and running it inside the standard linux environment to see if it could make sense of the weird
hardware interface provided by the driver and exposed by ALSA. Some hours later, it works!
After compiling cras
and running it (with the config files in the right place), the cras_test_client
included with cras
can
switch between speakers & headphones (and also HDMI 1 and HDMI 2, but I haven't tried using those yet). It can also switch between
a headset mic and the internal mic, and exposes "loopback" capture devices to record whatever is playing through the output device.
You can also use cras_test_client
to test audio playback and recording - to see if things are working try
cras_test_client --playback_file /usr/share/sounds/alsa/Front_Left.wav
.
Included with cras
are some ALSA plugins that create a new virtual ALSA device named cras
- if those are in the right place
(/usr/lib/x86_64-linux-gnu/alsa-lib/
on Ubuntu), apps that support ALSA can target that device and the audio will be routed
to cras
, which will then send it back to ALSA, this time targeting the actual hardware devices.
The final piece of the puzzle is PulseAudio, which will let us use the standard Gnome volume controls and basically let the rest of the system pretend that we're using a standard audio setup.
Once again, crouton shows the way - the crouton pulseaudio config
routes audio through the special cras
ALSA device, which then sends audio to cras
, which sends it back to ALSA, which
finally sends it to the kernel, where it hits the hardware at last.
Here's a picture of this Rube Goldberg contraption:
cras uses ALSA's real audio
devices for the hardware +---------------+
exposed by the driver | |
| cras |
+---------------------+ |
| | |
v +-------|-------+
+--------------+ +--------|------+ ^ Audio sent to the "cras" ALSA
| | | | | device gets routed to cras,
| Audio +<-----+ ALSA +----------------------+ which sends it back to the
| Driver | | | the real hardware ALSA device
| | | | +---------------+
+--------------+ +-------|-------+ | |
^ | pulseaudio |
+----------------------+ |
| |
pulse uses the +---------------+
virtual "cras" ALSA device
I was feeling pretty smug when I got audio working through the headphones, but the process of switching devices wasn't very
pleasant. Because pulseaudio only sees a single audio device (the virtual cras
ALSA device), you can't use the built-in
output switching provided by Gnome, etc. What you can do is use the cras_test_client
included with cras
to tell cras
what output and input you want to use.
The basic process works like this:
- run
cras_test_client
with no arguments to get a status report, including the names and IDs of all the input and output devices - find the ID of the output device you want to target (will be two numbers separated by
:
, e.g.7:0
) - run
cras_test_client --select_output $id_from_step_2
This seemed like a job for a hacky script, so I wrote one up. The eve-audio-ctl.py
script that gets installed when you run the
automated setup script wraps cras_test_client
and parses the device IDs, so you can just do e.g. eve-audio-ctl.py -o headphone
.
Running eve-audio-ctl.py
with no arguments will show a list of available audio devices and indicate which is active.
The final piece of the puzzle is automatically switching inputs when headphones are plugged or unplugged. For this, I used the
acpi_listen
command, which writes messages to stdout when headphones and microphones are plugged in or removed. If you run
eve-audio-ctl.py -j
, the script will listen for events and switch to headphones when they're plugged in and speakers when
the headphones are unplugged. It will also switch the input to the headset mic if one is plugged, and switch back to the
internal mic if removed.
The automatic install also creates a systemd service called eve-headphone-jack-listener
, which runs the script automatically
in the background, so everything should "just work" as expected without having to explicitly run the script.
When running the chromium-flavored kernel, the keyboard backlight can be controlled by writing an integer value between 0 and 100
to /sys/class/leds/chromeos::kbd_backlight/brightness
, e.g. echo 100 > '/sys/class/leds/chromeos::kbd_backlight/brightness'
.
By default only root
has permission to do this, so the automatic install script installs a udev rules file to grant permission
to an leds
group, and also makes sure the group exists and the main user account is a member.
There's also a eve-keyboard-brightness.sh
script installd in /usr/local/bin
that you can use to more easily set the brightness:
- Set brightness to absolute level between 0 and 100:
eve-keyboard-brightness.sh 100
. - Adjust brightness by relative amount:
eve-keyboard-brightness.sh +10
- handy for assigning to a keyboard shortcut
By default, the pixelbook touchpad feels off in non-ChromeOS linux, requiring too much pressure to move the cursor. This can be fixed by
fiddling with libinput debug tools
and creating a /etc/libinput/local-overrides.quirks
file.
An earlier version of this repo included a quirks file to set the sensitivity, but I realized I could do one better by once again building some ChromeOS platform code for vanilla linux.
ChromeOS has its own X11 input driver called cmt
(for Chromium Multi Touch), which is why the touchpad feels so
much nicer on ChromeOS than most flavors of linux.
I found a fork of the xf86-input-cmt
driver by @hugegreenbug,
which convinced me to try compiling it. Because @hugegreenbug's repo hasn't been updated in a few years, I decided
to make my own patches based on his changes and apply them during the automatic configuration process.
Running the automatic config script will build the input driver and its dependencies and install everything into the right place. On reboot, you should have nice touchpad sensitivity, and you'll be able to scroll much more smoothly.
The Pixelbook keyboard has three non-standard keys, the search key that takes the place of Caps Lock, the "hamburger" key in the upper right, and the Google Assistant key betweeen left control and left alt. The hamburger key is automatically recognized as F13, and search gets mapped to Left Super, but the assistant key is ignored.
The automatic install adds a /lib/udev/hwdb.d/61-eve-keyboard.hwdb
file that remaps the assistant key to Right Super.
If you'd prefer a different key, or to map the search key to something else,
see Running the install script for details on how to customize.